From b92b55ab8e11614a587929bc66c023b9fe7cf7f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl=20=C3=85stholm?= Date: Sun, 23 Mar 2025 18:48:05 +0100 Subject: [PATCH 01/76] Update test build.zig.zon files to conform to the new manifest rules --- test/link/build.zig.zon | 3 ++- test/standalone/build.zig.zon | 2 +- test/standalone/dependencyFromBuildZig/build.zig.zon | 3 ++- test/standalone/dependencyFromBuildZig/other/build.zig.zon | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/test/link/build.zig.zon b/test/link/build.zig.zon index 16bba08c4e..ab44726091 100644 --- a/test/link/build.zig.zon +++ b/test/link/build.zig.zon @@ -1,5 +1,6 @@ .{ - .name = "link_test_cases", + .name = .link_test_cases, + .fingerprint = 0x404f657576fec9f2, .version = "0.0.0", .dependencies = .{ .bss = .{ diff --git a/test/standalone/build.zig.zon b/test/standalone/build.zig.zon index 8cf899477f..afbe3fcfa8 100644 --- a/test/standalone/build.zig.zon +++ b/test/standalone/build.zig.zon @@ -1,6 +1,6 @@ .{ .name = .standalone_test_cases, - .fingerprint = 0xc0dbdf9c818957be, + .fingerprint = 0xc0dbdf9c3b92810b, .version = "0.0.0", .dependencies = .{ .simple = .{ diff --git a/test/standalone/dependencyFromBuildZig/build.zig.zon b/test/standalone/dependencyFromBuildZig/build.zig.zon index 085ae2c80b..fda6a098d8 100644 --- a/test/standalone/dependencyFromBuildZig/build.zig.zon +++ b/test/standalone/dependencyFromBuildZig/build.zig.zon @@ -1,5 +1,6 @@ .{ - .name = "dependencyFromBuildZig", + .name = .dependencyFromBuildZig, + .fingerprint = 0xfd939a1eb8169080, .version = "0.0.0", .dependencies = .{ .other = .{ diff --git a/test/standalone/dependencyFromBuildZig/other/build.zig.zon b/test/standalone/dependencyFromBuildZig/other/build.zig.zon index 204abdbbba..bb8fcb6fb4 100644 --- a/test/standalone/dependencyFromBuildZig/other/build.zig.zon +++ b/test/standalone/dependencyFromBuildZig/other/build.zig.zon @@ -1,5 +1,6 @@ .{ - .name = "other", + .name = .other, + .fingerprint = 0xd9583520a2405f6c, .version = "0.0.0", .dependencies = .{}, .paths = .{""}, From 00bc72b5ff01c7f8ceb4b58e82614e22a147ccc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl=20=C3=85stholm?= Date: Sun, 23 Mar 2025 20:38:41 +0100 Subject: [PATCH 02/76] Add standalone test case for passing options to dependencies --- test/standalone/build.zig.zon | 3 + test/standalone/dependency_options/build.zig | 63 +++++++++++++++++++ .../dependency_options/build.zig.zon | 11 ++++ .../dependency_options/other/build.zig | 56 +++++++++++++++++ .../dependency_options/other/build.zig.zon | 7 +++ 5 files changed, 140 insertions(+) create mode 100644 test/standalone/dependency_options/build.zig create mode 100644 test/standalone/dependency_options/build.zig.zon create mode 100644 test/standalone/dependency_options/other/build.zig create mode 100644 test/standalone/dependency_options/other/build.zig.zon diff --git a/test/standalone/build.zig.zon b/test/standalone/build.zig.zon index afbe3fcfa8..bdd059ab37 100644 --- a/test/standalone/build.zig.zon +++ b/test/standalone/build.zig.zon @@ -181,6 +181,9 @@ .install_headers = .{ .path = "install_headers", }, + .dependency_options = .{ + .path = "dependency_options", + }, .dependencyFromBuildZig = .{ .path = "dependencyFromBuildZig", }, diff --git a/test/standalone/dependency_options/build.zig b/test/standalone/dependency_options/build.zig new file mode 100644 index 0000000000..8726f61d30 --- /dev/null +++ b/test/standalone/dependency_options/build.zig @@ -0,0 +1,63 @@ +const std = @import("std"); + +pub const Enum = enum { alfa, bravo, charlie }; + +pub fn build(b: *std.Build) !void { + const test_step = b.step("test", "Test passing options to a dependency"); + b.default_step = test_step; + + const none_specified = b.dependency("other", .{}); + + const none_specified_mod = none_specified.module("dummy"); + if (!none_specified_mod.resolved_target.?.query.eql(b.graph.host.query)) return error.TestFailed; + if (none_specified_mod.optimize.? != .Debug) return error.TestFailed; + + const all_specified = b.dependency("other", .{ + .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }), + .optimize = @as(std.builtin.OptimizeMode, .ReleaseSafe), + .bool = @as(bool, true), + .int = @as(i64, 123), + .float = @as(f64, 0.5), + .string = @as([]const u8, "abc"), + .string_list = @as([]const []const u8, &.{ "a", "b", "c" }), + .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }), + .lazy_path_list = @as([]const std.Build.LazyPath, &.{ + .{ .cwd_relative = "a.txt" }, + .{ .cwd_relative = "b.txt" }, + .{ .cwd_relative = "c.txt" }, + }), + .@"enum" = @as(Enum, .alfa), + //.enum_list = @as([]const Enum, &.{ .alfa, .bravo, .charlie }), + //.build_id = @as(std.zig.BuildId, .uuid), + }); + + const all_specified_mod = all_specified.module("dummy"); + if (all_specified_mod.resolved_target.?.result.cpu.arch != .x86_64) return error.TestFailed; + if (all_specified_mod.resolved_target.?.result.os.tag != .windows) return error.TestFailed; + if (all_specified_mod.resolved_target.?.result.abi != .gnu) return error.TestFailed; + if (all_specified_mod.optimize.? != .ReleaseSafe) return error.TestFailed; + + // Most supported option types are serialized to a string representation, + // so alternative representations of the same option value should resolve + // to the same cached dependency instance. + const all_specified_alt = b.dependency("other", .{ + .target = @as(std.Target.Query, .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }), + .optimize = @as([]const u8, "ReleaseSafe"), + .bool = .true, + .int = @as([]const u8, "123"), + .float = @as(f16, 0.5), + .string = .abc, + .string_list = @as([]const []const u8, &.{ "a", "b", "c" }), + .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }), + .lazy_path_list = @as([]const std.Build.LazyPath, &.{ + .{ .cwd_relative = "a.txt" }, + .{ .cwd_relative = "b.txt" }, + .{ .cwd_relative = "c.txt" }, + }), + .@"enum" = @as([]const u8, "alfa"), + //.enum_list = @as([]const Enum, &.{ .alfa, .bravo, .charlie }), + //.build_id = @as(std.zig.BuildId, .uuid), + }); + + if (all_specified != all_specified_alt) return error.TestFailed; +} diff --git a/test/standalone/dependency_options/build.zig.zon b/test/standalone/dependency_options/build.zig.zon new file mode 100644 index 0000000000..6788640a80 --- /dev/null +++ b/test/standalone/dependency_options/build.zig.zon @@ -0,0 +1,11 @@ +.{ + .name = .dependency_options, + .fingerprint = 0x3e3ce1c1f92ba47e, + .version = "0.0.0", + .dependencies = .{ + .other = .{ + .path = "other", + }, + }, + .paths = .{""}, +} diff --git a/test/standalone/dependency_options/other/build.zig b/test/standalone/dependency_options/other/build.zig new file mode 100644 index 0000000000..fe676a5b25 --- /dev/null +++ b/test/standalone/dependency_options/other/build.zig @@ -0,0 +1,56 @@ +const std = @import("std"); + +pub const Enum = enum { alfa, bravo, charlie }; + +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const expected_bool: bool = true; + const expected_int: i64 = 123; + const expected_float: f64 = 0.5; + const expected_string: []const u8 = "abc"; + const expected_string_list: []const []const u8 = &.{ "a", "b", "c" }; + const expected_lazy_path: std.Build.LazyPath = .{ .cwd_relative = "abc.txt" }; + const expected_lazy_path_list: []const std.Build.LazyPath = &.{ + .{ .cwd_relative = "a.txt" }, + .{ .cwd_relative = "b.txt" }, + .{ .cwd_relative = "c.txt" }, + }; + const expected_enum: Enum = .alfa; + const expected_enum_list: []const Enum = &.{ .alfa, .bravo, .charlie }; + const expected_build_id: std.zig.BuildId = .uuid; + + const @"bool" = b.option(bool, "bool", "bool") orelse expected_bool; + const int = b.option(i64, "int", "int") orelse expected_int; + const float = b.option(f64, "float", "float") orelse expected_float; + const string = b.option([]const u8, "string", "string") orelse expected_string; + const string_list = b.option([]const []const u8, "string_list", "string_list") orelse expected_string_list; + const lazy_path = b.option(std.Build.LazyPath, "lazy_path", "lazy_path") orelse expected_lazy_path; + const lazy_path_list = b.option([]const std.Build.LazyPath, "lazy_path_list", "lazy_path_list") orelse expected_lazy_path_list; + const @"enum" = b.option(Enum, "enum", "enum") orelse expected_enum; + const enum_list = b.option([]const Enum, "enum_list", "enum_list") orelse expected_enum_list; + const build_id = b.option(std.zig.BuildId, "build_id", "build_id") orelse expected_build_id; + + if (@"bool" != expected_bool) return error.TestFailed; + if (int != expected_int) return error.TestFailed; + if (float != expected_float) return error.TestFailed; + if (!std.mem.eql(u8, string, expected_string)) return error.TestFailed; + if (string_list.len != expected_string_list.len) return error.TestFailed; + for (string_list, expected_string_list) |x, y| { + if (!std.mem.eql(u8, x, y)) return error.TestFailed; + } + if (!std.mem.eql(u8, lazy_path.cwd_relative, expected_lazy_path.cwd_relative)) return error.TestFailed; + for (lazy_path_list, expected_lazy_path_list) |x, y| { + if (!std.mem.eql(u8, x.cwd_relative, y.cwd_relative)) return error.TestFailed; + } + if (@"enum" != expected_enum) return error.TestFailed; + if (!std.mem.eql(Enum, enum_list, expected_enum_list)) return error.TestFailed; + if (!std.meta.eql(build_id, expected_build_id)) return error.TestFailed; + + _ = b.addModule("dummy", .{ + .root_source_file = b.path("build.zig"), + .target = target, + .optimize = optimize, + }); +} diff --git a/test/standalone/dependency_options/other/build.zig.zon b/test/standalone/dependency_options/other/build.zig.zon new file mode 100644 index 0000000000..d49a2cdcf8 --- /dev/null +++ b/test/standalone/dependency_options/other/build.zig.zon @@ -0,0 +1,7 @@ +.{ + .name = .other, + .fingerprint = 0xd95835207bc8b630, + .version = "0.0.0", + .dependencies = .{}, + .paths = .{""}, +} From 5380e81924dd98e9717eaf09ae05e935952a78ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl=20=C3=85stholm?= Date: Sun, 23 Mar 2025 22:45:38 +0100 Subject: [PATCH 03/76] Support passing null to `b.dependency()` Both null literals and optionals are supported. --- lib/std/Build.zig | 213 ++++++++++--------- test/standalone/dependency_options/build.zig | 46 +++- 2 files changed, 163 insertions(+), 96 deletions(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index e65a71e12b..e5b9e072f7 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -408,104 +408,127 @@ fn createChildOnly( return child; } -fn userInputOptionsFromArgs(allocator: Allocator, args: anytype) UserInputOptionsMap { - var user_input_options = UserInputOptionsMap.init(allocator); +fn userInputOptionsFromArgs(arena: Allocator, args: anytype) UserInputOptionsMap { + var map = UserInputOptionsMap.init(arena); inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| { - const v = @field(args, field.name); - const T = @TypeOf(v); - switch (T) { - Target.Query => { - user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .scalar = v.zigTriple(allocator) catch @panic("OOM") }, - .used = false, - }) catch @panic("OOM"); - user_input_options.put("cpu", .{ - .name = "cpu", - .value = .{ .scalar = v.serializeCpuAlloc(allocator) catch @panic("OOM") }, - .used = false, - }) catch @panic("OOM"); - }, - ResolvedTarget => { - user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .scalar = v.query.zigTriple(allocator) catch @panic("OOM") }, - .used = false, - }) catch @panic("OOM"); - user_input_options.put("cpu", .{ - .name = "cpu", - .value = .{ .scalar = v.query.serializeCpuAlloc(allocator) catch @panic("OOM") }, - .used = false, - }) catch @panic("OOM"); - }, - LazyPath => { - user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .lazy_path = v.dupeInner(allocator) }, - .used = false, - }) catch @panic("OOM"); - }, - []const LazyPath => { - var list = ArrayList(LazyPath).initCapacity(allocator, v.len) catch @panic("OOM"); - for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(allocator)); - user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .lazy_path_list = list }, - .used = false, - }) catch @panic("OOM"); - }, - []const u8 => { - user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .scalar = v }, - .used = false, - }) catch @panic("OOM"); - }, - []const []const u8 => { - var list = ArrayList([]const u8).initCapacity(allocator, v.len) catch @panic("OOM"); - list.appendSliceAssumeCapacity(v); - - user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .list = list }, - .used = false, - }) catch @panic("OOM"); - }, - else => switch (@typeInfo(T)) { - .bool => { - user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .scalar = if (v) "true" else "false" }, - .used = false, - }) catch @panic("OOM"); - }, - .@"enum", .enum_literal => { - user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .scalar = @tagName(v) }, - .used = false, - }) catch @panic("OOM"); - }, - .comptime_int, .int => { - user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .scalar = std.fmt.allocPrint(allocator, "{d}", .{v}) catch @panic("OOM") }, - .used = false, - }) catch @panic("OOM"); - }, - .comptime_float, .float => { - user_input_options.put(field.name, .{ - .name = field.name, - .value = .{ .scalar = std.fmt.allocPrint(allocator, "{e}", .{v}) catch @panic("OOM") }, - .used = false, - }) catch @panic("OOM"); - }, - else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)), - }, - } + if (field.type == @Type(.null)) continue; + addUserInputOptionFromArg(arena, &map, field, field.type, @field(args, field.name)); } + return map; +} - return user_input_options; +fn addUserInputOptionFromArg( + arena: Allocator, + map: *UserInputOptionsMap, + field: std.builtin.Type.StructField, + comptime T: type, + /// If null, the value won't be added, but `T` will still be type-checked. + maybe_value: ?T, +) void { + switch (T) { + Target.Query => return if (maybe_value) |v| { + map.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = v.zigTriple(arena) catch @panic("OOM") }, + .used = false, + }) catch @panic("OOM"); + map.put("cpu", .{ + .name = "cpu", + .value = .{ .scalar = v.serializeCpuAlloc(arena) catch @panic("OOM") }, + .used = false, + }) catch @panic("OOM"); + }, + ResolvedTarget => return if (maybe_value) |v| { + map.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = v.query.zigTriple(arena) catch @panic("OOM") }, + .used = false, + }) catch @panic("OOM"); + map.put("cpu", .{ + .name = "cpu", + .value = .{ .scalar = v.query.serializeCpuAlloc(arena) catch @panic("OOM") }, + .used = false, + }) catch @panic("OOM"); + }, + LazyPath => return if (maybe_value) |v| { + map.put(field.name, .{ + .name = field.name, + .value = .{ .lazy_path = v.dupeInner(arena) }, + .used = false, + }) catch @panic("OOM"); + }, + []const LazyPath => return if (maybe_value) |v| { + var list = ArrayList(LazyPath).initCapacity(arena, v.len) catch @panic("OOM"); + for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(arena)); + map.put(field.name, .{ + .name = field.name, + .value = .{ .lazy_path_list = list }, + .used = false, + }) catch @panic("OOM"); + }, + []const u8 => return if (maybe_value) |v| { + map.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = v }, + .used = false, + }) catch @panic("OOM"); + }, + []const []const u8 => return if (maybe_value) |v| { + var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM"); + list.appendSliceAssumeCapacity(v); + map.put(field.name, .{ + .name = field.name, + .value = .{ .list = list }, + .used = false, + }) catch @panic("OOM"); + }, + else => switch (@typeInfo(T)) { + .bool => return if (maybe_value) |v| { + map.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = if (v) "true" else "false" }, + .used = false, + }) catch @panic("OOM"); + }, + .@"enum", .enum_literal => return if (maybe_value) |v| { + map.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = @tagName(v) }, + .used = false, + }) catch @panic("OOM"); + }, + .comptime_int, .int => return if (maybe_value) |v| { + map.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = std.fmt.allocPrint(arena, "{d}", .{v}) catch @panic("OOM") }, + .used = false, + }) catch @panic("OOM"); + }, + .comptime_float, .float => return if (maybe_value) |v| { + map.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = std.fmt.allocPrint(arena, "{e}", .{v}) catch @panic("OOM") }, + .used = false, + }) catch @panic("OOM"); + }, + .null => unreachable, + .optional => |info| switch (@typeInfo(info.child)) { + .optional => {}, + else => { + addUserInputOptionFromArg( + arena, + map, + field, + info.child, + maybe_value orelse null, + ); + return; + }, + }, + else => {}, + }, + } + @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(field.type)); } const OrderedUserValue = union(enum) { diff --git a/test/standalone/dependency_options/build.zig b/test/standalone/dependency_options/build.zig index 8726f61d30..27ce63834d 100644 --- a/test/standalone/dependency_options/build.zig +++ b/test/standalone/dependency_options/build.zig @@ -12,6 +12,29 @@ pub fn build(b: *std.Build) !void { if (!none_specified_mod.resolved_target.?.query.eql(b.graph.host.query)) return error.TestFailed; if (none_specified_mod.optimize.? != .Debug) return error.TestFailed; + // Passing null is the same as not specifying the option, + // so this should resolve to the same cached dependency instance. + const null_specified = b.dependency("other", .{ + // Null literals + .target = null, + .optimize = null, + .bool = null, + + // Optionals + .int = @as(?i64, null), + .float = @as(?f64, null), + + // Optionals of the wrong type + .string = @as(?usize, null), + .@"enum" = @as(?bool, null), + + // Non-defined option names + .this_option_does_not_exist = null, + .neither_does_this_one = @as(?[]const u8, null), + }); + + if (null_specified != none_specified) return error.TestFailed; + const all_specified = b.dependency("other", .{ .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }), .optimize = @as(std.builtin.OptimizeMode, .ReleaseSafe), @@ -37,6 +60,27 @@ pub fn build(b: *std.Build) !void { if (all_specified_mod.resolved_target.?.result.abi != .gnu) return error.TestFailed; if (all_specified_mod.optimize.? != .ReleaseSafe) return error.TestFailed; + const all_specified_optional = b.dependency("other", .{ + .target = @as(?std.Build.ResolvedTarget, b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu })), + .optimize = @as(?std.builtin.OptimizeMode, .ReleaseSafe), + .bool = @as(?bool, true), + .int = @as(?i64, 123), + .float = @as(?f64, 0.5), + .string = @as(?[]const u8, "abc"), + .string_list = @as(?[]const []const u8, &.{ "a", "b", "c" }), + .lazy_path = @as(?std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }), + .lazy_path_list = @as(?[]const std.Build.LazyPath, &.{ + .{ .cwd_relative = "a.txt" }, + .{ .cwd_relative = "b.txt" }, + .{ .cwd_relative = "c.txt" }, + }), + .@"enum" = @as(?Enum, .alfa), + //.enum_list = @as(?[]const Enum, &.{ .alfa, .bravo, .charlie }), + //.build_id = @as(?std.zig.BuildId, .uuid), + }); + + if (all_specified_optional != all_specified) return error.TestFailed; + // Most supported option types are serialized to a string representation, // so alternative representations of the same option value should resolve // to the same cached dependency instance. @@ -59,5 +103,5 @@ pub fn build(b: *std.Build) !void { //.build_id = @as(std.zig.BuildId, .uuid), }); - if (all_specified != all_specified_alt) return error.TestFailed; + if (all_specified_alt != all_specified) return error.TestFailed; } From e7604bba3ef0654a882edb17d712d1beb2cefec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl=20=C3=85stholm?= Date: Mon, 24 Mar 2025 13:22:08 +0100 Subject: [PATCH 04/76] Serialize float options using the hexadecimal format This ensures no information is lost when the value is round-tripped. --- lib/std/Build.zig | 2 +- lib/std/Io/Writer.zig | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index e5b9e072f7..1c73767009 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -507,7 +507,7 @@ fn addUserInputOptionFromArg( .comptime_float, .float => return if (maybe_value) |v| { map.put(field.name, .{ .name = field.name, - .value = .{ .scalar = std.fmt.allocPrint(arena, "{e}", .{v}) catch @panic("OOM") }, + .value = .{ .scalar = std.fmt.allocPrint(arena, "{x}", .{v}) catch @panic("OOM") }, .used = false, }) catch @panic("OOM"); }, diff --git a/lib/std/Io/Writer.zig b/lib/std/Io/Writer.zig index 09a1c8f81b..1a717f0bca 100644 --- a/lib/std/Io/Writer.zig +++ b/lib/std/Io/Writer.zig @@ -1563,17 +1563,23 @@ pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number) } pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void { - if (std.math.signbit(value)) try w.writeByte('-'); - if (std.math.isNan(value)) return w.writeAll(switch (case) { + const v = switch (@TypeOf(value)) { + // comptime_float internally is a f128; this preserves precision. + comptime_float => @as(f128, value), + else => value, + }; + + if (std.math.signbit(v)) try w.writeByte('-'); + if (std.math.isNan(v)) return w.writeAll(switch (case) { .lower => "nan", .upper => "NAN", }); - if (std.math.isInf(value)) return w.writeAll(switch (case) { + if (std.math.isInf(v)) return w.writeAll(switch (case) { .lower => "inf", .upper => "INF", }); - const T = @TypeOf(value); + const T = @TypeOf(v); const TU = std.meta.Int(.unsigned, @bitSizeOf(T)); const mantissa_bits = std.math.floatMantissaBits(T); @@ -1583,7 +1589,7 @@ pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precisi const exponent_mask = (1 << exponent_bits) - 1; const exponent_bias = (1 << (exponent_bits - 1)) - 1; - const as_bits: TU = @bitCast(value); + const as_bits: TU = @bitCast(v); var mantissa = as_bits & mantissa_mask; var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask)); From 1a9fae2a70371fdbd77446fd5173162bfa065624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl=20=C3=85stholm?= Date: Mon, 24 Mar 2025 13:25:56 +0100 Subject: [PATCH 05/76] Dupe string options --- lib/std/Build.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 1c73767009..21eb5196ed 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -469,13 +469,13 @@ fn addUserInputOptionFromArg( []const u8 => return if (maybe_value) |v| { map.put(field.name, .{ .name = field.name, - .value = .{ .scalar = v }, + .value = .{ .scalar = arena.dupe(u8, v) catch @panic("OOM") }, .used = false, }) catch @panic("OOM"); }, []const []const u8 => return if (maybe_value) |v| { var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM"); - list.appendSliceAssumeCapacity(v); + for (v) |s| list.appendAssumeCapacity(arena.dupe(u8, s) catch @panic("OOM")); map.put(field.name, .{ .name = field.name, .value = .{ .list = list }, From fd5eba9358ebf2f498b7c35bae34267f06d070d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl=20=C3=85stholm?= Date: Mon, 24 Mar 2025 00:01:28 +0100 Subject: [PATCH 06/76] Coerce slice-like arguments passed to `b.dependency()` You can now pass string literals as options. --- lib/std/Build.zig | 34 +++++++++++++ test/standalone/dependency_options/build.zig | 53 ++++++++++++++++---- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 21eb5196ed..efff88b469 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -511,6 +511,40 @@ fn addUserInputOptionFromArg( .used = false, }) catch @panic("OOM"); }, + .pointer => |ptr_info| switch (ptr_info.size) { + .one => switch (@typeInfo(ptr_info.child)) { + .array => |array_info| { + comptime var slice_info = ptr_info; + slice_info.size = .slice; + slice_info.is_const = true; + slice_info.child = array_info.child; + slice_info.sentinel_ptr = null; + addUserInputOptionFromArg( + arena, + map, + field, + @Type(.{ .pointer = slice_info }), + maybe_value orelse null, + ); + return; + }, + else => {}, + }, + .slice => { + comptime var slice_info = ptr_info; + slice_info.is_const = true; + slice_info.sentinel_ptr = null; + addUserInputOptionFromArg( + arena, + map, + field, + @Type(.{ .pointer = slice_info }), + maybe_value orelse null, + ); + return; + }, + else => {}, + }, .null => unreachable, .optional => |info| switch (@typeInfo(info.child)) { .optional => {}, diff --git a/test/standalone/dependency_options/build.zig b/test/standalone/dependency_options/build.zig index 27ce63834d..351a82ccdb 100644 --- a/test/standalone/dependency_options/build.zig +++ b/test/standalone/dependency_options/build.zig @@ -81,25 +81,56 @@ pub fn build(b: *std.Build) !void { if (all_specified_optional != all_specified) return error.TestFailed; + const all_specified_literal = b.dependency("other", .{ + .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }), + .optimize = .ReleaseSafe, + .bool = true, + .int = 123, + .float = 0.5, + .string = "abc", + .string_list = &[_][]const u8{ "a", "b", "c" }, + .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }), + .lazy_path_list = &[_]std.Build.LazyPath{ + .{ .cwd_relative = "a.txt" }, + .{ .cwd_relative = "b.txt" }, + .{ .cwd_relative = "c.txt" }, + }, + .@"enum" = .alfa, + //.enum_list = &[_]Enum{ .alfa, .bravo, .charlie }, + //.build_id = @as(std.zig.BuildId, .uuid), + }); + + if (all_specified_literal != all_specified) return error.TestFailed; + + var mut_string_buf = "abc".*; + const mut_string: []u8 = &mut_string_buf; + var mut_string_list_buf = [_][]const u8{ "a", "b", "c" }; + const mut_string_list: [][]const u8 = &mut_string_list_buf; + var mut_lazy_path_list_buf = [_]std.Build.LazyPath{ + .{ .cwd_relative = "a.txt" }, + .{ .cwd_relative = "b.txt" }, + .{ .cwd_relative = "c.txt" }, + }; + const mut_lazy_path_list: []std.Build.LazyPath = &mut_lazy_path_list_buf; + var mut_enum_list_buf = [_]Enum{ .alfa, .bravo, .charlie }; + const mut_enum_list: []Enum = &mut_enum_list_buf; + _ = mut_enum_list; + // Most supported option types are serialized to a string representation, // so alternative representations of the same option value should resolve // to the same cached dependency instance. const all_specified_alt = b.dependency("other", .{ .target = @as(std.Target.Query, .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }), - .optimize = @as([]const u8, "ReleaseSafe"), + .optimize = "ReleaseSafe", .bool = .true, - .int = @as([]const u8, "123"), + .int = "123", .float = @as(f16, 0.5), - .string = .abc, - .string_list = @as([]const []const u8, &.{ "a", "b", "c" }), + .string = mut_string, + .string_list = mut_string_list, .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }), - .lazy_path_list = @as([]const std.Build.LazyPath, &.{ - .{ .cwd_relative = "a.txt" }, - .{ .cwd_relative = "b.txt" }, - .{ .cwd_relative = "c.txt" }, - }), - .@"enum" = @as([]const u8, "alfa"), - //.enum_list = @as([]const Enum, &.{ .alfa, .bravo, .charlie }), + .lazy_path_list = mut_lazy_path_list, + .@"enum" = "alfa", + //.enum_list = mut_enum_list, //.build_id = @as(std.zig.BuildId, .uuid), }); From 2c1a349fb9bc9965e309257262665564cff64a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl=20=C3=85stholm?= Date: Mon, 24 Mar 2025 00:14:25 +0100 Subject: [PATCH 07/76] Support passing enum slices to `b.dependency()` --- lib/std/Build.zig | 35 +++++++++++++------- test/standalone/dependency_options/build.zig | 9 +++-- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index efff88b469..39aa0f1a4b 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -530,18 +530,29 @@ fn addUserInputOptionFromArg( }, else => {}, }, - .slice => { - comptime var slice_info = ptr_info; - slice_info.is_const = true; - slice_info.sentinel_ptr = null; - addUserInputOptionFromArg( - arena, - map, - field, - @Type(.{ .pointer = slice_info }), - maybe_value orelse null, - ); - return; + .slice => switch (@typeInfo(ptr_info.child)) { + .@"enum" => return if (maybe_value) |v| { + var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM"); + for (v) |tag| list.appendAssumeCapacity(@tagName(tag)); + map.put(field.name, .{ + .name = field.name, + .value = .{ .list = list }, + .used = false, + }) catch @panic("OOM"); + }, + else => { + comptime var slice_info = ptr_info; + slice_info.is_const = true; + slice_info.sentinel_ptr = null; + addUserInputOptionFromArg( + arena, + map, + field, + @Type(.{ .pointer = slice_info }), + maybe_value orelse null, + ); + return; + }, }, else => {}, }, diff --git a/test/standalone/dependency_options/build.zig b/test/standalone/dependency_options/build.zig index 351a82ccdb..de7b710155 100644 --- a/test/standalone/dependency_options/build.zig +++ b/test/standalone/dependency_options/build.zig @@ -50,7 +50,7 @@ pub fn build(b: *std.Build) !void { .{ .cwd_relative = "c.txt" }, }), .@"enum" = @as(Enum, .alfa), - //.enum_list = @as([]const Enum, &.{ .alfa, .bravo, .charlie }), + .enum_list = @as([]const Enum, &.{ .alfa, .bravo, .charlie }), //.build_id = @as(std.zig.BuildId, .uuid), }); @@ -75,7 +75,7 @@ pub fn build(b: *std.Build) !void { .{ .cwd_relative = "c.txt" }, }), .@"enum" = @as(?Enum, .alfa), - //.enum_list = @as(?[]const Enum, &.{ .alfa, .bravo, .charlie }), + .enum_list = @as(?[]const Enum, &.{ .alfa, .bravo, .charlie }), //.build_id = @as(?std.zig.BuildId, .uuid), }); @@ -96,7 +96,7 @@ pub fn build(b: *std.Build) !void { .{ .cwd_relative = "c.txt" }, }, .@"enum" = .alfa, - //.enum_list = &[_]Enum{ .alfa, .bravo, .charlie }, + .enum_list = &[_]Enum{ .alfa, .bravo, .charlie }, //.build_id = @as(std.zig.BuildId, .uuid), }); @@ -114,7 +114,6 @@ pub fn build(b: *std.Build) !void { const mut_lazy_path_list: []std.Build.LazyPath = &mut_lazy_path_list_buf; var mut_enum_list_buf = [_]Enum{ .alfa, .bravo, .charlie }; const mut_enum_list: []Enum = &mut_enum_list_buf; - _ = mut_enum_list; // Most supported option types are serialized to a string representation, // so alternative representations of the same option value should resolve @@ -130,7 +129,7 @@ pub fn build(b: *std.Build) !void { .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }), .lazy_path_list = mut_lazy_path_list, .@"enum" = "alfa", - //.enum_list = mut_enum_list, + .enum_list = mut_enum_list, //.build_id = @as(std.zig.BuildId, .uuid), }); From ca57115da7c4603dbcefce1dc9395617e28a86f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl=20=C3=85stholm?= Date: Mon, 24 Mar 2025 14:25:47 +0100 Subject: [PATCH 08/76] Support passing `std.zig.BuildId` to `b.dependency()` --- lib/std/Build.zig | 7 +++++++ lib/std/zig.zig | 21 +++++++++++++++++++ test/standalone/dependency_options/build.zig | 12 +++++++---- .../dependency_options/other/build.zig | 3 +++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 39aa0f1a4b..d6b0e68f5d 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -450,6 +450,13 @@ fn addUserInputOptionFromArg( .used = false, }) catch @panic("OOM"); }, + std.zig.BuildId => return if (maybe_value) |v| { + map.put(field.name, .{ + .name = field.name, + .value = .{ .scalar = std.fmt.allocPrint(arena, "{f}", .{v}) catch @panic("OOM") }, + .used = false, + }) catch @panic("OOM"); + }, LazyPath => return if (maybe_value) |v| { map.put(field.name, .{ .name = field.name, diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 486947768d..2039a4d8c0 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -321,6 +321,27 @@ pub const BuildId = union(enum) { try std.testing.expectError(error.InvalidCharacter, parse("0xfoobbb")); try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx")); } + + pub fn format(id: BuildId, writer: *std.io.Writer) std.io.Writer.Error!void { + switch (id) { + .none, .fast, .uuid, .sha1, .md5 => { + try writer.writeAll(@tagName(id)); + }, + .hexstring => |hs| { + try writer.print("0x{x}", .{hs.toSlice()}); + }, + } + } + + test format { + try std.testing.expectFmt("none", "{f}", .{@as(BuildId, .none)}); + try std.testing.expectFmt("fast", "{f}", .{@as(BuildId, .fast)}); + try std.testing.expectFmt("uuid", "{f}", .{@as(BuildId, .uuid)}); + try std.testing.expectFmt("sha1", "{f}", .{@as(BuildId, .sha1)}); + try std.testing.expectFmt("md5", "{f}", .{@as(BuildId, .md5)}); + try std.testing.expectFmt("0x", "{f}", .{BuildId.initHexString("")}); + try std.testing.expectFmt("0x1234cdef", "{f}", .{BuildId.initHexString("\x12\x34\xcd\xef")}); + } }; pub const LtoMode = enum { none, full, thin }; diff --git a/test/standalone/dependency_options/build.zig b/test/standalone/dependency_options/build.zig index de7b710155..20e2db1fa2 100644 --- a/test/standalone/dependency_options/build.zig +++ b/test/standalone/dependency_options/build.zig @@ -51,7 +51,8 @@ pub fn build(b: *std.Build) !void { }), .@"enum" = @as(Enum, .alfa), .enum_list = @as([]const Enum, &.{ .alfa, .bravo, .charlie }), - //.build_id = @as(std.zig.BuildId, .uuid), + .build_id = @as(std.zig.BuildId, .uuid), + .hex_build_id = std.zig.BuildId.initHexString("\x12\x34\xcd\xef"), }); const all_specified_mod = all_specified.module("dummy"); @@ -76,7 +77,8 @@ pub fn build(b: *std.Build) !void { }), .@"enum" = @as(?Enum, .alfa), .enum_list = @as(?[]const Enum, &.{ .alfa, .bravo, .charlie }), - //.build_id = @as(?std.zig.BuildId, .uuid), + .build_id = @as(?std.zig.BuildId, .uuid), + .hex_build_id = @as(?std.zig.BuildId, .initHexString("\x12\x34\xcd\xef")), }); if (all_specified_optional != all_specified) return error.TestFailed; @@ -97,7 +99,8 @@ pub fn build(b: *std.Build) !void { }, .@"enum" = .alfa, .enum_list = &[_]Enum{ .alfa, .bravo, .charlie }, - //.build_id = @as(std.zig.BuildId, .uuid), + .build_id = .uuid, + .hex_build_id = std.zig.BuildId.initHexString("\x12\x34\xcd\xef"), }); if (all_specified_literal != all_specified) return error.TestFailed; @@ -130,7 +133,8 @@ pub fn build(b: *std.Build) !void { .lazy_path_list = mut_lazy_path_list, .@"enum" = "alfa", .enum_list = mut_enum_list, - //.build_id = @as(std.zig.BuildId, .uuid), + .build_id = "uuid", + .hex_build_id = "0x1234cdef", }); if (all_specified_alt != all_specified) return error.TestFailed; diff --git a/test/standalone/dependency_options/other/build.zig b/test/standalone/dependency_options/other/build.zig index fe676a5b25..c18f92f14d 100644 --- a/test/standalone/dependency_options/other/build.zig +++ b/test/standalone/dependency_options/other/build.zig @@ -20,6 +20,7 @@ pub fn build(b: *std.Build) !void { const expected_enum: Enum = .alfa; const expected_enum_list: []const Enum = &.{ .alfa, .bravo, .charlie }; const expected_build_id: std.zig.BuildId = .uuid; + const expected_hex_build_id: std.zig.BuildId = .initHexString("\x12\x34\xcd\xef"); const @"bool" = b.option(bool, "bool", "bool") orelse expected_bool; const int = b.option(i64, "int", "int") orelse expected_int; @@ -31,6 +32,7 @@ pub fn build(b: *std.Build) !void { const @"enum" = b.option(Enum, "enum", "enum") orelse expected_enum; const enum_list = b.option([]const Enum, "enum_list", "enum_list") orelse expected_enum_list; const build_id = b.option(std.zig.BuildId, "build_id", "build_id") orelse expected_build_id; + const hex_build_id = b.option(std.zig.BuildId, "hex_build_id", "hex_build_id") orelse expected_hex_build_id; if (@"bool" != expected_bool) return error.TestFailed; if (int != expected_int) return error.TestFailed; @@ -47,6 +49,7 @@ pub fn build(b: *std.Build) !void { if (@"enum" != expected_enum) return error.TestFailed; if (!std.mem.eql(Enum, enum_list, expected_enum_list)) return error.TestFailed; if (!std.meta.eql(build_id, expected_build_id)) return error.TestFailed; + if (!hex_build_id.eql(expected_hex_build_id)) return error.TestFailed; _ = b.addModule("dummy", .{ .root_source_file = b.path("build.zig"), From c8c59d7ba5d4dbca72c5a529b080a12aa2c164b5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 12:30:43 -0700 Subject: [PATCH 09/76] std.json: delete dead API --- lib/std/json.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/std/json.zig b/lib/std/json.zig index f81ac1cd65..c7b7dcf19f 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -69,7 +69,6 @@ pub const ArrayHashMap = @import("json/hashmap.zig").ArrayHashMap; pub const Scanner = @import("json/Scanner.zig"); pub const validate = Scanner.validate; pub const Error = Scanner.Error; -pub const reader = Scanner.reader; pub const default_buffer_size = Scanner.default_buffer_size; pub const Token = Scanner.Token; pub const TokenType = Scanner.TokenType; From 5df52ca0a28d204da0557e88c6c9fe1818bcd6af Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 12:31:26 -0700 Subject: [PATCH 10/76] build runner: print newline before summary --- lib/compiler/build_runner.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compiler/build_runner.zig b/lib/compiler/build_runner.zig index 693e9b4c70..7402a4c66d 100644 --- a/lib/compiler/build_runner.zig +++ b/lib/compiler/build_runner.zig @@ -708,7 +708,7 @@ fn runStepNames( const total_count = success_count + failure_count + pending_count + skipped_count; ttyconf.setColor(w, .cyan) catch {}; - w.writeAll("Build Summary:") catch {}; + w.writeAll("\nBuild Summary:") catch {}; ttyconf.setColor(w, .reset) catch {}; w.print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {}; if (skipped_count > 0) w.print("; {d} skipped", .{skipped_count}) catch {}; From f2a3ac7c0534a74ee544fdf6ef9d2176a8d62389 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 12:49:14 -0700 Subject: [PATCH 11/76] std.fs.File: delete writeFileAll and friends please use File.Writer for these use cases also breaking API changes to std.fs.AtomicFile --- lib/std/Build/Step/Run.zig | 19 ++- lib/std/fs/AtomicFile.zig | 98 ++++++++-------- lib/std/fs/Dir.zig | 180 ++++++++++++----------------- lib/std/fs/File.zig | 107 ----------------- lib/std/fs/test.zig | 39 +++---- src/Builtin.zig | 4 +- src/Compilation.zig | 230 ++++++++++++++++++------------------- src/fmt.zig | 4 +- src/link/MachO.zig | 1 - src/main.zig | 4 +- 10 files changed, 272 insertions(+), 414 deletions(-) diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index e35b602e06..414f7ccff2 100644 --- a/lib/std/Build/Step/Run.zig +++ b/lib/std/Build/Step/Run.zig @@ -169,7 +169,7 @@ pub const Output = struct { pub fn create(owner: *std.Build, name: []const u8) *Run { const run = owner.allocator.create(Run) catch @panic("OOM"); run.* = .{ - .step = Step.init(.{ + .step = .init(.{ .id = base_id, .name = name, .owner = owner, @@ -1769,13 +1769,22 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult { child.stdin = null; }, .lazy_path => |lazy_path| { - const path = lazy_path.getPath2(b, &run.step); - const file = b.build_root.handle.openFile(path, .{}) catch |err| { + const path = lazy_path.getPath3(b, &run.step); + const file = path.root_dir.handle.openFile(path.subPathOrDot(), .{}) catch |err| { return run.step.fail("unable to open stdin file: {s}", .{@errorName(err)}); }; defer file.close(); - child.stdin.?.writeFileAll(file, .{}) catch |err| { - return run.step.fail("unable to write file to stdin: {s}", .{@errorName(err)}); + // TODO https://github.com/ziglang/zig/issues/23955 + var buffer: [1024]u8 = undefined; + var file_reader = file.reader(&buffer); + var stdin_writer = child.stdin.?.writer(&.{}); + _ = stdin_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) { + error.ReadFailed => return run.step.fail("failed to read from {f}: {t}", .{ + path, file_reader.err.?, + }), + error.WriteFailed => return run.step.fail("failed to write to stdin: {t}", .{ + stdin_writer.err.?, + }), }; child.stdin.?.close(); child.stdin = null; diff --git a/lib/std/fs/AtomicFile.zig b/lib/std/fs/AtomicFile.zig index 17a17f8993..96793aec72 100644 --- a/lib/std/fs/AtomicFile.zig +++ b/lib/std/fs/AtomicFile.zig @@ -1,6 +1,13 @@ -file: File, -// TODO either replace this with rand_buf or use []u16 on Windows -tmp_path_buf: [tmp_path_len:0]u8, +const AtomicFile = @This(); +const std = @import("../std.zig"); +const File = std.fs.File; +const Dir = std.fs.Dir; +const fs = std.fs; +const assert = std.debug.assert; +const posix = std.posix; + +file_writer: File.Writer, +random_integer: u64, dest_basename: []const u8, file_open: bool, file_exists: bool, @@ -9,35 +16,24 @@ dir: Dir, pub const InitError = File.OpenError; -pub const random_bytes_len = 12; -const tmp_path_len = fs.base64_encoder.calcSize(random_bytes_len); - /// Note that the `Dir.atomicFile` API may be more handy than this lower-level function. pub fn init( dest_basename: []const u8, mode: File.Mode, dir: Dir, close_dir_on_deinit: bool, + write_buffer: []u8, ) InitError!AtomicFile { - var rand_buf: [random_bytes_len]u8 = undefined; - var tmp_path_buf: [tmp_path_len:0]u8 = undefined; - while (true) { - std.crypto.random.bytes(rand_buf[0..]); - const tmp_path = fs.base64_encoder.encode(&tmp_path_buf, &rand_buf); - tmp_path_buf[tmp_path.len] = 0; - - const file = dir.createFile( - tmp_path, - .{ .mode = mode, .exclusive = true }, - ) catch |err| switch (err) { + const random_integer = std.crypto.random.int(u64); + const tmp_sub_path = std.fmt.hex(random_integer); + const file = dir.createFile(&tmp_sub_path, .{ .mode = mode, .exclusive = true }) catch |err| switch (err) { error.PathAlreadyExists => continue, else => |e| return e, }; - - return AtomicFile{ - .file = file, - .tmp_path_buf = tmp_path_buf, + return .{ + .file_writer = file.writer(write_buffer), + .random_integer = random_integer, .dest_basename = dest_basename, .file_open = true, .file_exists = true, @@ -48,41 +44,51 @@ pub fn init( } /// Always call deinit, even after a successful finish(). -pub fn deinit(self: *AtomicFile) void { - if (self.file_open) { - self.file.close(); - self.file_open = false; +pub fn deinit(af: *AtomicFile) void { + if (af.file_open) { + af.file_writer.file.close(); + af.file_open = false; } - if (self.file_exists) { - self.dir.deleteFile(&self.tmp_path_buf) catch {}; - self.file_exists = false; + if (af.file_exists) { + const tmp_sub_path = std.fmt.hex(af.random_integer); + af.dir.deleteFile(&tmp_sub_path) catch {}; + af.file_exists = false; } - if (self.close_dir_on_deinit) { - self.dir.close(); + if (af.close_dir_on_deinit) { + af.dir.close(); } - self.* = undefined; + af.* = undefined; } -pub const FinishError = posix.RenameError; +pub const FlushError = File.WriteError; + +pub fn flush(af: *AtomicFile) FlushError!void { + af.file_writer.interface.flush() catch |err| switch (err) { + error.WriteFailed => return af.file_writer.err.?, + }; +} + +pub const RenameIntoPlaceError = posix.RenameError; /// On Windows, this function introduces a period of time where some file /// system operations on the destination file will result in /// `error.AccessDenied`, including rename operations (such as the one used in /// this function). -pub fn finish(self: *AtomicFile) FinishError!void { - assert(self.file_exists); - if (self.file_open) { - self.file.close(); - self.file_open = false; +pub fn renameIntoPlace(af: *AtomicFile) RenameIntoPlaceError!void { + assert(af.file_exists); + if (af.file_open) { + af.file_writer.file.close(); + af.file_open = false; } - try posix.renameat(self.dir.fd, self.tmp_path_buf[0..], self.dir.fd, self.dest_basename); - self.file_exists = false; + const tmp_sub_path = std.fmt.hex(af.random_integer); + try posix.renameat(af.dir.fd, &tmp_sub_path, af.dir.fd, af.dest_basename); + af.file_exists = false; } -const AtomicFile = @This(); -const std = @import("../std.zig"); -const File = std.fs.File; -const Dir = std.fs.Dir; -const fs = std.fs; -const assert = std.debug.assert; -const posix = std.posix; +pub const FinishError = FlushError || RenameIntoPlaceError; + +/// Combination of `flush` followed by `renameIntoPlace`. +pub fn finish(af: *AtomicFile) FinishError!void { + try af.flush(); + try af.renameIntoPlace(); +} diff --git a/lib/std/fs/Dir.zig b/lib/std/fs/Dir.zig index 27d97a00cb..16418d216f 100644 --- a/lib/std/fs/Dir.zig +++ b/lib/std/fs/Dir.zig @@ -1,3 +1,20 @@ +const Dir = @This(); +const builtin = @import("builtin"); +const std = @import("../std.zig"); +const File = std.fs.File; +const AtomicFile = std.fs.AtomicFile; +const base64_encoder = fs.base64_encoder; +const posix = std.posix; +const mem = std.mem; +const path = fs.path; +const fs = std.fs; +const Allocator = std.mem.Allocator; +const assert = std.debug.assert; +const linux = std.os.linux; +const windows = std.os.windows; +const native_os = builtin.os.tag; +const have_flock = @TypeOf(posix.system.flock) != void; + fd: Handle, pub const Handle = posix.fd_t; @@ -1862,9 +1879,10 @@ pub fn symLinkW( /// Same as `symLink`, except tries to create the symbolic link until it /// succeeds or encounters an error other than `error.PathAlreadyExists`. -/// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). -/// On WASI, both paths should be encoded as valid UTF-8. -/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding. +/// +/// * On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). +/// * On WASI, both paths should be encoded as valid UTF-8. +/// * On other platforms, both paths are an opaque sequence of bytes with no particular encoding. pub fn atomicSymLink( dir: Dir, target_path: []const u8, @@ -1880,9 +1898,8 @@ pub fn atomicSymLink( const dirname = path.dirname(sym_link_path) orelse "."; - var rand_buf: [AtomicFile.random_bytes_len]u8 = undefined; - - const temp_path_len = dirname.len + 1 + base64_encoder.calcSize(rand_buf.len); + const rand_len = @sizeOf(u64) * 2; + const temp_path_len = dirname.len + 1 + rand_len; var temp_path_buf: [fs.max_path_bytes]u8 = undefined; if (temp_path_len > temp_path_buf.len) return error.NameTooLong; @@ -1892,8 +1909,8 @@ pub fn atomicSymLink( const temp_path = temp_path_buf[0..temp_path_len]; while (true) { - crypto.random.bytes(rand_buf[0..]); - _ = base64_encoder.encode(temp_path[dirname.len + 1 ..], rand_buf[0..]); + const random_integer = std.crypto.random.int(u64); + temp_path[dirname.len + 1 ..][0..rand_len].* = std.fmt.hex(random_integer); if (dir.symLink(target_path, temp_path, flags)) { return dir.rename(temp_path, sym_link_path); @@ -2552,25 +2569,42 @@ pub fn updateFile( try dest_dir.makePath(dirname); } - var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = actual_mode }); + var buffer: [1000]u8 = undefined; // Used only when direct fd-to-fd is not available. + var atomic_file = try dest_dir.atomicFile(dest_path, .{ + .mode = actual_mode, + .write_buffer = &buffer, + }); defer atomic_file.deinit(); - try atomic_file.file.writeFileAll(src_file, .{ .in_len = src_stat.size }); - try atomic_file.file.updateTimes(src_stat.atime, src_stat.mtime); + var src_reader: File.Reader = .initSize(src_file, &.{}, src_stat.size); + const dest_writer = &atomic_file.file_writer.interface; + + _ = dest_writer.sendFileAll(&src_reader, .unlimited) catch |err| switch (err) { + error.ReadFailed => return src_reader.err.?, + error.WriteFailed => return atomic_file.file_writer.err.?, + }; + try atomic_file.file_writer.file.updateTimes(src_stat.atime, src_stat.mtime); try atomic_file.finish(); - return PrevStatus.stale; + return .stale; } pub const CopyFileError = File.OpenError || File.StatError || - AtomicFile.InitError || CopyFileRawError || AtomicFile.FinishError; + AtomicFile.InitError || AtomicFile.FinishError || + File.ReadError || File.WriteError; -/// Guaranteed to be atomic. -/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, -/// there is a possibility of power loss or application termination leaving temporary files present -/// in the same directory as dest_path. -/// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). -/// On WASI, both paths should be encoded as valid UTF-8. -/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding. +/// Atomically creates a new file at `dest_path` within `dest_dir` with the +/// same contents as `source_path` within `source_dir`, overwriting any already +/// existing file. +/// +/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and +/// readily available, there is a possibility of power loss or application +/// termination leaving temporary files present in the same directory as +/// dest_path. +/// +/// On Windows, both paths should be encoded as +/// [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, both paths should be +/// encoded as valid UTF-8. On other platforms, both paths are an opaque +/// sequence of bytes with no particular encoding. pub fn copyFile( source_dir: Dir, source_path: []const u8, @@ -2578,79 +2612,34 @@ pub fn copyFile( dest_path: []const u8, options: CopyFileOptions, ) CopyFileError!void { - var in_file = try source_dir.openFile(source_path, .{}); - defer in_file.close(); + var file_reader: File.Reader = .init(try source_dir.openFile(source_path, .{}), &.{}); + defer file_reader.file.close(); - var size: ?u64 = null; const mode = options.override_mode orelse blk: { - const st = try in_file.stat(); - size = st.size; + const st = try file_reader.file.stat(); + file_reader.size = st.size; break :blk st.mode; }; - var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode }); + var buffer: [1024]u8 = undefined; // Used only when direct fd-to-fd is not available. + var atomic_file = try dest_dir.atomicFile(dest_path, .{ + .mode = mode, + .write_buffer = &buffer, + }); defer atomic_file.deinit(); - try copy_file(in_file.handle, atomic_file.file.handle, size); + _ = atomic_file.file_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) { + error.ReadFailed => return file_reader.err.?, + error.WriteFailed => return atomic_file.file_writer.err.?, + }; + try atomic_file.finish(); } -const CopyFileRawError = error{SystemResources} || posix.CopyFileRangeError || posix.SendFileError; - -// Transfer all the data between two file descriptors in the most efficient way. -// The copy starts at offset 0, the initial offsets are preserved. -// No metadata is transferred over. -fn copy_file(fd_in: posix.fd_t, fd_out: posix.fd_t, maybe_size: ?u64) CopyFileRawError!void { - if (builtin.target.os.tag.isDarwin()) { - const rc = posix.system.fcopyfile(fd_in, fd_out, null, .{ .DATA = true }); - switch (posix.errno(rc)) { - .SUCCESS => return, - .INVAL => unreachable, - .NOMEM => return error.SystemResources, - // The source file is not a directory, symbolic link, or regular file. - // Try with the fallback path before giving up. - .OPNOTSUPP => {}, - else => |err| return posix.unexpectedErrno(err), - } - } - - if (native_os == .linux) { - // Try copy_file_range first as that works at the FS level and is the - // most efficient method (if available). - var offset: u64 = 0; - cfr_loop: while (true) { - // The kernel checks the u64 value `offset+count` for overflow, use - // a 32 bit value so that the syscall won't return EINVAL except for - // impossibly large files (> 2^64-1 - 2^32-1). - const amt = try posix.copy_file_range(fd_in, offset, fd_out, offset, std.math.maxInt(u32), 0); - // Terminate as soon as we have copied size bytes or no bytes - if (maybe_size) |s| { - if (s == amt) break :cfr_loop; - } - if (amt == 0) break :cfr_loop; - offset += amt; - } - return; - } - - // Sendfile is a zero-copy mechanism iff the OS supports it, otherwise the - // fallback code will copy the contents chunk by chunk. - const empty_iovec = [0]posix.iovec_const{}; - var offset: u64 = 0; - sendfile_loop: while (true) { - const amt = try posix.sendfile(fd_out, fd_in, offset, 0, &empty_iovec, &empty_iovec, 0); - // Terminate as soon as we have copied size bytes or no bytes - if (maybe_size) |s| { - if (s == amt) break :sendfile_loop; - } - if (amt == 0) break :sendfile_loop; - offset += amt; - } -} - pub const AtomicFileOptions = struct { mode: File.Mode = File.default_mode, make_path: bool = false, + write_buffer: []u8, }; /// Directly access the `.file` field, and then call `AtomicFile.finish` to @@ -2668,9 +2657,9 @@ pub fn atomicFile(self: Dir, dest_path: []const u8, options: AtomicFileOptions) else try self.openDir(dirname, .{}); - return AtomicFile.init(fs.path.basename(dest_path), options.mode, dir, true); + return .init(fs.path.basename(dest_path), options.mode, dir, true, options.write_buffer); } else { - return AtomicFile.init(dest_path, options.mode, self, false); + return .init(dest_path, options.mode, self, false, options.write_buffer); } } @@ -2768,30 +2757,3 @@ pub fn setPermissions(self: Dir, permissions: Permissions) SetPermissionsError!v const file: File = .{ .handle = self.fd }; try file.setPermissions(permissions); } - -const Metadata = File.Metadata; -pub const MetadataError = File.MetadataError; - -/// Returns a `Metadata` struct, representing the permissions on the directory -pub fn metadata(self: Dir) MetadataError!Metadata { - const file: File = .{ .handle = self.fd }; - return try file.metadata(); -} - -const Dir = @This(); -const builtin = @import("builtin"); -const std = @import("../std.zig"); -const File = std.fs.File; -const AtomicFile = std.fs.AtomicFile; -const base64_encoder = fs.base64_encoder; -const crypto = std.crypto; -const posix = std.posix; -const mem = std.mem; -const path = fs.path; -const fs = std.fs; -const Allocator = std.mem.Allocator; -const assert = std.debug.assert; -const linux = std.os.linux; -const windows = std.os.windows; -const native_os = builtin.os.tag; -const have_flock = @TypeOf(posix.system.flock) != void; diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 5b7e0aa570..50f2a30876 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1089,113 +1089,6 @@ pub fn copyRangeAll(in: File, in_offset: u64, out: File, out_offset: u64, len: u return total_bytes_copied; } -/// Deprecated in favor of `Writer`. -pub const WriteFileOptions = struct { - in_offset: u64 = 0, - in_len: ?u64 = null, - headers_and_trailers: []posix.iovec_const = &[0]posix.iovec_const{}, - header_count: usize = 0, -}; - -/// Deprecated in favor of `Writer`. -pub const WriteFileError = ReadError || error{EndOfStream} || WriteError; - -/// Deprecated in favor of `Writer`. -pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void { - return self.writeFileAllSendfile(in_file, args) catch |err| switch (err) { - error.Unseekable, - error.FastOpenAlreadyInProgress, - error.MessageTooBig, - error.FileDescriptorNotASocket, - error.NetworkUnreachable, - error.NetworkSubsystemFailed, - error.ConnectionRefused, - => return self.writeFileAllUnseekable(in_file, args), - else => |e| return e, - }; -} - -/// Deprecated in favor of `Writer`. -pub fn writeFileAllUnseekable(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void { - const headers = args.headers_and_trailers[0..args.header_count]; - const trailers = args.headers_and_trailers[args.header_count..]; - try self.writevAll(headers); - try in_file.deprecatedReader().skipBytes(args.in_offset, .{ .buf_size = 4096 }); - var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init(); - if (args.in_len) |len| { - var stream = std.io.limitedReader(in_file.deprecatedReader(), len); - try fifo.pump(stream.reader(), self.deprecatedWriter()); - } else { - try fifo.pump(in_file.deprecatedReader(), self.deprecatedWriter()); - } - try self.writevAll(trailers); -} - -/// Deprecated in favor of `Writer`. -fn writeFileAllSendfile(self: File, in_file: File, args: WriteFileOptions) posix.SendFileError!void { - const count = blk: { - if (args.in_len) |l| { - if (l == 0) { - return self.writevAll(args.headers_and_trailers); - } else { - break :blk l; - } - } else { - break :blk 0; - } - }; - const headers = args.headers_and_trailers[0..args.header_count]; - const trailers = args.headers_and_trailers[args.header_count..]; - const zero_iovec = &[0]posix.iovec_const{}; - // When reading the whole file, we cannot put the trailers in the sendfile() syscall, - // because we have no way to determine whether a partial write is past the end of the file or not. - const trls = if (count == 0) zero_iovec else trailers; - const offset = args.in_offset; - const out_fd = self.handle; - const in_fd = in_file.handle; - const flags = 0; - var amt: usize = 0; - hdrs: { - var i: usize = 0; - while (i < headers.len) { - amt = try posix.sendfile(out_fd, in_fd, offset, count, headers[i..], trls, flags); - while (amt >= headers[i].len) { - amt -= headers[i].len; - i += 1; - if (i >= headers.len) break :hdrs; - } - headers[i].base += amt; - headers[i].len -= amt; - } - } - if (count == 0) { - var off: u64 = amt; - while (true) { - amt = try posix.sendfile(out_fd, in_fd, offset + off, 0, zero_iovec, zero_iovec, flags); - if (amt == 0) break; - off += amt; - } - } else { - var off: u64 = amt; - while (off < count) { - amt = try posix.sendfile(out_fd, in_fd, offset + off, count - off, zero_iovec, trailers, flags); - off += amt; - } - amt = @as(usize, @intCast(off - count)); - } - var i: usize = 0; - while (i < trailers.len) { - while (amt >= trailers[i].len) { - amt -= trailers[i].len; - i += 1; - if (i >= trailers.len) return; - } - trailers[i].base += amt; - trailers[i].len -= amt; - amt = try posix.writev(self.handle, trailers[i..]); - } -} - /// Deprecated in favor of `Reader`. pub const DeprecatedReader = io.GenericReader(File, ReadError, read); diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 50cbccf270..9fe2551738 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -1499,32 +1499,18 @@ test "sendfile" { const header2 = "second header\n"; const trailer1 = "trailer1\n"; const trailer2 = "second trailer\n"; - var hdtr = [_]posix.iovec_const{ - .{ - .base = header1, - .len = header1.len, - }, - .{ - .base = header2, - .len = header2.len, - }, - .{ - .base = trailer1, - .len = trailer1.len, - }, - .{ - .base = trailer2, - .len = trailer2.len, - }, - }; + var headers: [2][]const u8 = .{ header1, header2 }; + var trailers: [2][]const u8 = .{ trailer1, trailer2 }; var written_buf: [100]u8 = undefined; - try dest_file.writeFileAll(src_file, .{ - .in_offset = 1, - .in_len = 10, - .headers_and_trailers = &hdtr, - .header_count = 2, - }); + var file_reader = src_file.reader(&.{}); + var fallback_buffer: [50]u8 = undefined; + var file_writer = dest_file.writer(&fallback_buffer); + try file_writer.interface.writeVecAll(&headers); + try file_reader.seekTo(1); + try testing.expectEqual(10, try file_writer.interface.sendFileAll(&file_reader, .limited(10))); + try file_writer.interface.writeVecAll(&trailers); + try file_writer.interface.flush(); const amt = try dest_file.preadAll(&written_buf, 0); try testing.expectEqualStrings("header1\nsecond header\nine1\nsecontrailer1\nsecond trailer\n", written_buf[0..amt]); } @@ -1595,9 +1581,10 @@ test "AtomicFile" { ; { - var af = try ctx.dir.atomicFile(test_out_file, .{}); + var buffer: [100]u8 = undefined; + var af = try ctx.dir.atomicFile(test_out_file, .{ .write_buffer = &buffer }); defer af.deinit(); - try af.file.writeAll(test_content); + try af.file_writer.interface.writeAll(test_content); try af.finish(); } const content = try ctx.dir.readFileAlloc(allocator, test_out_file, 9999); diff --git a/src/Builtin.zig b/src/Builtin.zig index b2cb603f53..b4e05a6089 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -342,9 +342,9 @@ pub fn updateFileOnDisk(file: *File, comp: *Compilation) !void { } // `make_path` matters because the dir hasn't actually been created yet. - var af = try root_dir.atomicFile(sub_path, .{ .make_path = true }); + var af = try root_dir.atomicFile(sub_path, .{ .make_path = true, .write_buffer = &.{} }); defer af.deinit(); - try af.file.writeAll(file.source.?); + try af.file_writer.interface.writeAll(file.source.?); af.finish() catch |err| switch (err) { error.AccessDenied => switch (builtin.os.tag) { .windows => { diff --git a/src/Compilation.zig b/src/Compilation.zig index b5597017c4..649288dab2 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3382,7 +3382,7 @@ pub fn saveState(comp: *Compilation) !void { const gpa = comp.gpa; - var bufs = std.ArrayList(std.posix.iovec_const).init(gpa); + var bufs = std.ArrayList([]const u8).init(gpa); defer bufs.deinit(); var pt_headers = std.ArrayList(Header.PerThread).init(gpa); @@ -3421,50 +3421,50 @@ pub fn saveState(comp: *Compilation) !void { try bufs.ensureTotalCapacityPrecise(14 + 8 * pt_headers.items.len); addBuf(&bufs, mem.asBytes(&header)); - addBuf(&bufs, mem.sliceAsBytes(pt_headers.items)); + addBuf(&bufs, @ptrCast(pt_headers.items)); - addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.interned_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.interned_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.zon_file_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.zon_file_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.embed_file_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.embed_file_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.values())); + addBuf(&bufs, @ptrCast(ip.src_hash_deps.keys())); + addBuf(&bufs, @ptrCast(ip.src_hash_deps.values())); + addBuf(&bufs, @ptrCast(ip.nav_val_deps.keys())); + addBuf(&bufs, @ptrCast(ip.nav_val_deps.values())); + addBuf(&bufs, @ptrCast(ip.nav_ty_deps.keys())); + addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values())); + addBuf(&bufs, @ptrCast(ip.interned_deps.keys())); + addBuf(&bufs, @ptrCast(ip.interned_deps.values())); + addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys())); + addBuf(&bufs, @ptrCast(ip.zon_file_deps.values())); + addBuf(&bufs, @ptrCast(ip.embed_file_deps.keys())); + addBuf(&bufs, @ptrCast(ip.embed_file_deps.values())); + addBuf(&bufs, @ptrCast(ip.namespace_deps.keys())); + addBuf(&bufs, @ptrCast(ip.namespace_deps.values())); + addBuf(&bufs, @ptrCast(ip.namespace_name_deps.keys())); + addBuf(&bufs, @ptrCast(ip.namespace_name_deps.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.first_dependency.keys())); - addBuf(&bufs, mem.sliceAsBytes(ip.first_dependency.values())); - addBuf(&bufs, mem.sliceAsBytes(ip.dep_entries.items)); - addBuf(&bufs, mem.sliceAsBytes(ip.free_dep_entries.items)); + addBuf(&bufs, @ptrCast(ip.first_dependency.keys())); + addBuf(&bufs, @ptrCast(ip.first_dependency.values())); + addBuf(&bufs, @ptrCast(ip.dep_entries.items)); + addBuf(&bufs, @ptrCast(ip.free_dep_entries.items)); for (ip.locals, pt_headers.items) |*local, pt_header| { if (pt_header.intern_pool.limbs_len > 0) { - addBuf(&bufs, mem.sliceAsBytes(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len])); + addBuf(&bufs, @ptrCast(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len])); } if (pt_header.intern_pool.extra_len > 0) { - addBuf(&bufs, mem.sliceAsBytes(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len])); + addBuf(&bufs, @ptrCast(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len])); } if (pt_header.intern_pool.items_len > 0) { - addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len])); - addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len])); + addBuf(&bufs, @ptrCast(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len])); + addBuf(&bufs, @ptrCast(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len])); } if (pt_header.intern_pool.string_bytes_len > 0) { addBuf(&bufs, local.shared.strings.view().items(.@"0")[0..pt_header.intern_pool.string_bytes_len]); } if (pt_header.intern_pool.tracked_insts_len > 0) { - addBuf(&bufs, mem.sliceAsBytes(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len])); + addBuf(&bufs, @ptrCast(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len])); } if (pt_header.intern_pool.files_len > 0) { - addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.bin_digest)[0..pt_header.intern_pool.files_len])); - addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len])); + addBuf(&bufs, @ptrCast(local.shared.files.view().items(.bin_digest)[0..pt_header.intern_pool.files_len])); + addBuf(&bufs, @ptrCast(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len])); } } @@ -3482,95 +3482,95 @@ pub fn saveState(comp: *Compilation) !void { try bufs.ensureUnusedCapacity(85); addBuf(&bufs, wasm.string_bytes.items); // TODO make it well-defined memory layout - //addBuf(&bufs, mem.sliceAsBytes(wasm.objects.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.func_types.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_function_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_function_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_functions.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_global_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_global_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_globals.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_table_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_table_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_tables.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_memory_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_memory_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_memories.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.tag))); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.offset))); + //addBuf(&bufs, @ptrCast(wasm.objects.items)); + addBuf(&bufs, @ptrCast(wasm.func_types.keys())); + addBuf(&bufs, @ptrCast(wasm.object_function_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.object_function_imports.values())); + addBuf(&bufs, @ptrCast(wasm.object_functions.items)); + addBuf(&bufs, @ptrCast(wasm.object_global_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.object_global_imports.values())); + addBuf(&bufs, @ptrCast(wasm.object_globals.items)); + addBuf(&bufs, @ptrCast(wasm.object_table_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.object_table_imports.values())); + addBuf(&bufs, @ptrCast(wasm.object_tables.items)); + addBuf(&bufs, @ptrCast(wasm.object_memory_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.object_memory_imports.values())); + addBuf(&bufs, @ptrCast(wasm.object_memories.items)); + addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.tag))); + addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.offset))); // TODO handle the union safety field - //addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.pointee))); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.addend))); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_init_funcs.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_segments.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_datas.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_custom_segments.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_custom_segments.values())); + //addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.pointee))); + addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.addend))); + addBuf(&bufs, @ptrCast(wasm.object_init_funcs.items)); + addBuf(&bufs, @ptrCast(wasm.object_data_segments.items)); + addBuf(&bufs, @ptrCast(wasm.object_datas.items)); + addBuf(&bufs, @ptrCast(wasm.object_data_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.object_data_imports.values())); + addBuf(&bufs, @ptrCast(wasm.object_custom_segments.keys())); + addBuf(&bufs, @ptrCast(wasm.object_custom_segments.values())); // TODO make it well-defined memory layout - // addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdats.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations_table.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations_table.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdat_symbols.items(.kind))); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdat_symbols.items(.index))); - addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.tag))); - addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.offset))); + // addBuf(&bufs, @ptrCast(wasm.object_comdats.items)); + addBuf(&bufs, @ptrCast(wasm.object_relocations_table.keys())); + addBuf(&bufs, @ptrCast(wasm.object_relocations_table.values())); + addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.kind))); + addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.index))); + addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.tag))); + addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.offset))); // TODO handle the union safety field - //addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.pointee))); - addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.addend))); - addBuf(&bufs, mem.sliceAsBytes(wasm.uav_fixups.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.nav_fixups.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.func_table_fixups.items)); + //addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.pointee))); + addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.addend))); + addBuf(&bufs, @ptrCast(wasm.uav_fixups.items)); + addBuf(&bufs, @ptrCast(wasm.nav_fixups.items)); + addBuf(&bufs, @ptrCast(wasm.func_table_fixups.items)); if (is_obj) { - addBuf(&bufs, mem.sliceAsBytes(wasm.navs_obj.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.navs_obj.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_obj.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_obj.values())); + addBuf(&bufs, @ptrCast(wasm.navs_obj.keys())); + addBuf(&bufs, @ptrCast(wasm.navs_obj.values())); + addBuf(&bufs, @ptrCast(wasm.uavs_obj.keys())); + addBuf(&bufs, @ptrCast(wasm.uavs_obj.values())); } else { - addBuf(&bufs, mem.sliceAsBytes(wasm.navs_exe.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.navs_exe.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_exe.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_exe.values())); + addBuf(&bufs, @ptrCast(wasm.navs_exe.keys())); + addBuf(&bufs, @ptrCast(wasm.navs_exe.values())); + addBuf(&bufs, @ptrCast(wasm.uavs_exe.keys())); + addBuf(&bufs, @ptrCast(wasm.uavs_exe.values())); } - addBuf(&bufs, mem.sliceAsBytes(wasm.overaligned_uavs.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.overaligned_uavs.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_funcs.keys())); + addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.keys())); + addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.values())); + addBuf(&bufs, @ptrCast(wasm.zcu_funcs.keys())); // TODO handle the union safety field - // addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_funcs.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.nav_exports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.nav_exports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.uav_exports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.uav_exports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.missing_exports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.function_exports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.function_exports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.hidden_function_exports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.hidden_function_exports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.global_exports.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.functions.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.function_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.function_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.data_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.data_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.data_segments.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.globals.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.global_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.global_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.tables.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.table_imports.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.table_imports.values())); - addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_indirect_function_set.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_indirect_function_import_set.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.object_indirect_function_set.keys())); - addBuf(&bufs, mem.sliceAsBytes(wasm.mir_instructions.items(.tag))); + // addBuf(&bufs, @ptrCast(wasm.zcu_funcs.values())); + addBuf(&bufs, @ptrCast(wasm.nav_exports.keys())); + addBuf(&bufs, @ptrCast(wasm.nav_exports.values())); + addBuf(&bufs, @ptrCast(wasm.uav_exports.keys())); + addBuf(&bufs, @ptrCast(wasm.uav_exports.values())); + addBuf(&bufs, @ptrCast(wasm.imports.keys())); + addBuf(&bufs, @ptrCast(wasm.missing_exports.keys())); + addBuf(&bufs, @ptrCast(wasm.function_exports.keys())); + addBuf(&bufs, @ptrCast(wasm.function_exports.values())); + addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.keys())); + addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.values())); + addBuf(&bufs, @ptrCast(wasm.global_exports.items)); + addBuf(&bufs, @ptrCast(wasm.functions.keys())); + addBuf(&bufs, @ptrCast(wasm.function_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.function_imports.values())); + addBuf(&bufs, @ptrCast(wasm.data_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.data_imports.values())); + addBuf(&bufs, @ptrCast(wasm.data_segments.keys())); + addBuf(&bufs, @ptrCast(wasm.globals.keys())); + addBuf(&bufs, @ptrCast(wasm.global_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.global_imports.values())); + addBuf(&bufs, @ptrCast(wasm.tables.keys())); + addBuf(&bufs, @ptrCast(wasm.table_imports.keys())); + addBuf(&bufs, @ptrCast(wasm.table_imports.values())); + addBuf(&bufs, @ptrCast(wasm.zcu_indirect_function_set.keys())); + addBuf(&bufs, @ptrCast(wasm.object_indirect_function_import_set.keys())); + addBuf(&bufs, @ptrCast(wasm.object_indirect_function_set.keys())); + addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.tag))); // TODO handle the union safety field - //addBuf(&bufs, mem.sliceAsBytes(wasm.mir_instructions.items(.data))); - addBuf(&bufs, mem.sliceAsBytes(wasm.mir_extra.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.mir_locals.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.tag_name_bytes.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.tag_name_offs.items)); + //addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.data))); + addBuf(&bufs, @ptrCast(wasm.mir_extra.items)); + addBuf(&bufs, @ptrCast(wasm.mir_locals.items)); + addBuf(&bufs, @ptrCast(wasm.tag_name_bytes.items)); + addBuf(&bufs, @ptrCast(wasm.tag_name_offs.items)); // TODO add as header fields // entry_resolution: FunctionImport.Resolution @@ -3596,16 +3596,16 @@ pub fn saveState(comp: *Compilation) !void { // Using an atomic file prevents a crash or power failure from corrupting // the previous incremental compilation state. - var af = try lf.emit.root_dir.handle.atomicFile(basename, .{}); + var write_buffer: [1024]u8 = undefined; + var af = try lf.emit.root_dir.handle.atomicFile(basename, .{ .write_buffer = &write_buffer }); defer af.deinit(); - try af.file.pwritevAll(bufs.items, 0); + try af.file_writer.interface.writeVecAll(bufs.items); try af.finish(); } -fn addBuf(list: *std.ArrayList(std.posix.iovec_const), buf: []const u8) void { - // Even when len=0, the undefined pointer might cause EFAULT. +fn addBuf(list: *std.ArrayList([]const u8), buf: []const u8) void { if (buf.len == 0) return; - list.appendAssumeCapacity(.{ .base = buf.ptr, .len = buf.len }); + list.appendAssumeCapacity(buf); } /// This function is temporally single-threaded. diff --git a/src/fmt.zig b/src/fmt.zig index 23e668d245..92ae22e4bc 100644 --- a/src/fmt.zig +++ b/src/fmt.zig @@ -348,10 +348,10 @@ fn fmtPathFile( try fmt.stdout_writer.interface.print("{s}\n", .{file_path}); fmt.any_error = true; } else { - var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode }); + var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode, .write_buffer = &.{} }); defer af.deinit(); - try af.file.writeAll(fmt.out_buffer.getWritten()); + try af.file_writer.interface.writeAll(fmt.out_buffer.getWritten()); try af.finish(); try fmt.stdout_writer.interface.print("{s}\n", .{file_path}); } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 734b4b6a04..5b0e8520d1 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -612,7 +612,6 @@ pub fn flush( }; const emit = self.base.emit; invalidateKernelCache(emit.root_dir.handle, emit.sub_path) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, else => |e| return diags.fail("failed to invalidate kernel cache: {s}", .{@errorName(e)}), }; } diff --git a/src/main.zig b/src/main.zig index 7ad40e1a68..d3655c9d79 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4624,7 +4624,9 @@ fn cmdTranslateC( fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{ path, fs.path.sep_str, out_zig_path, @errorName(err) }); }; defer zig_file.close(); - try fs.File.stdout().writeFileAll(zig_file, .{}); + var stdout_writer = fs.File.stdout().writer(&stdout_buffer); + var file_reader = zig_file.reader(&.{}); + _ = try stdout_writer.interface.sendFileAll(&file_reader, .unlimited); return cleanExit(); } } From f1576ef14c5956cdab742aaf31ec4c672b54252b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 16:43:47 -0700 Subject: [PATCH 12/76] objcopy: delete most of it this code is not up to zig project standards tracked by #24522 oh, and fix not adjusting buffer seek position in std.fs.File.Reader --- lib/compiler/objcopy.zig | 969 ++--------------------- lib/std/elf.zig | 275 +++---- lib/std/fs/File.zig | 22 +- test/standalone/stack_iterator/build.zig | 113 +-- tools/gen_stubs.zig | 3 +- 5 files changed, 240 insertions(+), 1142 deletions(-) diff --git a/lib/compiler/objcopy.zig b/lib/compiler/objcopy.zig index 52ffe208f6..5908f8b73d 100644 --- a/lib/compiler/objcopy.zig +++ b/lib/compiler/objcopy.zig @@ -13,6 +13,9 @@ const Server = std.zig.Server; var stdin_buffer: [1024]u8 = undefined; var stdout_buffer: [1024]u8 = undefined; +var input_buffer: [1024]u8 = undefined; +var output_buffer: [1024]u8 = undefined; + pub fn main() !void { var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena_instance.deinit(); @@ -145,13 +148,16 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void const input = opt_input orelse fatal("expected input parameter", .{}); const output = opt_output orelse fatal("expected output parameter", .{}); - var in_file = fs.cwd().openFile(input, .{}) catch |err| - fatal("unable to open '{s}': {s}", .{ input, @errorName(err) }); - defer in_file.close(); + const input_file = fs.cwd().openFile(input, .{}) catch |err| fatal("failed to open {s}: {t}", .{ input, err }); + defer input_file.close(); - const elf_hdr = std.elf.Header.read(in_file) catch |err| switch (err) { - error.InvalidElfMagic => fatal("not an ELF file: '{s}'", .{input}), - else => fatal("unable to read '{s}': {s}", .{ input, @errorName(err) }), + const stat = input_file.stat() catch |err| fatal("failed to stat {s}: {t}", .{ input, err }); + + var in: File.Reader = .initSize(input_file, &input_buffer, stat.size); + + const elf_hdr = std.elf.Header.read(&in.interface) catch |err| switch (err) { + error.ReadFailed => fatal("unable to read {s}: {t}", .{ input, in.err.? }), + else => |e| fatal("invalid elf file: {t}", .{e}), }; const in_ofmt = .elf; @@ -168,16 +174,12 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void } }; - const mode = mode: { - if (out_fmt != .elf or only_keep_debug) - break :mode fs.File.default_mode; - if (in_file.stat()) |stat| - break :mode stat.mode - else |_| - break :mode fs.File.default_mode; - }; - var out_file = try fs.cwd().createFile(output, .{ .mode = mode }); - defer out_file.close(); + const mode = if (out_fmt != .elf or only_keep_debug) fs.File.default_mode else stat.mode; + + var output_file = try fs.cwd().createFile(output, .{ .mode = mode }); + defer output_file.close(); + + var out = output_file.writer(&output_buffer); switch (out_fmt) { .hex, .raw => { @@ -192,7 +194,7 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void if (set_section_flags != null) fatal("zig objcopy: ELF to RAW or HEX copying does not support --set_section_flags", .{}); - try emitElf(arena, in_file, out_file, elf_hdr, .{ + try emitElf(arena, &in, &out, elf_hdr, .{ .ofmt = out_fmt, .only_section = only_section, .pad_to = pad_to, @@ -208,22 +210,13 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void if (pad_to) |_| fatal("zig objcopy: ELF to ELF copying does not support --pad-to", .{}); - try stripElf(arena, in_file, out_file, elf_hdr, .{ - .strip_debug = strip_debug, - .strip_all = strip_all, - .only_keep_debug = only_keep_debug, - .add_debuglink = opt_add_debuglink, - .extract_to = opt_extract, - .compress_debug = compress_debug_sections, - .add_section = add_section, - .set_section_alignment = set_section_alignment, - .set_section_flags = set_section_flags, - }); - return std.process.cleanExit(); + fatal("unimplemented", .{}); }, else => fatal("unsupported output object format: {s}", .{@tagName(out_fmt)}), } + try out.end(); + if (listen) { var stdin_reader = fs.File.stdin().reader(&stdin_buffer); var stdout_writer = fs.File.stdout().writer(&stdout_buffer); @@ -304,12 +297,12 @@ const SetSectionFlags = struct { fn emitElf( arena: Allocator, - in_file: File, - out_file: File, + in: *File.Reader, + out: *File.Writer, elf_hdr: elf.Header, options: EmitRawElfOptions, ) !void { - var binary_elf_output = try BinaryElfOutput.parse(arena, in_file, elf_hdr); + var binary_elf_output = try BinaryElfOutput.parse(arena, in, elf_hdr); defer binary_elf_output.deinit(); if (options.ofmt == .elf) { @@ -328,8 +321,8 @@ fn emitElf( continue; } - try writeBinaryElfSection(in_file, out_file, section); - try padFile(out_file, options.pad_to); + try writeBinaryElfSection(in, out, section); + try padFile(out, options.pad_to); return; } }, @@ -342,10 +335,10 @@ fn emitElf( switch (options.ofmt) { .raw => { for (binary_elf_output.sections.items) |section| { - try out_file.seekTo(section.binaryOffset); - try writeBinaryElfSection(in_file, out_file, section); + try out.seekTo(section.binaryOffset); + try writeBinaryElfSection(in, out, section); } - try padFile(out_file, options.pad_to); + try padFile(out, options.pad_to); }, .hex => { if (binary_elf_output.segments.items.len == 0) return; @@ -353,15 +346,15 @@ fn emitElf( return error.InvalidHexfileAddressRange; } - var hex_writer = HexWriter{ .out_file = out_file }; + var hex_writer = HexWriter{ .out = out }; for (binary_elf_output.segments.items) |segment| { - try hex_writer.writeSegment(segment, in_file); + try hex_writer.writeSegment(segment, in); } if (options.pad_to) |_| { // Padding to a size in hex files isn't applicable return error.InvalidArgument; } - try hex_writer.writeEOF(); + try hex_writer.writeEof(); }, else => unreachable, } @@ -399,7 +392,7 @@ const BinaryElfOutput = struct { self.segments.deinit(self.allocator); } - pub fn parse(allocator: Allocator, elf_file: File, elf_hdr: elf.Header) !Self { + pub fn parse(allocator: Allocator, in: *File.Reader, elf_hdr: elf.Header) !Self { var self: Self = .{ .segments = .{}, .sections = .{}, @@ -412,7 +405,7 @@ const BinaryElfOutput = struct { self.shstrtab = blk: { if (elf_hdr.shstrndx >= elf_hdr.shnum) break :blk null; - var section_headers = elf_hdr.section_header_iterator(&elf_file); + var section_headers = elf_hdr.iterateSectionHeaders(in); var section_counter: usize = 0; while (section_counter < elf_hdr.shstrndx) : (section_counter += 1) { @@ -421,18 +414,13 @@ const BinaryElfOutput = struct { const shstrtab_shdr = (try section_headers.next()).?; - const buffer = try allocator.alloc(u8, @intCast(shstrtab_shdr.sh_size)); - errdefer allocator.free(buffer); - - const num_read = try elf_file.preadAll(buffer, shstrtab_shdr.sh_offset); - if (num_read != buffer.len) return error.EndOfStream; - - break :blk buffer; + try in.seekTo(shstrtab_shdr.sh_offset); + break :blk try in.interface.readAlloc(allocator, shstrtab_shdr.sh_size); }; errdefer if (self.shstrtab) |shstrtab| allocator.free(shstrtab); - var section_headers = elf_hdr.section_header_iterator(&elf_file); + var section_headers = elf_hdr.iterateSectionHeaders(in); while (try section_headers.next()) |section| { if (sectionValidForOutput(section)) { const newSection = try allocator.create(BinaryElfSection); @@ -451,7 +439,7 @@ const BinaryElfOutput = struct { } } - var program_headers = elf_hdr.program_header_iterator(&elf_file); + var program_headers = elf_hdr.iterateProgramHeaders(in); while (try program_headers.next()) |phdr| { if (phdr.p_type == elf.PT_LOAD) { const newSegment = try allocator.create(BinaryElfSegment); @@ -539,19 +527,17 @@ const BinaryElfOutput = struct { } }; -fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void { - try out_file.writeFileAll(elf_file, .{ - .in_offset = section.elfOffset, - .in_len = section.fileSize, - }); +fn writeBinaryElfSection(in: *File.Reader, out: *File.Writer, section: *BinaryElfSection) !void { + try in.seekTo(section.elfOffset); + _ = try out.interface.sendFileAll(in, .limited(section.fileSize)); } const HexWriter = struct { prev_addr: ?u32 = null, - out_file: File, + out: *File.Writer, /// Max data bytes per line of output - const MAX_PAYLOAD_LEN: u8 = 16; + const max_payload_len: u8 = 16; fn addressParts(address: u16) [2]u8 { const msb: u8 = @truncate(address >> 8); @@ -627,13 +613,13 @@ const HexWriter = struct { return (sum ^ 0xFF) +% 1; } - fn write(self: Record, file: File) File.WriteError!void { + fn write(self: Record, out: *File.Writer) !void { const linesep = "\r\n"; // colon, (length, address, type, payload, checksum) as hex, CRLF - const BUFSIZE = 1 + (1 + 2 + 1 + MAX_PAYLOAD_LEN + 1) * 2 + linesep.len; + const BUFSIZE = 1 + (1 + 2 + 1 + max_payload_len + 1) * 2 + linesep.len; var outbuf: [BUFSIZE]u8 = undefined; const payload_bytes = self.getPayloadBytes(); - assert(payload_bytes.len <= MAX_PAYLOAD_LEN); + assert(payload_bytes.len <= max_payload_len); const line = try std.fmt.bufPrint(&outbuf, ":{0X:0>2}{1X:0>4}{2X:0>2}{3X}{4X:0>2}" ++ linesep, .{ @as(u8, @intCast(payload_bytes.len)), @@ -642,38 +628,37 @@ const HexWriter = struct { payload_bytes, self.checksum(), }); - try file.writeAll(line); + try out.interface.writeAll(line); } }; - pub fn writeSegment(self: *HexWriter, segment: *const BinaryElfSegment, elf_file: File) !void { - var buf: [MAX_PAYLOAD_LEN]u8 = undefined; + pub fn writeSegment(self: *HexWriter, segment: *const BinaryElfSegment, in: *File.Reader) !void { + var buf: [max_payload_len]u8 = undefined; var bytes_read: usize = 0; while (bytes_read < segment.fileSize) { const row_address: u32 = @intCast(segment.physicalAddress + bytes_read); const remaining = segment.fileSize - bytes_read; - const to_read: usize = @intCast(@min(remaining, MAX_PAYLOAD_LEN)); - const did_read = try elf_file.preadAll(buf[0..to_read], segment.elfOffset + bytes_read); - if (did_read < to_read) return error.UnexpectedEOF; + const dest = buf[0..@min(remaining, max_payload_len)]; + try in.seekTo(segment.elfOffset + bytes_read); + try in.interface.readSliceAll(dest); + try self.writeDataRow(row_address, dest); - try self.writeDataRow(row_address, buf[0..did_read]); - - bytes_read += did_read; + bytes_read += dest.len; } } - fn writeDataRow(self: *HexWriter, address: u32, data: []const u8) File.WriteError!void { + fn writeDataRow(self: *HexWriter, address: u32, data: []const u8) !void { const record = Record.Data(address, data); if (address > 0xFFFF and (self.prev_addr == null or record.address != self.prev_addr.?)) { - try Record.Address(address).write(self.out_file); + try Record.Address(address).write(self.out); } - try record.write(self.out_file); + try record.write(self.out); self.prev_addr = @intCast(record.address + data.len); } - fn writeEOF(self: HexWriter) File.WriteError!void { - try Record.EOF().write(self.out_file); + fn writeEof(self: HexWriter) !void { + try Record.EOF().write(self.out); } }; @@ -686,9 +671,9 @@ fn containsValidAddressRange(segments: []*BinaryElfSegment) bool { return true; } -fn padFile(f: File, opt_size: ?u64) !void { +fn padFile(out: *File.Writer, opt_size: ?u64) !void { const size = opt_size orelse return; - try f.setEndPos(size); + try out.file.setEndPos(size); } test "HexWriter.Record.Address has correct payload and checksum" { @@ -732,836 +717,6 @@ test "containsValidAddressRange" { try std.testing.expect(containsValidAddressRange(&buf)); } -// ------------- -// ELF to ELF stripping - -const StripElfOptions = struct { - extract_to: ?[]const u8 = null, - add_debuglink: ?[]const u8 = null, - strip_all: bool = false, - strip_debug: bool = false, - only_keep_debug: bool = false, - compress_debug: bool = false, - add_section: ?AddSection, - set_section_alignment: ?SetSectionAlignment, - set_section_flags: ?SetSectionFlags, -}; - -fn stripElf( - allocator: Allocator, - in_file: File, - out_file: File, - elf_hdr: elf.Header, - options: StripElfOptions, -) !void { - const Filter = ElfFileHelper.Filter; - const DebugLink = ElfFileHelper.DebugLink; - - const filter: Filter = filter: { - if (options.only_keep_debug) break :filter .debug; - if (options.strip_all) break :filter .program; - if (options.strip_debug) break :filter .program_and_symbols; - break :filter .all; - }; - - const filter_complement: ?Filter = blk: { - if (options.extract_to) |_| { - break :blk switch (filter) { - .program => .debug_and_symbols, - .debug => .program_and_symbols, - .program_and_symbols => .debug, - .debug_and_symbols => .program, - .all => fatal("zig objcopy: nothing to extract", .{}), - }; - } else { - break :blk null; - } - }; - const debuglink_path = path: { - if (options.add_debuglink) |path| break :path path; - if (options.extract_to) |path| break :path path; - break :path null; - }; - - switch (elf_hdr.is_64) { - inline else => |is_64| { - var elf_file = try ElfFile(is_64).parse(allocator, in_file, elf_hdr); - defer elf_file.deinit(); - - if (options.add_section) |user_section| { - for (elf_file.sections) |section| { - if (std.mem.eql(u8, section.name, user_section.section_name)) { - fatal("zig objcopy: unable to add section '{s}'. Section already exists in input", .{user_section.section_name}); - } - } - } - - if (filter_complement) |flt| { - // write the .dbg file and close it, so it can be read back to compute the debuglink checksum. - const path = options.extract_to.?; - const dbg_file = std.fs.cwd().createFile(path, .{}) catch |err| { - fatal("zig objcopy: unable to create '{s}': {s}", .{ path, @errorName(err) }); - }; - defer dbg_file.close(); - - try elf_file.emit(allocator, dbg_file, in_file, .{ .section_filter = flt, .compress_debug = options.compress_debug }); - } - - const debuglink: ?DebugLink = if (debuglink_path) |path| ElfFileHelper.createDebugLink(path) else null; - try elf_file.emit(allocator, out_file, in_file, .{ - .section_filter = filter, - .debuglink = debuglink, - .compress_debug = options.compress_debug, - .add_section = options.add_section, - .set_section_alignment = options.set_section_alignment, - .set_section_flags = options.set_section_flags, - }); - }, - } -} - -// note: this is "a minimal effort implementation" -// It doesn't support all possibile elf files: some sections type may need fixups, the program header may need fix up, ... -// It was written for a specific use case (strip debug info to a sperate file, for linux 64-bits executables built with `zig` or `zig c++` ) -// It moves and reoders the sections as little as possible to avoid having to do fixups. -// TODO: support non-native endianess - -fn ElfFile(comptime is_64: bool) type { - const Elf_Ehdr = if (is_64) elf.Elf64_Ehdr else elf.Elf32_Ehdr; - const Elf_Phdr = if (is_64) elf.Elf64_Phdr else elf.Elf32_Phdr; - const Elf_Shdr = if (is_64) elf.Elf64_Shdr else elf.Elf32_Shdr; - const Elf_Chdr = if (is_64) elf.Elf64_Chdr else elf.Elf32_Chdr; - const Elf_Sym = if (is_64) elf.Elf64_Sym else elf.Elf32_Sym; - const Elf_OffSize = if (is_64) elf.Elf64_Off else elf.Elf32_Off; - - return struct { - raw_elf_header: Elf_Ehdr, - program_segments: []const Elf_Phdr, - sections: []const Section, - arena: std.heap.ArenaAllocator, - - const SectionCategory = ElfFileHelper.SectionCategory; - const section_memory_align: std.mem.Alignment = .of(Elf_Sym); // most restrictive of what we may load in memory - const Section = struct { - section: Elf_Shdr, - name: []const u8 = "", - segment: ?*const Elf_Phdr = null, // if the section is used by a program segment (there can be more than one) - payload: ?[]align(section_memory_align.toByteUnits()) const u8 = null, // if we need the data in memory - category: SectionCategory = .none, // should the section be kept in the exe or stripped to the debug database, or both. - }; - - const Self = @This(); - - pub fn parse(gpa: Allocator, in_file: File, header: elf.Header) !Self { - var arena = std.heap.ArenaAllocator.init(gpa); - errdefer arena.deinit(); - const allocator = arena.allocator(); - - var raw_header: Elf_Ehdr = undefined; - { - const bytes_read = try in_file.preadAll(std.mem.asBytes(&raw_header), 0); - if (bytes_read < @sizeOf(Elf_Ehdr)) - return error.TRUNCATED_ELF; - } - - // program header: list of segments - const program_segments = blk: { - if (@sizeOf(Elf_Phdr) != header.phentsize) - fatal("zig objcopy: unsupported ELF file, unexpected phentsize ({d})", .{header.phentsize}); - - const program_header = try allocator.alloc(Elf_Phdr, header.phnum); - const bytes_read = try in_file.preadAll(std.mem.sliceAsBytes(program_header), header.phoff); - if (bytes_read < @sizeOf(Elf_Phdr) * header.phnum) - return error.TRUNCATED_ELF; - break :blk program_header; - }; - - // section header - const sections = blk: { - if (@sizeOf(Elf_Shdr) != header.shentsize) - fatal("zig objcopy: unsupported ELF file, unexpected shentsize ({d})", .{header.shentsize}); - - const section_header = try allocator.alloc(Section, header.shnum); - - const raw_section_header = try allocator.alloc(Elf_Shdr, header.shnum); - defer allocator.free(raw_section_header); - const bytes_read = try in_file.preadAll(std.mem.sliceAsBytes(raw_section_header), header.shoff); - if (bytes_read < @sizeOf(Elf_Phdr) * header.shnum) - return error.TRUNCATED_ELF; - - for (section_header, raw_section_header) |*section, hdr| { - section.* = .{ .section = hdr }; - } - break :blk section_header; - }; - - // load data to memory for some sections: - // string tables for access - // sections than need modifications when other sections move. - for (sections, 0..) |*section, idx| { - const need_data = switch (section.section.sh_type) { - elf.DT_VERSYM => true, - elf.SHT_SYMTAB, elf.SHT_DYNSYM => true, - else => false, - }; - const need_strings = (idx == header.shstrndx); - - if (need_data or need_strings) { - const buffer = try allocator.alignedAlloc(u8, section_memory_align, @intCast(section.section.sh_size)); - const bytes_read = try in_file.preadAll(buffer, section.section.sh_offset); - if (bytes_read != section.section.sh_size) return error.TRUNCATED_ELF; - section.payload = buffer; - } - } - - // fill-in sections info: - // resolve the name - // find if a program segment uses the section - // categorize sections usage (used by program segments, debug datadase, common metadata, symbol table) - for (sections) |*section| { - section.segment = for (program_segments) |*seg| { - if (sectionWithinSegment(section.section, seg.*)) break seg; - } else null; - - if (section.section.sh_name != 0 and header.shstrndx != elf.SHN_UNDEF) - section.name = std.mem.span(@as([*:0]const u8, @ptrCast(§ions[header.shstrndx].payload.?[section.section.sh_name]))); - - const category_from_program: SectionCategory = if (section.segment != null) .exe else .debug; - section.category = switch (section.section.sh_type) { - elf.SHT_NOTE => .common, - elf.SHT_SYMTAB => .symbols, // "strip all" vs "strip only debug" - elf.SHT_DYNSYM => .exe, - elf.SHT_PROGBITS => cat: { - if (std.mem.eql(u8, section.name, ".comment")) break :cat .exe; - if (std.mem.eql(u8, section.name, ".gnu_debuglink")) break :cat .none; - break :cat category_from_program; - }, - elf.SHT_LOPROC...elf.SHT_HIPROC => .common, // don't strip unknown sections - elf.SHT_LOUSER...elf.SHT_HIUSER => .common, // don't strip unknown sections - else => category_from_program, - }; - } - - sections[0].category = .common; // mandatory null section - if (header.shstrndx != elf.SHN_UNDEF) - sections[header.shstrndx].category = .common; // string table for the headers - - // recursively propagate section categories to their linked sections, so that they are kept together - var dirty: u1 = 1; - while (dirty != 0) { - dirty = 0; - - for (sections) |*section| { - if (section.section.sh_link != elf.SHN_UNDEF) - dirty |= ElfFileHelper.propagateCategory(§ions[section.section.sh_link].category, section.category); - if ((section.section.sh_flags & elf.SHF_INFO_LINK) != 0 and section.section.sh_info != elf.SHN_UNDEF) - dirty |= ElfFileHelper.propagateCategory(§ions[section.section.sh_info].category, section.category); - } - } - - return Self{ - .arena = arena, - .raw_elf_header = raw_header, - .program_segments = program_segments, - .sections = sections, - }; - } - - pub fn deinit(self: *Self) void { - self.arena.deinit(); - } - - const Filter = ElfFileHelper.Filter; - const DebugLink = ElfFileHelper.DebugLink; - const EmitElfOptions = struct { - section_filter: Filter = .all, - debuglink: ?DebugLink = null, - compress_debug: bool = false, - add_section: ?AddSection = null, - set_section_alignment: ?SetSectionAlignment = null, - set_section_flags: ?SetSectionFlags = null, - }; - fn emit(self: *const Self, gpa: Allocator, out_file: File, in_file: File, options: EmitElfOptions) !void { - var arena = std.heap.ArenaAllocator.init(gpa); - defer arena.deinit(); - const allocator = arena.allocator(); - - // when emitting the stripped exe: - // - unused sections are removed - // when emitting the debug file: - // - all sections are kept, but some are emptied and their types is changed to SHT_NOBITS - // the program header is kept unchanged. (`strip` does update it, but `eu-strip` does not, and it still works) - - const Update = struct { - action: ElfFileHelper.Action, - - // remap the indexs after omitting the filtered sections - remap_idx: u16, - - // optionally overrides the payload from the source file - payload: ?[]align(section_memory_align.toByteUnits()) const u8 = null, - section: ?Elf_Shdr = null, - }; - const sections_update = try allocator.alloc(Update, self.sections.len); - const new_shnum = blk: { - var next_idx: u16 = 0; - for (self.sections, sections_update) |section, *update| { - const action = ElfFileHelper.selectAction(section.category, options.section_filter); - const remap_idx = idx: { - if (action == .strip) break :idx elf.SHN_UNDEF; - next_idx += 1; - break :idx next_idx - 1; - }; - update.* = Update{ .action = action, .remap_idx = remap_idx }; - } - - if (options.debuglink != null) - next_idx += 1; - - if (options.add_section != null) { - next_idx += 1; - } - - break :blk next_idx; - }; - - // add a ".gnu_debuglink" to the string table if needed - const debuglink_name: u32 = blk: { - if (options.debuglink == null) break :blk elf.SHN_UNDEF; - if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF) - fatal("zig objcopy: no strtab, cannot add the debuglink section", .{}); // TODO add the section if needed? - - const strtab = &self.sections[self.raw_elf_header.e_shstrndx]; - const update = §ions_update[self.raw_elf_header.e_shstrndx]; - - const name: []const u8 = ".gnu_debuglink"; - const new_offset: u32 = @intCast(strtab.payload.?.len); - const buf = try allocator.alignedAlloc(u8, section_memory_align, new_offset + name.len + 1); - @memcpy(buf[0..new_offset], strtab.payload.?); - @memcpy(buf[new_offset..][0..name.len], name); - buf[new_offset + name.len] = 0; - - assert(update.action == .keep); - update.payload = buf; - - break :blk new_offset; - }; - - // add user section to the string table if needed - const user_section_name: u32 = blk: { - if (options.add_section == null) break :blk elf.SHN_UNDEF; - if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF) - fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed? - - const strtab = &self.sections[self.raw_elf_header.e_shstrndx]; - const update = §ions_update[self.raw_elf_header.e_shstrndx]; - - const name = options.add_section.?.section_name; - const new_offset: u32 = @intCast(strtab.payload.?.len); - const buf = try allocator.alignedAlloc(u8, section_memory_align, new_offset + name.len + 1); - @memcpy(buf[0..new_offset], strtab.payload.?); - @memcpy(buf[new_offset..][0..name.len], name); - buf[new_offset + name.len] = 0; - - assert(update.action == .keep); - update.payload = buf; - - break :blk new_offset; - }; - - // maybe compress .debug sections - if (options.compress_debug) { - for (self.sections[1..], sections_update[1..]) |section, *update| { - if (update.action != .keep) continue; - if (!std.mem.startsWith(u8, section.name, ".debug_")) continue; - if ((section.section.sh_flags & elf.SHF_COMPRESSED) != 0) continue; // already compressed - - const chdr = Elf_Chdr{ - .ch_type = elf.COMPRESS.ZLIB, - .ch_size = section.section.sh_size, - .ch_addralign = section.section.sh_addralign, - }; - - const compressed_payload = try ElfFileHelper.tryCompressSection(allocator, in_file, section.section.sh_offset, section.section.sh_size, std.mem.asBytes(&chdr)); - if (compressed_payload) |payload| { - update.payload = payload; - update.section = section.section; - update.section.?.sh_addralign = @alignOf(Elf_Chdr); - update.section.?.sh_size = @intCast(payload.len); - update.section.?.sh_flags |= elf.SHF_COMPRESSED; - } - } - } - - var cmdbuf = std.ArrayList(ElfFileHelper.WriteCmd).init(allocator); - defer cmdbuf.deinit(); - try cmdbuf.ensureUnusedCapacity(3 + new_shnum); - var eof_offset: Elf_OffSize = 0; // track the end of the data written so far. - - // build the updated headers - // nb: updated_elf_header will be updated before the actual write - var updated_elf_header = self.raw_elf_header; - if (updated_elf_header.e_shstrndx != elf.SHN_UNDEF) - updated_elf_header.e_shstrndx = sections_update[updated_elf_header.e_shstrndx].remap_idx; - cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = std.mem.asBytes(&updated_elf_header), .out_offset = 0 } }); - eof_offset = @sizeOf(Elf_Ehdr); - - // program header as-is. - // nb: for only-debug files, removing it appears to work, but is invalid by ELF specifcation. - { - assert(updated_elf_header.e_phoff == @sizeOf(Elf_Ehdr)); - const data = std.mem.sliceAsBytes(self.program_segments); - assert(data.len == @as(usize, updated_elf_header.e_phentsize) * updated_elf_header.e_phnum); - cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = data, .out_offset = updated_elf_header.e_phoff } }); - eof_offset = updated_elf_header.e_phoff + @as(Elf_OffSize, @intCast(data.len)); - } - - // update sections and queue payload writes - const updated_section_header = blk: { - const dest_sections = try allocator.alloc(Elf_Shdr, new_shnum); - - { - // the ELF format doesn't specify the order for all sections. - // this code only supports when they are in increasing file order. - var offset: u64 = eof_offset; - for (self.sections[1..]) |section| { - if (section.section.sh_type == elf.SHT_NOBITS) - continue; - if (section.section.sh_offset < offset) { - fatal("zig objcopy: unsupported ELF file", .{}); - } - offset = section.section.sh_offset; - } - } - - dest_sections[0] = self.sections[0].section; - - var dest_section_idx: u32 = 1; - for (self.sections[1..], sections_update[1..]) |section, update| { - if (update.action == .strip) continue; - assert(update.remap_idx == dest_section_idx); - - const src = if (update.section) |*s| s else §ion.section; - const dest = &dest_sections[dest_section_idx]; - const payload = if (update.payload) |data| data else section.payload; - dest_section_idx += 1; - - dest.* = src.*; - - if (src.sh_link != elf.SHN_UNDEF) - dest.sh_link = sections_update[src.sh_link].remap_idx; - if ((src.sh_flags & elf.SHF_INFO_LINK) != 0 and src.sh_info != elf.SHN_UNDEF) - dest.sh_info = sections_update[src.sh_info].remap_idx; - - if (payload) |data| - dest.sh_size = @intCast(data.len); - - const addralign = if (src.sh_addralign == 0 or dest.sh_type == elf.SHT_NOBITS) 1 else src.sh_addralign; - dest.sh_offset = std.mem.alignForward(Elf_OffSize, eof_offset, addralign); - if (src.sh_offset != dest.sh_offset and section.segment != null and update.action != .empty and dest.sh_type != elf.SHT_NOTE and dest.sh_type != elf.SHT_NOBITS) { - if (src.sh_offset > dest.sh_offset) { - dest.sh_offset = src.sh_offset; // add padding to avoid modifing the program segments - } else { - fatal("zig objcopy: cannot adjust program segments", .{}); - } - } - assert(dest.sh_addr % addralign == dest.sh_offset % addralign); - - if (update.action == .empty) - dest.sh_type = elf.SHT_NOBITS; - - if (dest.sh_type != elf.SHT_NOBITS) { - if (payload) |src_data| { - // update sections payload and write - const dest_data = switch (src.sh_type) { - elf.DT_VERSYM => dst_data: { - const data = try allocator.alignedAlloc(u8, section_memory_align, src_data.len); - @memcpy(data, src_data); - - const defs = @as([*]elf.Verdef, @ptrCast(data))[0 .. @as(usize, @intCast(src.sh_size)) / @sizeOf(elf.Verdef)]; - for (defs) |*def| switch (def.ndx) { - .LOCAL, .GLOBAL => {}, - else => def.ndx = @enumFromInt(sections_update[src.sh_info].remap_idx), - }; - - break :dst_data data; - }, - elf.SHT_SYMTAB, elf.SHT_DYNSYM => dst_data: { - const data = try allocator.alignedAlloc(u8, section_memory_align, src_data.len); - @memcpy(data, src_data); - - const syms = @as([*]Elf_Sym, @ptrCast(data))[0 .. @as(usize, @intCast(src.sh_size)) / @sizeOf(Elf_Sym)]; - for (syms) |*sym| { - if (sym.st_shndx != elf.SHN_UNDEF and sym.st_shndx < elf.SHN_LORESERVE) - sym.st_shndx = sections_update[sym.st_shndx].remap_idx; - } - - break :dst_data data; - }, - else => src_data, - }; - - assert(dest_data.len == dest.sh_size); - cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = dest_data, .out_offset = dest.sh_offset } }); - eof_offset = dest.sh_offset + dest.sh_size; - } else { - // direct contents copy - cmdbuf.appendAssumeCapacity(.{ .copy_range = .{ .in_offset = src.sh_offset, .len = dest.sh_size, .out_offset = dest.sh_offset } }); - eof_offset = dest.sh_offset + dest.sh_size; - } - } else { - // account for alignment padding even in empty sections to keep logical section order - eof_offset = dest.sh_offset; - } - } - - // add a ".gnu_debuglink" section - if (options.debuglink) |link| { - const payload = payload: { - const crc_offset = std.mem.alignForward(usize, link.name.len + 1, 4); - const buf = try allocator.alignedAlloc(u8, .@"4", crc_offset + 4); - @memcpy(buf[0..link.name.len], link.name); - @memset(buf[link.name.len..crc_offset], 0); - @memcpy(buf[crc_offset..], std.mem.asBytes(&link.crc32)); - break :payload buf; - }; - - dest_sections[dest_section_idx] = Elf_Shdr{ - .sh_name = debuglink_name, - .sh_type = elf.SHT_PROGBITS, - .sh_flags = 0, - .sh_addr = 0, - .sh_offset = eof_offset, - .sh_size = @intCast(payload.len), - .sh_link = elf.SHN_UNDEF, - .sh_info = elf.SHN_UNDEF, - .sh_addralign = 4, - .sh_entsize = 0, - }; - dest_section_idx += 1; - - cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = payload, .out_offset = eof_offset } }); - eof_offset += @as(Elf_OffSize, @intCast(payload.len)); - } - - // --add-section - if (options.add_section) |add_section| { - var section_file = fs.cwd().openFile(add_section.file_path, .{}) catch |err| - fatal("unable to open '{s}': {s}", .{ add_section.file_path, @errorName(err) }); - defer section_file.close(); - - const payload = try section_file.readToEndAlloc(arena.allocator(), std.math.maxInt(usize)); - - dest_sections[dest_section_idx] = Elf_Shdr{ - .sh_name = user_section_name, - .sh_type = elf.SHT_PROGBITS, - .sh_flags = 0, - .sh_addr = 0, - .sh_offset = eof_offset, - .sh_size = @intCast(payload.len), - .sh_link = elf.SHN_UNDEF, - .sh_info = elf.SHN_UNDEF, - .sh_addralign = 4, - .sh_entsize = 0, - }; - dest_section_idx += 1; - - cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = payload, .out_offset = eof_offset } }); - eof_offset += @as(Elf_OffSize, @intCast(payload.len)); - } - - assert(dest_section_idx == new_shnum); - break :blk dest_sections; - }; - - // --set-section-alignment: overwrite alignment - if (options.set_section_alignment) |set_align| { - if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF) - fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed? - - const strtab = §ions_update[self.raw_elf_header.e_shstrndx]; - for (updated_section_header) |*section| { - const section_name = std.mem.span(@as([*:0]const u8, @ptrCast(&strtab.payload.?[section.sh_name]))); - if (std.mem.eql(u8, section_name, set_align.section_name)) { - section.sh_addralign = set_align.alignment; - break; - } - } else std.log.warn("Skipping --set-section-alignment. Section '{s}' not found", .{set_align.section_name}); - } - - // --set-section-flags: overwrite flags - if (options.set_section_flags) |set_flags| { - if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF) - fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed? - - const strtab = §ions_update[self.raw_elf_header.e_shstrndx]; - for (updated_section_header) |*section| { - const section_name = std.mem.span(@as([*:0]const u8, @ptrCast(&strtab.payload.?[section.sh_name]))); - if (std.mem.eql(u8, section_name, set_flags.section_name)) { - section.sh_flags = std.elf.SHF_WRITE; // default is writable cleared by "readonly" - const f = set_flags.flags; - - // Supporting a subset of GNU and LLVM objcopy for ELF only - // GNU: - // alloc: add SHF_ALLOC - // contents: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing - // load: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing (same as contents) - // noload: not ELF relevant - // readonly: clear default SHF_WRITE flag - // code: add SHF_EXECINSTR - // data: not ELF relevant - // rom: ignored - // exclude: add SHF_EXCLUDE - // share: not ELF relevant - // debug: not ELF relevant - // large: add SHF_X86_64_LARGE. Fatal error if target is not x86_64 - if (f.alloc) section.sh_flags |= std.elf.SHF_ALLOC; - if (f.contents or f.load) { - if (section.sh_type == std.elf.SHT_NOBITS) section.sh_type = std.elf.SHT_PROGBITS; - } - if (f.readonly) section.sh_flags &= ~@as(@TypeOf(section.sh_type), std.elf.SHF_WRITE); - if (f.code) section.sh_flags |= std.elf.SHF_EXECINSTR; - if (f.exclude) section.sh_flags |= std.elf.SHF_EXCLUDE; - if (f.large) { - if (updated_elf_header.e_machine != std.elf.EM.X86_64) - fatal("zig objcopy: 'large' section flag is only supported on x86_64 targets", .{}); - section.sh_flags |= std.elf.SHF_X86_64_LARGE; - } - - // LLVM: - // merge: add SHF_MERGE - // strings: add SHF_STRINGS - if (f.merge) section.sh_flags |= std.elf.SHF_MERGE; - if (f.strings) section.sh_flags |= std.elf.SHF_STRINGS; - break; - } - } else std.log.warn("Skipping --set-section-flags. Section '{s}' not found", .{set_flags.section_name}); - } - - // write the section header at the tail - { - const offset = std.mem.alignForward(Elf_OffSize, eof_offset, @alignOf(Elf_Shdr)); - - const data = std.mem.sliceAsBytes(updated_section_header); - assert(data.len == @as(usize, updated_elf_header.e_shentsize) * new_shnum); - updated_elf_header.e_shoff = offset; - updated_elf_header.e_shnum = new_shnum; - - cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = data, .out_offset = updated_elf_header.e_shoff } }); - } - - try ElfFileHelper.write(allocator, out_file, in_file, cmdbuf.items); - } - - fn sectionWithinSegment(section: Elf_Shdr, segment: Elf_Phdr) bool { - const file_size = if (section.sh_type == elf.SHT_NOBITS) 0 else section.sh_size; - return segment.p_offset <= section.sh_offset and (segment.p_offset + segment.p_filesz) >= (section.sh_offset + file_size); - } - }; -} - -const ElfFileHelper = struct { - const DebugLink = struct { name: []const u8, crc32: u32 }; - const Filter = enum { all, program, debug, program_and_symbols, debug_and_symbols }; - - const SectionCategory = enum { common, exe, debug, symbols, none }; - fn propagateCategory(cur: *SectionCategory, new: SectionCategory) u1 { - const cat: SectionCategory = switch (cur.*) { - .none => new, - .common => .common, - .debug => switch (new) { - .none, .debug => .debug, - else => new, - }, - .exe => switch (new) { - .common => .common, - .none, .debug, .exe => .exe, - .symbols => .exe, - }, - .symbols => switch (new) { - .none, .common, .debug, .exe => unreachable, - .symbols => .symbols, - }, - }; - - if (cur.* != cat) { - cur.* = cat; - return 1; - } else { - return 0; - } - } - - const Action = enum { keep, strip, empty }; - fn selectAction(category: SectionCategory, filter: Filter) Action { - if (category == .none) return .strip; - return switch (filter) { - .all => switch (category) { - .none => .strip, - else => .keep, - }, - .program => switch (category) { - .common, .exe => .keep, - else => .strip, - }, - .program_and_symbols => switch (category) { - .common, .exe, .symbols => .keep, - else => .strip, - }, - .debug => switch (category) { - .exe, .symbols => .empty, - .none => .strip, - else => .keep, - }, - .debug_and_symbols => switch (category) { - .exe => .empty, - .none => .strip, - else => .keep, - }, - }; - } - - const WriteCmd = union(enum) { - copy_range: struct { in_offset: u64, len: u64, out_offset: u64 }, - write_data: struct { data: []const u8, out_offset: u64 }, - }; - fn write(allocator: Allocator, out_file: File, in_file: File, cmds: []const WriteCmd) !void { - // consolidate holes between writes: - // by coping original padding data from in_file (by fusing contiguous ranges) - // by writing zeroes otherwise - const zeroes = [1]u8{0} ** 4096; - var consolidated = std.ArrayList(WriteCmd).init(allocator); - defer consolidated.deinit(); - try consolidated.ensureUnusedCapacity(cmds.len * 2); - var offset: u64 = 0; - var fused_cmd: ?WriteCmd = null; - for (cmds) |cmd| { - switch (cmd) { - .write_data => |data| { - assert(data.out_offset >= offset); - if (fused_cmd) |prev| { - consolidated.appendAssumeCapacity(prev); - fused_cmd = null; - } - if (data.out_offset > offset) { - consolidated.appendAssumeCapacity(.{ .write_data = .{ .data = zeroes[0..@intCast(data.out_offset - offset)], .out_offset = offset } }); - } - consolidated.appendAssumeCapacity(cmd); - offset = data.out_offset + data.data.len; - }, - .copy_range => |range| { - assert(range.out_offset >= offset); - if (fused_cmd) |prev| { - if (range.in_offset >= prev.copy_range.in_offset + prev.copy_range.len and (range.out_offset - prev.copy_range.out_offset == range.in_offset - prev.copy_range.in_offset)) { - fused_cmd = .{ .copy_range = .{ - .in_offset = prev.copy_range.in_offset, - .out_offset = prev.copy_range.out_offset, - .len = (range.out_offset + range.len) - prev.copy_range.out_offset, - } }; - } else { - consolidated.appendAssumeCapacity(prev); - if (range.out_offset > offset) { - consolidated.appendAssumeCapacity(.{ .write_data = .{ .data = zeroes[0..@intCast(range.out_offset - offset)], .out_offset = offset } }); - } - fused_cmd = cmd; - } - } else { - fused_cmd = cmd; - } - offset = range.out_offset + range.len; - }, - } - } - if (fused_cmd) |cmd| { - consolidated.appendAssumeCapacity(cmd); - } - - // write the output file - for (consolidated.items) |cmd| { - switch (cmd) { - .write_data => |data| { - var iovec = [_]std.posix.iovec_const{.{ .base = data.data.ptr, .len = data.data.len }}; - try out_file.pwritevAll(&iovec, data.out_offset); - }, - .copy_range => |range| { - const copied_bytes = try in_file.copyRangeAll(range.in_offset, out_file, range.out_offset, range.len); - if (copied_bytes < range.len) return error.TRUNCATED_ELF; - }, - } - } - } - - fn tryCompressSection(allocator: Allocator, in_file: File, offset: u64, size: u64, prefix: []const u8) !?[]align(8) const u8 { - if (size < prefix.len) return null; - - try in_file.seekTo(offset); - var section_reader = std.io.limitedReader(in_file.deprecatedReader(), size); - - // allocate as large as decompressed data. if the compression doesn't fit, keep the data uncompressed. - const compressed_data = try allocator.alignedAlloc(u8, .@"8", @intCast(size)); - var compressed_stream = std.io.fixedBufferStream(compressed_data); - - try compressed_stream.writer().writeAll(prefix); - - { - var compressor = try std.compress.zlib.compressor(compressed_stream.writer(), .{}); - - var buf: [8000]u8 = undefined; - while (true) { - const bytes_read = try section_reader.read(&buf); - if (bytes_read == 0) break; - const bytes_written = compressor.write(buf[0..bytes_read]) catch |err| switch (err) { - error.NoSpaceLeft => { - allocator.free(compressed_data); - return null; - }, - else => return err, - }; - std.debug.assert(bytes_written == bytes_read); - } - compressor.finish() catch |err| switch (err) { - error.NoSpaceLeft => { - allocator.free(compressed_data); - return null; - }, - else => return err, - }; - } - - const compressed_len: usize = @intCast(compressed_stream.getPos() catch unreachable); - const data = allocator.realloc(compressed_data, compressed_len) catch compressed_data; - return data[0..compressed_len]; - } - - fn createDebugLink(path: []const u8) DebugLink { - const file = std.fs.cwd().openFile(path, .{}) catch |err| { - fatal("zig objcopy: could not open `{s}`: {s}\n", .{ path, @errorName(err) }); - }; - defer file.close(); - - const crc = ElfFileHelper.computeFileCrc(file) catch |err| { - fatal("zig objcopy: could not read `{s}`: {s}\n", .{ path, @errorName(err) }); - }; - return .{ - .name = std.fs.path.basename(path), - .crc32 = crc, - }; - } - - fn computeFileCrc(file: File) !u32 { - var buf: [8000]u8 = undefined; - - try file.seekTo(0); - var hasher = std.hash.Crc32.init(); - while (true) { - const bytes_read = try file.read(&buf); - if (bytes_read == 0) break; - hasher.update(buf[0..bytes_read]); - } - return hasher.final(); - } -}; - const SectionFlags = packed struct { alloc: bool = false, contents: bool = false, diff --git a/lib/std/elf.zig b/lib/std/elf.zig index 4e15cd3a09..47b3add84f 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -482,6 +482,7 @@ pub const Header = struct { is_64: bool, endian: std.builtin.Endian, os_abi: OSABI, + /// The meaning of this value depends on `os_abi`. abi_version: u8, type: ET, machine: EM, @@ -494,205 +495,135 @@ pub const Header = struct { shnum: u16, shstrndx: u16, - pub fn program_header_iterator(self: Header, parse_source: anytype) ProgramHeaderIterator(@TypeOf(parse_source)) { - return ProgramHeaderIterator(@TypeOf(parse_source)){ - .elf_header = self, - .parse_source = parse_source, + pub fn iterateProgramHeaders(h: Header, file_reader: *std.fs.File.Reader) ProgramHeaderIterator { + return .{ + .elf_header = h, + .file_reader = file_reader, }; } - pub fn section_header_iterator(self: Header, parse_source: anytype) SectionHeaderIterator(@TypeOf(parse_source)) { - return SectionHeaderIterator(@TypeOf(parse_source)){ - .elf_header = self, - .parse_source = parse_source, + pub fn iterateSectionHeaders(h: Header, file_reader: *std.fs.File.Reader) SectionHeaderIterator { + return .{ + .elf_header = h, + .file_reader = file_reader, }; } - pub fn read(parse_source: anytype) !Header { - var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined; - try parse_source.seekableStream().seekTo(0); - try parse_source.deprecatedReader().readNoEof(&hdr_buf); - return Header.parse(&hdr_buf); - } + pub const ReadError = std.Io.Reader.Error || error{ + InvalidElfMagic, + InvalidElfVersion, + InvalidElfClass, + InvalidElfEndian, + }; - pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header { - const hdr32 = @as(*const Elf32_Ehdr, @ptrCast(hdr_buf)); - const hdr64 = @as(*const Elf64_Ehdr, @ptrCast(hdr_buf)); - if (!mem.eql(u8, hdr32.e_ident[0..4], MAGIC)) return error.InvalidElfMagic; - if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion; + pub fn read(r: *std.Io.Reader) ReadError!Header { + const buf = try r.peek(@sizeOf(Elf64_Ehdr)); - const is_64 = switch (hdr32.e_ident[EI_CLASS]) { - ELFCLASS32 => false, - ELFCLASS64 => true, - else => return error.InvalidElfClass, - }; + if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic; + if (buf[EI_VERSION] != 1) return error.InvalidElfVersion; - const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) { + const endian: std.builtin.Endian = switch (buf[EI_DATA]) { ELFDATA2LSB => .little, ELFDATA2MSB => .big, else => return error.InvalidElfEndian, }; - const need_bswap = endian != native_endian; + return switch (buf[EI_CLASS]) { + ELFCLASS32 => .init(try r.takeStruct(Elf32_Ehdr, endian), endian), + ELFCLASS64 => .init(try r.takeStruct(Elf64_Ehdr, endian), endian), + else => return error.InvalidElfClass, + }; + } + + pub fn init(hdr: anytype, endian: std.builtin.Endian) Header { // Converting integers to exhaustive enums using `@enumFromInt` could cause a panic. comptime assert(!@typeInfo(OSABI).@"enum".is_exhaustive); - const os_abi: OSABI = @enumFromInt(hdr32.e_ident[EI_OSABI]); - - // The meaning of this value depends on `os_abi` so just make it available as `u8`. - const abi_version = hdr32.e_ident[EI_ABIVERSION]; - - const @"type" = if (need_bswap) blk: { - comptime assert(!@typeInfo(ET).@"enum".is_exhaustive); - const value = @intFromEnum(hdr32.e_type); - break :blk @as(ET, @enumFromInt(@byteSwap(value))); - } else hdr32.e_type; - - const machine = if (need_bswap) blk: { - comptime assert(!@typeInfo(EM).@"enum".is_exhaustive); - const value = @intFromEnum(hdr32.e_machine); - break :blk @as(EM, @enumFromInt(@byteSwap(value))); - } else hdr32.e_machine; - - return @as(Header, .{ - .is_64 = is_64, + return .{ + .is_64 = switch (@TypeOf(hdr)) { + Elf32_Ehdr => false, + Elf64_Ehdr => true, + else => @compileError("bad type"), + }, .endian = endian, - .os_abi = os_abi, - .abi_version = abi_version, - .type = @"type", - .machine = machine, - .entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry), - .phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff), - .shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff), - .phentsize = int(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize), - .phnum = int(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum), - .shentsize = int(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize), - .shnum = int(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum), - .shstrndx = int(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx), - }); + .os_abi = @enumFromInt(hdr.e_ident[EI_OSABI]), + .abi_version = hdr.e_ident[EI_ABIVERSION], + .type = hdr.e_type, + .machine = hdr.e_machine, + .entry = hdr.e_entry, + .phoff = hdr.e_phoff, + .shoff = hdr.e_shoff, + .phentsize = hdr.e_phentsize, + .phnum = hdr.e_phnum, + .shentsize = hdr.e_shentsize, + .shnum = hdr.e_shnum, + .shstrndx = hdr.e_shstrndx, + }; } }; -pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type { - return struct { - elf_header: Header, - parse_source: ParseSource, - index: usize = 0, +pub const ProgramHeaderIterator = struct { + elf_header: Header, + file_reader: *std.fs.File.Reader, + index: usize = 0, - pub fn next(self: *@This()) !?Elf64_Phdr { - if (self.index >= self.elf_header.phnum) return null; - defer self.index += 1; + pub fn next(it: *ProgramHeaderIterator) !?Elf64_Phdr { + if (it.index >= it.elf_header.phnum) return null; + defer it.index += 1; - if (self.elf_header.is_64) { - var phdr: Elf64_Phdr = undefined; - const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index; - try self.parse_source.seekableStream().seekTo(offset); - try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&phdr)); - - // ELF endianness matches native endianness. - if (self.elf_header.endian == native_endian) return phdr; - - // Convert fields to native endianness. - mem.byteSwapAllFields(Elf64_Phdr, &phdr); - return phdr; - } - - var phdr: Elf32_Phdr = undefined; - const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index; - try self.parse_source.seekableStream().seekTo(offset); - try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&phdr)); - - // ELF endianness does NOT match native endianness. - if (self.elf_header.endian != native_endian) { - // Convert fields to native endianness. - mem.byteSwapAllFields(Elf32_Phdr, &phdr); - } - - // Convert 32-bit header to 64-bit. - return Elf64_Phdr{ - .p_type = phdr.p_type, - .p_offset = phdr.p_offset, - .p_vaddr = phdr.p_vaddr, - .p_paddr = phdr.p_paddr, - .p_filesz = phdr.p_filesz, - .p_memsz = phdr.p_memsz, - .p_flags = phdr.p_flags, - .p_align = phdr.p_align, - }; + if (it.elf_header.is_64) { + const offset = it.elf_header.phoff + @sizeOf(Elf64_Phdr) * it.index; + try it.file_reader.seekTo(offset); + const phdr = try it.file_reader.interface.takeStruct(Elf64_Phdr, it.elf_header.endian); + return phdr; } - }; -} -pub fn SectionHeaderIterator(comptime ParseSource: anytype) type { - return struct { - elf_header: Header, - parse_source: ParseSource, - index: usize = 0, - - pub fn next(self: *@This()) !?Elf64_Shdr { - if (self.index >= self.elf_header.shnum) return null; - defer self.index += 1; - - if (self.elf_header.is_64) { - var shdr: Elf64_Shdr = undefined; - const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index; - try self.parse_source.seekableStream().seekTo(offset); - try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&shdr)); - - // ELF endianness matches native endianness. - if (self.elf_header.endian == native_endian) return shdr; - - // Convert fields to native endianness. - mem.byteSwapAllFields(Elf64_Shdr, &shdr); - return shdr; - } - - var shdr: Elf32_Shdr = undefined; - const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index; - try self.parse_source.seekableStream().seekTo(offset); - try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&shdr)); - - // ELF endianness does NOT match native endianness. - if (self.elf_header.endian != native_endian) { - // Convert fields to native endianness. - mem.byteSwapAllFields(Elf32_Shdr, &shdr); - } - - // Convert 32-bit header to 64-bit. - return Elf64_Shdr{ - .sh_name = shdr.sh_name, - .sh_type = shdr.sh_type, - .sh_flags = shdr.sh_flags, - .sh_addr = shdr.sh_addr, - .sh_offset = shdr.sh_offset, - .sh_size = shdr.sh_size, - .sh_link = shdr.sh_link, - .sh_info = shdr.sh_info, - .sh_addralign = shdr.sh_addralign, - .sh_entsize = shdr.sh_entsize, - }; - } - }; -} - -fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) { - if (is_64) { - if (need_bswap) { - return @byteSwap(int_64); - } else { - return int_64; - } - } else { - return int32(need_bswap, int_32, @TypeOf(int_64)); + const offset = it.elf_header.phoff + @sizeOf(Elf32_Phdr) * it.index; + try it.file_reader.seekTo(offset); + const phdr = try it.file_reader.interface.takeStruct(Elf32_Phdr, it.elf_header.endian); + return .{ + .p_type = phdr.p_type, + .p_offset = phdr.p_offset, + .p_vaddr = phdr.p_vaddr, + .p_paddr = phdr.p_paddr, + .p_filesz = phdr.p_filesz, + .p_memsz = phdr.p_memsz, + .p_flags = phdr.p_flags, + .p_align = phdr.p_align, + }; } -} +}; -fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 { - if (need_bswap) { - return @byteSwap(int_32); - } else { - return int_32; +pub const SectionHeaderIterator = struct { + elf_header: Header, + file_reader: *std.fs.File.Reader, + index: usize = 0, + + pub fn next(it: *SectionHeaderIterator) !?Elf64_Shdr { + if (it.index >= it.elf_header.shnum) return null; + defer it.index += 1; + + if (it.elf_header.is_64) { + try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf64_Shdr) * it.index); + const shdr = try it.file_reader.interface.takeStruct(Elf64_Shdr, it.elf_header.endian); + return shdr; + } + + try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf32_Shdr) * it.index); + const shdr = try it.file_reader.interface.takeStruct(Elf32_Shdr, it.elf_header.endian); + return .{ + .sh_name = shdr.sh_name, + .sh_type = shdr.sh_type, + .sh_flags = shdr.sh_flags, + .sh_addr = shdr.sh_addr, + .sh_offset = shdr.sh_offset, + .sh_size = shdr.sh_size, + .sh_link = shdr.sh_link, + .sh_info = shdr.sh_info, + .sh_addralign = shdr.sh_addralign, + .sh_entsize = shdr.sh_entsize, + }; } -} +}; pub const ELFCLASSNONE = 0; pub const ELFCLASS32 = 1; diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 50f2a30876..85264dd4db 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1228,14 +1228,12 @@ pub const Reader = struct { pub fn seekBy(r: *Reader, offset: i64) Reader.SeekError!void { switch (r.mode) { .positional, .positional_reading => { - // TODO: make += operator allow any integer types - r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset); + setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset)); }, .streaming, .streaming_reading => { const seek_err = r.seek_err orelse e: { if (posix.lseek_CUR(r.file.handle, offset)) |_| { - // TODO: make += operator allow any integer types - r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset); + setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset)); return; } else |err| { r.seek_err = err; @@ -1251,6 +1249,8 @@ pub const Reader = struct { r.pos += n; remaining -= n; } + r.interface.seek = 0; + r.interface.end = 0; }, .failure => return r.seek_err.?, } @@ -1259,7 +1259,7 @@ pub const Reader = struct { pub fn seekTo(r: *Reader, offset: u64) Reader.SeekError!void { switch (r.mode) { .positional, .positional_reading => { - r.pos = offset; + setPosAdjustingBuffer(r, offset); }, .streaming, .streaming_reading => { if (offset >= r.pos) return Reader.seekBy(r, @intCast(offset - r.pos)); @@ -1268,12 +1268,22 @@ pub const Reader = struct { r.seek_err = err; return err; }; - r.pos = offset; + setPosAdjustingBuffer(r, offset); }, .failure => return r.seek_err.?, } } + fn setPosAdjustingBuffer(r: *Reader, offset: u64) void { + if (offset < r.pos or offset >= r.pos + r.interface.bufferedLen()) { + r.interface.seek = 0; + r.interface.end = 0; + } else { + r.interface.seek += @intCast(offset - r.pos); + } + r.pos = offset; + } + /// Number of slices to store on the stack, when trying to send as many byte /// vectors through the underlying read calls as possible. const max_buffers_len = 16; diff --git a/test/standalone/stack_iterator/build.zig b/test/standalone/stack_iterator/build.zig index a036a64ab7..878859312b 100644 --- a/test/standalone/stack_iterator/build.zig +++ b/test/standalone/stack_iterator/build.zig @@ -65,69 +65,70 @@ pub fn build(b: *std.Build) void { test_step.dependOn(&run_cmd.step); } - // Unwinding through a C shared library without a frame pointer (libc) - // - // getcontext version: libc - // - // Unwind info type: - // - ELF: DWARF .eh_frame + .debug_frame - // - MachO: __unwind_info encodings: - // - x86_64: STACK_IMMD, STACK_IND - // - aarch64: FRAMELESS, DWARF - { - const c_shared_lib = b.addLibrary(.{ - .linkage = .dynamic, - .name = "c_shared_lib", - .root_module = b.createModule(.{ - .root_source_file = null, - .target = target, - .optimize = optimize, - .link_libc = true, - .strip = false, - }), - }); + // https://github.com/ziglang/zig/issues/24522 + //// Unwinding through a C shared library without a frame pointer (libc) + //// + //// getcontext version: libc + //// + //// Unwind info type: + //// - ELF: DWARF .eh_frame + .debug_frame + //// - MachO: __unwind_info encodings: + //// - x86_64: STACK_IMMD, STACK_IND + //// - aarch64: FRAMELESS, DWARF + //{ + // const c_shared_lib = b.addLibrary(.{ + // .linkage = .dynamic, + // .name = "c_shared_lib", + // .root_module = b.createModule(.{ + // .root_source_file = null, + // .target = target, + // .optimize = optimize, + // .link_libc = true, + // .strip = false, + // }), + // }); - if (target.result.os.tag == .windows) - c_shared_lib.root_module.addCMacro("LIB_API", "__declspec(dllexport)"); + // if (target.result.os.tag == .windows) + // c_shared_lib.root_module.addCMacro("LIB_API", "__declspec(dllexport)"); - c_shared_lib.root_module.addCSourceFile(.{ - .file = b.path("shared_lib.c"), - .flags = &.{"-fomit-frame-pointer"}, - }); + // c_shared_lib.root_module.addCSourceFile(.{ + // .file = b.path("shared_lib.c"), + // .flags = &.{"-fomit-frame-pointer"}, + // }); - const exe = b.addExecutable(.{ - .name = "shared_lib_unwind", - .root_module = b.createModule(.{ - .root_source_file = b.path("shared_lib_unwind.zig"), - .target = target, - .optimize = optimize, - .unwind_tables = if (target.result.os.tag.isDarwin()) .async else null, - .omit_frame_pointer = true, - }), - // zig objcopy doesn't support incremental binaries - .use_llvm = true, - }); + // const exe = b.addExecutable(.{ + // .name = "shared_lib_unwind", + // .root_module = b.createModule(.{ + // .root_source_file = b.path("shared_lib_unwind.zig"), + // .target = target, + // .optimize = optimize, + // .unwind_tables = if (target.result.os.tag.isDarwin()) .async else null, + // .omit_frame_pointer = true, + // }), + // // zig objcopy doesn't support incremental binaries + // .use_llvm = true, + // }); - exe.linkLibrary(c_shared_lib); + // exe.linkLibrary(c_shared_lib); - const run_cmd = b.addRunArtifact(exe); - test_step.dependOn(&run_cmd.step); + // const run_cmd = b.addRunArtifact(exe); + // test_step.dependOn(&run_cmd.step); - // Separate debug info ELF file - if (target.result.ofmt == .elf) { - const filename = b.fmt("{s}_stripped", .{exe.out_filename}); - const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{ - .basename = filename, // set the name for the debuglink - .compress_debug = true, - .strip = .debug, - .extract_to_separate_file = true, - }); + // // Separate debug info ELF file + // if (target.result.ofmt == .elf) { + // const filename = b.fmt("{s}_stripped", .{exe.out_filename}); + // const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{ + // .basename = filename, // set the name for the debuglink + // .compress_debug = true, + // .strip = .debug, + // .extract_to_separate_file = true, + // }); - const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename})); - run_stripped.addFileArg(stripped_exe.getOutput()); - test_step.dependOn(&run_stripped.step); - } - } + // const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename})); + // run_stripped.addFileArg(stripped_exe.getOutput()); + // test_step.dependOn(&run_stripped.step); + // } + //} // Unwinding without libc/posix // diff --git a/tools/gen_stubs.zig b/tools/gen_stubs.zig index ed60d7e67d..9fdd63eda1 100644 --- a/tools/gen_stubs.zig +++ b/tools/gen_stubs.zig @@ -310,7 +310,8 @@ pub fn main() !void { build_all_path, libc_so_path, @errorName(err), }); }; - const header = try elf.Header.parse(elf_bytes[0..@sizeOf(elf.Elf64_Ehdr)]); + var stream: std.Io.Reader = .fixed(elf_bytes); + const header = try elf.Header.read(&stream); const parse: Parse = .{ .arena = arena, From 38559e282b137ea365ab074e3d78cf3312dd5702 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 20:36:26 -0700 Subject: [PATCH 13/76] disable failing test tracked by #24524 --- test/incremental/fix_many_errors | 71 -------------------------------- 1 file changed, 71 deletions(-) delete mode 100644 test/incremental/fix_many_errors diff --git a/test/incremental/fix_many_errors b/test/incremental/fix_many_errors deleted file mode 100644 index 1d9446022c..0000000000 --- a/test/incremental/fix_many_errors +++ /dev/null @@ -1,71 +0,0 @@ -#target=x86_64-linux-selfhosted -#target=x86_64-linux-cbe -#target=x86_64-windows-cbe -#update=initial version -#file=main.zig -pub fn main() !void {} -comptime { @compileError("c0"); } -comptime { @compileError("c1"); } -comptime { @compileError("c2"); } -comptime { @compileError("c3"); } -comptime { @compileError("c4"); } -comptime { @compileError("c5"); } -comptime { @compileError("c6"); } -comptime { @compileError("c7"); } -comptime { @compileError("c8"); } -comptime { @compileError("c9"); } -export fn f0() void { @compileError("f0"); } -export fn f1() void { @compileError("f1"); } -export fn f2() void { @compileError("f2"); } -export fn f3() void { @compileError("f3"); } -export fn f4() void { @compileError("f4"); } -export fn f5() void { @compileError("f5"); } -export fn f6() void { @compileError("f6"); } -export fn f7() void { @compileError("f7"); } -export fn f8() void { @compileError("f8"); } -export fn f9() void { @compileError("f9"); } -#expect_error=main.zig:2:12: error: c0 -#expect_error=main.zig:3:12: error: c1 -#expect_error=main.zig:4:12: error: c2 -#expect_error=main.zig:5:12: error: c3 -#expect_error=main.zig:6:12: error: c4 -#expect_error=main.zig:7:12: error: c5 -#expect_error=main.zig:8:12: error: c6 -#expect_error=main.zig:9:12: error: c7 -#expect_error=main.zig:10:12: error: c8 -#expect_error=main.zig:11:12: error: c9 -#expect_error=main.zig:12:23: error: f0 -#expect_error=main.zig:13:23: error: f1 -#expect_error=main.zig:14:23: error: f2 -#expect_error=main.zig:15:23: error: f3 -#expect_error=main.zig:16:23: error: f4 -#expect_error=main.zig:17:23: error: f5 -#expect_error=main.zig:18:23: error: f6 -#expect_error=main.zig:19:23: error: f7 -#expect_error=main.zig:20:23: error: f8 -#expect_error=main.zig:21:23: error: f9 -#update=fix all the errors -#file=main.zig -pub fn main() !void {} -comptime {} -comptime {} -comptime {} -comptime {} -comptime {} -comptime {} -comptime {} -comptime {} -comptime {} -comptime {} -export fn f0() void {} -export fn f1() void {} -export fn f2() void {} -export fn f3() void {} -export fn f4() void {} -export fn f5() void {} -export fn f6() void {} -export fn f7() void {} -export fn f8() void {} -export fn f9() void {} -const std = @import("std"); -#expect_stdout="" From fe10c66d664ae7b1acb2bcf01600eeacc2958fc7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 20:46:07 -0700 Subject: [PATCH 14/76] std.fs.File.Reader: only fcopyfile if size available --- lib/std/fs/File.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 85264dd4db..04b2f1dd94 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1825,6 +1825,7 @@ pub const Writer = struct { if (file_reader.pos != 0) break :fcf; if (w.pos != 0) break :fcf; if (limit != .unlimited) break :fcf; + const size = file_reader.getSize() catch break :fcf; const rc = std.c.fcopyfile(in_fd, out_fd, null, .{ .DATA = true }); switch (posix.errno(rc)) { .SUCCESS => {}, @@ -1845,10 +1846,9 @@ pub const Writer = struct { return 0; }, } - const n = if (file_reader.size) |size| size else @panic("TODO figure out how much copied"); - file_reader.pos = n; - w.pos = n; - return n; + file_reader.pos = size; + w.pos = size; + return size; } return error.Unimplemented; From b35c55e2373ace674cd1eec7f5086b805d1c8256 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 21 Jul 2025 18:13:45 -0700 Subject: [PATCH 15/76] std.fs.File.Reader: fix seek position logic --- lib/std/fs/File.zig | 14 ++++++++++---- lib/std/fs/test.zig | 47 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 04b2f1dd94..a95bd1401a 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1135,7 +1135,7 @@ pub const Reader = struct { err: ?ReadError = null, mode: Reader.Mode = .positional, /// Tracks the true seek position in the file. To obtain the logical - /// position, subtract the buffer size from this value. + /// position, use `logicalPos`. pos: u64 = 0, size: ?u64 = null, size_err: ?GetEndPosError = null, @@ -1274,14 +1274,20 @@ pub const Reader = struct { } } + pub fn logicalPos(r: *const Reader) u64 { + return r.pos - r.interface.bufferedLen(); + } + fn setPosAdjustingBuffer(r: *Reader, offset: u64) void { - if (offset < r.pos or offset >= r.pos + r.interface.bufferedLen()) { + const logical_pos = logicalPos(r); + if (offset < logical_pos or offset >= r.pos) { r.interface.seek = 0; r.interface.end = 0; + r.pos = offset; } else { - r.interface.seek += @intCast(offset - r.pos); + const logical_delta: usize = @intCast(offset - logical_pos); + r.interface.seek += logical_delta; } - r.pos = offset; } /// Number of slices to store on the stack, when trying to send as many byte diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 9fe2551738..4b63873af5 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -2060,7 +2060,7 @@ test "invalid UTF-8/WTF-8 paths" { } test "read file non vectored" { - var tmp_dir = std.testing.tmpDir(.{}); + var tmp_dir = testing.tmpDir(.{}); defer tmp_dir.cleanup(); const contents = "hello, world!\n"; @@ -2085,6 +2085,47 @@ test "read file non vectored" { else => |e| return e, }; } - try std.testing.expectEqualStrings(contents, w.buffered()); - try std.testing.expectEqual(contents.len, i); + try testing.expectEqualStrings(contents, w.buffered()); + try testing.expectEqual(contents.len, i); +} + +test "seek keeping partial buffer" { + var tmp_dir = testing.tmpDir(.{}); + defer tmp_dir.cleanup(); + + const contents = "0123456789"; + + const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true }); + defer file.close(); + { + var file_writer: std.fs.File.Writer = .init(file, &.{}); + try file_writer.interface.writeAll(contents); + try file_writer.interface.flush(); + } + + var read_buffer: [3]u8 = undefined; + var file_reader: std.fs.File.Reader = .init(file, &read_buffer); + + try testing.expectEqual(0, file_reader.logicalPos()); + + var buf: [4]u8 = undefined; + try file_reader.interface.readSliceAll(&buf); + + if (file_reader.interface.bufferedLen() != 3) { + // Pass the test if the OS doesn't give us vectored reads. + return; + } + + try testing.expectEqual(4, file_reader.logicalPos()); + try testing.expectEqual(7, file_reader.pos); + try file_reader.seekTo(6); + try testing.expectEqual(6, file_reader.logicalPos()); + try testing.expectEqual(7, file_reader.pos); + + try testing.expectEqualStrings("0123", &buf); + + const n = try file_reader.interface.readSliceShort(&buf); + try testing.expectEqual(4, n); + + try testing.expectEqualStrings("6789", &buf); } From 96cbdd145d6ec5bf2e3ed80743c99ab4b2cdff68 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 21 Jul 2025 20:00:45 -0700 Subject: [PATCH 16/76] std.fs.File.Reader: fix sendFile logic it wasn't accounting for both writer and reader buffering --- lib/std/c.zig | 4 +- lib/std/fs/File.zig | 134 ++++++++++++++++++-- lib/std/posix.zig | 289 -------------------------------------------- 3 files changed, 128 insertions(+), 299 deletions(-) diff --git a/lib/std/c.zig b/lib/std/c.zig index 2880e3850a..74bc76d67f 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -10497,9 +10497,9 @@ pub const sysconf = switch (native_os) { pub const sf_hdtr = switch (native_os) { .freebsd, .macos, .ios, .tvos, .watchos, .visionos => extern struct { - headers: [*]const iovec_const, + headers: ?[*]const iovec_const, hdr_cnt: c_int, - trailers: [*]const iovec_const, + trailers: ?[*]const iovec_const, trl_cnt: c_int, }, else => void, diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index a95bd1401a..2091b27f60 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1435,7 +1435,7 @@ pub const Reader = struct { } return 0; }; - const n = @min(size - pos, std.math.maxInt(i64), @intFromEnum(limit)); + const n = @min(size - pos, maxInt(i64), @intFromEnum(limit)); file.seekBy(n) catch |err| { r.seek_err = err; return 0; @@ -1726,18 +1726,123 @@ pub const Writer = struct { file_reader: *Reader, limit: std.io.Limit, ) std.io.Writer.FileError!usize { + const reader_buffered = file_reader.interface.buffered(); + if (reader_buffered.len >= @intFromEnum(limit)) + return sendFileBuffered(io_w, file_reader, reader_buffered); + const writer_buffered = io_w.buffered(); + const file_limit = @intFromEnum(limit) - reader_buffered.len; const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w)); const out_fd = w.file.handle; const in_fd = file_reader.file.handle; - // TODO try using copy_file_range on FreeBSD - // TODO try using sendfile on macOS - // TODO try using sendfile on FreeBSD + + if (native_os == .freebsd and w.mode == .streaming) sf: { + // Try using sendfile on FreeBSD. + if (w.sendfile_err != null) break :sf; + const offset = std.math.cast(std.c.off_t, file_reader.pos) orelse break :sf; + var hdtr_data: std.c.sf_hdtr = undefined; + var headers: [2]posix.iovec_const = undefined; + var headers_i: u8 = 0; + if (writer_buffered.len != 0) { + headers[headers_i] = .{ .base = writer_buffered.ptr, .len = writer_buffered.len }; + headers_i += 1; + } + if (reader_buffered.len != 0) { + headers[headers_i] = .{ .base = reader_buffered.ptr, .len = reader_buffered.len }; + headers_i += 1; + } + const hdtr: ?*std.c.sf_hdtr = if (headers_i == 0) null else b: { + hdtr_data = .{ + .headers = &headers, + .hdr_cnt = headers_i, + .trailers = null, + .trl_cnt = 0, + }; + break :b &hdtr_data; + }; + var sbytes: std.c.off_t = undefined; + const nbytes: usize = @min(file_limit, maxInt(usize)); + const flags = 0; + switch (posix.errno(std.c.sendfile(in_fd, out_fd, offset, nbytes, hdtr, &sbytes, flags))) { + .SUCCESS, .INTR => {}, + .INVAL, .OPNOTSUPP, .NOTSOCK, .NOSYS => w.sendfile_err = error.UnsupportedOperation, + .BADF => if (builtin.mode == .Debug) @panic("race condition") else { + w.sendfile_err = error.Unexpected; + }, + .FAULT => if (builtin.mode == .Debug) @panic("segmentation fault") else { + w.sendfile_err = error.Unexpected; + }, + .NOTCONN => w.sendfile_err = error.BrokenPipe, + .AGAIN, .BUSY => if (sbytes == 0) { + w.sendfile_err = error.WouldBlock; + }, + .IO => w.sendfile_err = error.InputOutput, + .PIPE => w.sendfile_err = error.BrokenPipe, + .NOBUFS => w.sendfile_err = error.SystemResources, + else => |err| w.sendfile_err = posix.unexpectedErrno(err), + } + const consumed = io_w.consume(@bitCast(sbytes)); + file_reader.seekTo(file_reader.pos + consumed) catch return error.ReadFailed; + return consumed; + } + + if (native_os.isDarwin() and w.mode == .streaming) sf: { + // Try using sendfile on macOS. + if (w.sendfile_err != null) break :sf; + const offset = std.math.cast(std.c.off_t, file_reader.pos) orelse break :sf; + var hdtr_data: std.c.sf_hdtr = undefined; + var headers: [2]posix.iovec_const = undefined; + var headers_i: u8 = 0; + if (writer_buffered.len != 0) { + headers[headers_i] = .{ .base = writer_buffered.ptr, .len = writer_buffered.len }; + headers_i += 1; + } + if (reader_buffered.len != 0) { + headers[headers_i] = .{ .base = reader_buffered.ptr, .len = reader_buffered.len }; + headers_i += 1; + } + const hdtr: ?*std.c.sf_hdtr = if (headers_i == 0) null else b: { + hdtr_data = .{ + .headers = &headers, + .hdr_cnt = headers_i, + .trailers = null, + .trl_cnt = 0, + }; + break :b &hdtr_data; + }; + const max_count = maxInt(i32); // Avoid EINVAL. + var sbytes: std.c.off_t = @min(file_limit, max_count); + const flags = 0; + switch (posix.errno(std.c.sendfile(in_fd, out_fd, offset, &sbytes, hdtr, flags))) { + .SUCCESS, .INTR => {}, + .OPNOTSUPP, .NOTSOCK, .NOSYS => w.sendfile_err = error.UnsupportedOperation, + .BADF => if (builtin.mode == .Debug) @panic("race condition") else { + w.sendfile_err = error.Unexpected; + }, + .FAULT => if (builtin.mode == .Debug) @panic("segmentation fault") else { + w.sendfile_err = error.Unexpected; + }, + .INVAL => if (builtin.mode == .Debug) @panic("invalid API usage") else { + w.sendfile_err = error.Unexpected; + }, + .NOTCONN => w.sendfile_err = error.BrokenPipe, + .AGAIN => if (sbytes == 0) { + w.sendfile_err = error.WouldBlock; + }, + .IO => w.sendfile_err = error.InputOutput, + .PIPE => w.sendfile_err = error.BrokenPipe, + else => |err| w.sendfile_err = posix.unexpectedErrno(err), + } + const consumed = io_w.consume(@bitCast(sbytes)); + file_reader.seekTo(file_reader.pos + consumed) catch return error.ReadFailed; + return consumed; + } + if (native_os == .linux and w.mode == .streaming) sf: { // Try using sendfile on Linux. if (w.sendfile_err != null) break :sf; // Linux sendfile does not support headers. - const buffered = limit.slice(file_reader.interface.buffer); - if (io_w.end != 0 or buffered.len != 0) return drain(io_w, &.{buffered}, 1); + if (writer_buffered.len != 0 or reader_buffered.len != 0) + return sendFileBuffered(io_w, file_reader, reader_buffered); const max_count = 0x7ffff000; // Avoid EINVAL. var off: std.os.linux.off_t = undefined; const off_ptr: ?*std.os.linux.off_t, const count: usize = switch (file_reader.mode) { @@ -1784,6 +1889,7 @@ pub const Writer = struct { w.pos += n; return n; } + const copy_file_range = switch (native_os) { .freebsd => std.os.freebsd.copy_file_range, .linux => if (std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 })) std.os.linux.wrapped.copy_file_range else {}, @@ -1791,8 +1897,8 @@ pub const Writer = struct { }; if (@TypeOf(copy_file_range) != void) cfr: { if (w.copy_file_range_err != null) break :cfr; - const buffered = limit.slice(file_reader.interface.buffer); - if (io_w.end != 0 or buffered.len != 0) return drain(io_w, &.{buffered}, 1); + if (writer_buffered.len != 0 or reader_buffered.len != 0) + return sendFileBuffered(io_w, file_reader, reader_buffered); var off_in: i64 = undefined; var off_out: i64 = undefined; const off_in_ptr: ?*i64 = switch (file_reader.mode) { @@ -1832,6 +1938,8 @@ pub const Writer = struct { if (w.pos != 0) break :fcf; if (limit != .unlimited) break :fcf; const size = file_reader.getSize() catch break :fcf; + if (writer_buffered.len != 0 or reader_buffered.len != 0) + return sendFileBuffered(io_w, file_reader, reader_buffered); const rc = std.c.fcopyfile(in_fd, out_fd, null, .{ .DATA = true }); switch (posix.errno(rc)) { .SUCCESS => {}, @@ -1860,6 +1968,16 @@ pub const Writer = struct { return error.Unimplemented; } + fn sendFileBuffered( + io_w: *std.io.Writer, + file_reader: *Reader, + reader_buffered: []const u8, + ) std.io.Writer.FileError!usize { + const n = try drain(io_w, &.{reader_buffered}, 1); + file_reader.seekTo(file_reader.pos + n) catch return error.ReadFailed; + return n; + } + pub fn seekTo(w: *Writer, offset: u64) SeekError!void { switch (w.mode) { .positional, .positional_reading => { diff --git a/lib/std/posix.zig b/lib/std/posix.zig index e3e1657705..3f654422b1 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -6326,295 +6326,6 @@ pub fn send( }; } -pub const SendFileError = PReadError || WriteError || SendError; - -/// Transfer data between file descriptors, with optional headers and trailers. -/// -/// Returns the number of bytes written, which can be zero. -/// -/// The `sendfile` call copies `in_len` bytes from one file descriptor to another. When possible, -/// this is done within the operating system kernel, which can provide better performance -/// characteristics than transferring data from kernel to user space and back, such as with -/// `read` and `write` calls. When `in_len` is `0`, it means to copy until the end of the input file has been -/// reached. Note, however, that partial writes are still possible in this case. -/// -/// `in_fd` must be a file descriptor opened for reading, and `out_fd` must be a file descriptor -/// opened for writing. They may be any kind of file descriptor; however, if `in_fd` is not a regular -/// file system file, it may cause this function to fall back to calling `read` and `write`, in which case -/// atomicity guarantees no longer apply. -/// -/// Copying begins reading at `in_offset`. The input file descriptor seek position is ignored and not updated. -/// If the output file descriptor has a seek position, it is updated as bytes are written. When -/// `in_offset` is past the end of the input file, it successfully reads 0 bytes. -/// -/// `flags` has different meanings per operating system; refer to the respective man pages. -/// -/// These systems support atomically sending everything, including headers and trailers: -/// * macOS -/// * FreeBSD -/// -/// These systems support in-kernel data copying, but headers and trailers are not sent atomically: -/// * Linux -/// -/// Other systems fall back to calling `read` / `write`. -/// -/// Linux has a limit on how many bytes may be transferred in one `sendfile` call, which is `0x7ffff000` -/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as -/// well as stuffing the errno codes into the last `4096` values. This is noted on the `sendfile` man page. -/// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL. -/// The corresponding POSIX limit on this is `maxInt(isize)`. -pub fn sendfile( - out_fd: fd_t, - in_fd: fd_t, - in_offset: u64, - in_len: u64, - headers: []const iovec_const, - trailers: []const iovec_const, - flags: u32, -) SendFileError!usize { - var header_done = false; - var total_written: usize = 0; - - // Prevents EOVERFLOW. - const size_t = std.meta.Int(.unsigned, @typeInfo(usize).int.bits - 1); - const max_count = switch (native_os) { - .linux => 0x7ffff000, - .macos, .ios, .watchos, .tvos, .visionos => maxInt(i32), - else => maxInt(size_t), - }; - - switch (native_os) { - .linux => sf: { - if (headers.len != 0) { - const amt = try writev(out_fd, headers); - total_written += amt; - if (amt < count_iovec_bytes(headers)) return total_written; - header_done = true; - } - - // Here we match BSD behavior, making a zero count value send as many bytes as possible. - const adjusted_count = if (in_len == 0) max_count else @min(in_len, max_count); - - const sendfile_sym = if (lfs64_abi) system.sendfile64 else system.sendfile; - while (true) { - var offset: off_t = @bitCast(in_offset); - const rc = sendfile_sym(out_fd, in_fd, &offset, adjusted_count); - switch (errno(rc)) { - .SUCCESS => { - const amt: usize = @bitCast(rc); - total_written += amt; - if (in_len == 0 and amt == 0) { - // We have detected EOF from `in_fd`. - break; - } else if (amt < in_len) { - return total_written; - } else { - break; - } - }, - - .BADF => unreachable, // Always a race condition. - .FAULT => unreachable, // Segmentation fault. - .OVERFLOW => unreachable, // We avoid passing too large of a `count`. - .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket - - .INVAL => { - // EINVAL could be any of the following situations: - // * Descriptor is not valid or locked - // * an mmap(2)-like operation is not available for in_fd - // * count is negative - // * out_fd has the APPEND flag set - // Because of the "mmap(2)-like operation" possibility, we fall back to doing read/write - // manually. - break :sf; - }, - .AGAIN => return error.WouldBlock, - .IO => return error.InputOutput, - .PIPE => return error.BrokenPipe, - .NOMEM => return error.SystemResources, - .NXIO => return error.Unseekable, - .SPIPE => return error.Unseekable, - else => |err| { - unexpectedErrno(err) catch {}; - break :sf; - }, - } - } - - if (trailers.len != 0) { - total_written += try writev(out_fd, trailers); - } - - return total_written; - }, - .freebsd => sf: { - var hdtr_data: std.c.sf_hdtr = undefined; - var hdtr: ?*std.c.sf_hdtr = null; - if (headers.len != 0 or trailers.len != 0) { - // Here we carefully avoid `@intCast` by returning partial writes when - // too many io vectors are provided. - const hdr_cnt = cast(u31, headers.len) orelse maxInt(u31); - if (headers.len > hdr_cnt) return writev(out_fd, headers); - - const trl_cnt = cast(u31, trailers.len) orelse maxInt(u31); - - hdtr_data = std.c.sf_hdtr{ - .headers = headers.ptr, - .hdr_cnt = hdr_cnt, - .trailers = trailers.ptr, - .trl_cnt = trl_cnt, - }; - hdtr = &hdtr_data; - } - - while (true) { - var sbytes: off_t = undefined; - const err = errno(system.sendfile(in_fd, out_fd, @bitCast(in_offset), @min(in_len, max_count), hdtr, &sbytes, flags)); - const amt: usize = @bitCast(sbytes); - switch (err) { - .SUCCESS => return amt, - - .BADF => unreachable, // Always a race condition. - .FAULT => unreachable, // Segmentation fault. - .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket - - .INVAL, .OPNOTSUPP, .NOTSOCK, .NOSYS => { - // EINVAL could be any of the following situations: - // * The fd argument is not a regular file. - // * The s argument is not a SOCK.STREAM type socket. - // * The offset argument is negative. - // Because of some of these possibilities, we fall back to doing read/write - // manually, the same as ENOSYS. - break :sf; - }, - - .INTR => if (amt != 0) return amt else continue, - - .AGAIN => if (amt != 0) { - return amt; - } else { - return error.WouldBlock; - }, - - .BUSY => if (amt != 0) { - return amt; - } else { - return error.WouldBlock; - }, - - .IO => return error.InputOutput, - .NOBUFS => return error.SystemResources, - .PIPE => return error.BrokenPipe, - - else => { - unexpectedErrno(err) catch {}; - if (amt != 0) { - return amt; - } else { - break :sf; - } - }, - } - } - }, - .macos, .ios, .tvos, .watchos, .visionos => sf: { - var hdtr_data: std.c.sf_hdtr = undefined; - var hdtr: ?*std.c.sf_hdtr = null; - if (headers.len != 0 or trailers.len != 0) { - // Here we carefully avoid `@intCast` by returning partial writes when - // too many io vectors are provided. - const hdr_cnt = cast(u31, headers.len) orelse maxInt(u31); - if (headers.len > hdr_cnt) return writev(out_fd, headers); - - const trl_cnt = cast(u31, trailers.len) orelse maxInt(u31); - - hdtr_data = std.c.sf_hdtr{ - .headers = headers.ptr, - .hdr_cnt = hdr_cnt, - .trailers = trailers.ptr, - .trl_cnt = trl_cnt, - }; - hdtr = &hdtr_data; - } - - while (true) { - var sbytes: off_t = @min(in_len, max_count); - const err = errno(system.sendfile(in_fd, out_fd, @bitCast(in_offset), &sbytes, hdtr, flags)); - const amt: usize = @bitCast(sbytes); - switch (err) { - .SUCCESS => return amt, - - .BADF => unreachable, // Always a race condition. - .FAULT => unreachable, // Segmentation fault. - .INVAL => unreachable, - .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket - - .OPNOTSUPP, .NOTSOCK, .NOSYS => break :sf, - - .INTR => if (amt != 0) return amt else continue, - - .AGAIN => if (amt != 0) { - return amt; - } else { - return error.WouldBlock; - }, - - .IO => return error.InputOutput, - .PIPE => return error.BrokenPipe, - - else => { - unexpectedErrno(err) catch {}; - if (amt != 0) { - return amt; - } else { - break :sf; - } - }, - } - } - }, - else => {}, // fall back to read/write - } - - if (headers.len != 0 and !header_done) { - const amt = try writev(out_fd, headers); - total_written += amt; - if (amt < count_iovec_bytes(headers)) return total_written; - } - - rw: { - var buf: [8 * 4096]u8 = undefined; - // Here we match BSD behavior, making a zero count value send as many bytes as possible. - const adjusted_count = if (in_len == 0) buf.len else @min(buf.len, in_len); - const amt_read = try pread(in_fd, buf[0..adjusted_count], in_offset); - if (amt_read == 0) { - if (in_len == 0) { - // We have detected EOF from `in_fd`. - break :rw; - } else { - return total_written; - } - } - const amt_written = try write(out_fd, buf[0..amt_read]); - total_written += amt_written; - if (amt_written < in_len or in_len == 0) return total_written; - } - - if (trailers.len != 0) { - total_written += try writev(out_fd, trailers); - } - - return total_written; -} - -fn count_iovec_bytes(iovs: []const iovec_const) usize { - var count: usize = 0; - for (iovs) |iov| { - count += iov.len; - } - return count; -} - pub const CopyFileRangeError = error{ FileTooBig, InputOutput, From 76fe518d498116763dc1e3a7669619a3a9413715 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 21 Jul 2025 23:26:18 -0700 Subject: [PATCH 17/76] std.fs.File.Reader.sendFile: fix EndOfStream detection --- lib/std/fs/File.zig | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 2091b27f60..be993895bc 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1624,7 +1624,6 @@ pub const Writer = struct { const pattern = data[data.len - 1]; if (pattern.len == 0 or splat == 0) return 0; const n = windows.WriteFile(handle, pattern, null) catch |err| { - std.debug.print("windows write file failed3: {t}\n", .{err}); w.err = err; return error.WriteFailed; }; @@ -1735,6 +1734,16 @@ pub const Writer = struct { const out_fd = w.file.handle; const in_fd = file_reader.file.handle; + if (file_reader.size) |size| { + if (size - file_reader.pos == 0) { + if (reader_buffered.len != 0) { + return sendFileBuffered(io_w, file_reader, reader_buffered); + } else { + return error.EndOfStream; + } + } + } + if (native_os == .freebsd and w.mode == .streaming) sf: { // Try using sendfile on FreeBSD. if (w.sendfile_err != null) break :sf; @@ -1780,6 +1789,10 @@ pub const Writer = struct { .NOBUFS => w.sendfile_err = error.SystemResources, else => |err| w.sendfile_err = posix.unexpectedErrno(err), } + if (sbytes == 0) { + file_reader.size = file_reader.pos; + return error.EndOfStream; + } const consumed = io_w.consume(@bitCast(sbytes)); file_reader.seekTo(file_reader.pos + consumed) catch return error.ReadFailed; return consumed; @@ -1810,9 +1823,9 @@ pub const Writer = struct { break :b &hdtr_data; }; const max_count = maxInt(i32); // Avoid EINVAL. - var sbytes: std.c.off_t = @min(file_limit, max_count); + var len: std.c.off_t = @min(file_limit, max_count); const flags = 0; - switch (posix.errno(std.c.sendfile(in_fd, out_fd, offset, &sbytes, hdtr, flags))) { + switch (posix.errno(std.c.sendfile(in_fd, out_fd, offset, &len, hdtr, flags))) { .SUCCESS, .INTR => {}, .OPNOTSUPP, .NOTSOCK, .NOSYS => w.sendfile_err = error.UnsupportedOperation, .BADF => if (builtin.mode == .Debug) @panic("race condition") else { @@ -1825,14 +1838,18 @@ pub const Writer = struct { w.sendfile_err = error.Unexpected; }, .NOTCONN => w.sendfile_err = error.BrokenPipe, - .AGAIN => if (sbytes == 0) { + .AGAIN => if (len == 0) { w.sendfile_err = error.WouldBlock; }, .IO => w.sendfile_err = error.InputOutput, .PIPE => w.sendfile_err = error.BrokenPipe, else => |err| w.sendfile_err = posix.unexpectedErrno(err), } - const consumed = io_w.consume(@bitCast(sbytes)); + if (len == 0) { + file_reader.size = file_reader.pos; + return error.EndOfStream; + } + const consumed = io_w.consume(@bitCast(len)); file_reader.seekTo(file_reader.pos + consumed) catch return error.ReadFailed; return consumed; } From 34d2778239b7eea854385354fd956358ae7cf5a0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 22 Jul 2025 09:39:24 -0700 Subject: [PATCH 18/76] std.fs.File.Reader.sendFile: fix 32-bit freebsd --- lib/std/fs/File.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index be993895bc..138807972e 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1793,7 +1793,7 @@ pub const Writer = struct { file_reader.size = file_reader.pos; return error.EndOfStream; } - const consumed = io_w.consume(@bitCast(sbytes)); + const consumed = io_w.consume(@intCast(sbytes)); file_reader.seekTo(file_reader.pos + consumed) catch return error.ReadFailed; return consumed; } From d509bc933fe749cad270e11a7f3be88e1ec9a1a7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 17:02:01 -0700 Subject: [PATCH 19/76] std.Io: delete CWriter it shan't be missed --- lib/std/Io.zig | 4 ---- lib/std/Io/c_writer.zig | 44 ----------------------------------------- 2 files changed, 48 deletions(-) delete mode 100644 lib/std/Io/c_writer.zig diff --git a/lib/std/Io.zig b/lib/std/Io.zig index ff6966d7f7..3865c17159 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -448,9 +448,6 @@ pub const bufferedReaderSize = @import("Io/buffered_reader.zig").bufferedReaderS pub const FixedBufferStream = @import("Io/fixed_buffer_stream.zig").FixedBufferStream; pub const fixedBufferStream = @import("Io/fixed_buffer_stream.zig").fixedBufferStream; -pub const CWriter = @import("Io/c_writer.zig").CWriter; -pub const cWriter = @import("Io/c_writer.zig").cWriter; - pub const LimitedReader = @import("Io/limited_reader.zig").LimitedReader; pub const limitedReader = @import("Io/limited_reader.zig").limitedReader; @@ -903,7 +900,6 @@ test { _ = @import("Io/buffered_atomic_file.zig"); _ = @import("Io/buffered_reader.zig"); _ = @import("Io/buffered_writer.zig"); - _ = @import("Io/c_writer.zig"); _ = @import("Io/counting_writer.zig"); _ = @import("Io/counting_reader.zig"); _ = @import("Io/fixed_buffer_stream.zig"); diff --git a/lib/std/Io/c_writer.zig b/lib/std/Io/c_writer.zig deleted file mode 100644 index 30d0cabcf5..0000000000 --- a/lib/std/Io/c_writer.zig +++ /dev/null @@ -1,44 +0,0 @@ -const std = @import("../std.zig"); -const builtin = @import("builtin"); -const io = std.io; -const testing = std.testing; - -pub const CWriter = io.GenericWriter(*std.c.FILE, std.fs.File.WriteError, cWriterWrite); - -pub fn cWriter(c_file: *std.c.FILE) CWriter { - return .{ .context = c_file }; -} - -fn cWriterWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize { - const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file); - if (amt_written >= 0) return amt_written; - switch (@as(std.c.E, @enumFromInt(std.c._errno().*))) { - .SUCCESS => unreachable, - .INVAL => unreachable, - .FAULT => unreachable, - .AGAIN => unreachable, // this is a blocking API - .BADF => unreachable, // always a race condition - .DESTADDRREQ => unreachable, // connect was never called - .DQUOT => return error.DiskQuota, - .FBIG => return error.FileTooBig, - .IO => return error.InputOutput, - .NOSPC => return error.NoSpaceLeft, - .PERM => return error.PermissionDenied, - .PIPE => return error.BrokenPipe, - else => |err| return std.posix.unexpectedErrno(err), - } -} - -test cWriter { - if (!builtin.link_libc or builtin.os.tag == .wasi) return error.SkipZigTest; - - const filename = "tmp_io_test_file.txt"; - const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile; - defer { - _ = std.c.fclose(out_file); - std.fs.cwd().deleteFileZ(filename) catch {}; - } - - const writer = cWriter(out_file); - try writer.print("hi: {}\n", .{@as(i32, 123)}); -} From a3efdd7279179de9591e62cab38bafdafd7e4814 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 17:04:00 -0700 Subject: [PATCH 20/76] std.Io: delete StreamSource it shan't be missed --- CMakeLists.txt | 9 --- lib/std/Io.zig | 3 - lib/std/Io/stream_source.zig | 127 ----------------------------------- 3 files changed, 139 deletions(-) delete mode 100644 lib/std/Io/stream_source.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index d9824e5c12..c0a53c28e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -390,15 +390,6 @@ set(ZIG_STAGE2_SOURCES lib/std/Io.zig lib/std/Io/Reader.zig lib/std/Io/Writer.zig - lib/std/Io/buffered_atomic_file.zig - lib/std/Io/buffered_writer.zig - lib/std/Io/change_detection_stream.zig - lib/std/Io/counting_reader.zig - lib/std/Io/counting_writer.zig - lib/std/Io/find_byte_writer.zig - lib/std/Io/fixed_buffer_stream.zig - lib/std/Io/limited_reader.zig - lib/std/Io/seekable_stream.zig lib/std/Progress.zig lib/std/Random.zig lib/std/Target.zig diff --git a/lib/std/Io.zig b/lib/std/Io.zig index 3865c17159..cc79ecade5 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -473,8 +473,6 @@ pub const findByteWriter = @import("Io/find_byte_writer.zig").findByteWriter; pub const BufferedAtomicFile = @import("Io/buffered_atomic_file.zig").BufferedAtomicFile; -pub const StreamSource = @import("Io/stream_source.zig").StreamSource; - pub const tty = @import("Io/tty.zig"); /// A Writer that doesn't write to anything. @@ -904,6 +902,5 @@ test { _ = @import("Io/counting_reader.zig"); _ = @import("Io/fixed_buffer_stream.zig"); _ = @import("Io/seekable_stream.zig"); - _ = @import("Io/stream_source.zig"); _ = @import("Io/test.zig"); } diff --git a/lib/std/Io/stream_source.zig b/lib/std/Io/stream_source.zig deleted file mode 100644 index 2a3527e479..0000000000 --- a/lib/std/Io/stream_source.zig +++ /dev/null @@ -1,127 +0,0 @@ -const std = @import("../std.zig"); -const builtin = @import("builtin"); -const io = std.io; - -/// Provides `io.GenericReader`, `io.GenericWriter`, and `io.SeekableStream` for in-memory buffers as -/// well as files. -/// For memory sources, if the supplied byte buffer is const, then `io.GenericWriter` is not available. -/// The error set of the stream functions is the error set of the corresponding file functions. -pub const StreamSource = union(enum) { - // TODO: expose UEFI files to std.os in a way that allows this to be true - const has_file = (builtin.os.tag != .freestanding and builtin.os.tag != .uefi); - - /// The stream access is redirected to this buffer. - buffer: io.FixedBufferStream([]u8), - - /// The stream access is redirected to this buffer. - /// Writing to the source will always yield `error.AccessDenied`. - const_buffer: io.FixedBufferStream([]const u8), - - /// The stream access is redirected to this file. - /// On freestanding, this must never be initialized! - file: if (has_file) std.fs.File else void, - - pub const ReadError = io.FixedBufferStream([]u8).ReadError || (if (has_file) std.fs.File.ReadError else error{}); - pub const WriteError = error{AccessDenied} || io.FixedBufferStream([]u8).WriteError || (if (has_file) std.fs.File.WriteError else error{}); - pub const SeekError = io.FixedBufferStream([]u8).SeekError || (if (has_file) std.fs.File.SeekError else error{}); - pub const GetSeekPosError = io.FixedBufferStream([]u8).GetSeekPosError || (if (has_file) std.fs.File.GetSeekPosError else error{}); - - pub const Reader = io.GenericReader(*StreamSource, ReadError, read); - pub const Writer = io.GenericWriter(*StreamSource, WriteError, write); - pub const SeekableStream = io.SeekableStream( - *StreamSource, - SeekError, - GetSeekPosError, - seekTo, - seekBy, - getPos, - getEndPos, - ); - - pub fn read(self: *StreamSource, dest: []u8) ReadError!usize { - switch (self.*) { - .buffer => |*x| return x.read(dest), - .const_buffer => |*x| return x.read(dest), - .file => |x| if (!has_file) unreachable else return x.read(dest), - } - } - - pub fn write(self: *StreamSource, bytes: []const u8) WriteError!usize { - switch (self.*) { - .buffer => |*x| return x.write(bytes), - .const_buffer => return error.AccessDenied, - .file => |x| if (!has_file) unreachable else return x.write(bytes), - } - } - - pub fn seekTo(self: *StreamSource, pos: u64) SeekError!void { - switch (self.*) { - .buffer => |*x| return x.seekTo(pos), - .const_buffer => |*x| return x.seekTo(pos), - .file => |x| if (!has_file) unreachable else return x.seekTo(pos), - } - } - - pub fn seekBy(self: *StreamSource, amt: i64) SeekError!void { - switch (self.*) { - .buffer => |*x| return x.seekBy(amt), - .const_buffer => |*x| return x.seekBy(amt), - .file => |x| if (!has_file) unreachable else return x.seekBy(amt), - } - } - - pub fn getEndPos(self: *StreamSource) GetSeekPosError!u64 { - switch (self.*) { - .buffer => |*x| return x.getEndPos(), - .const_buffer => |*x| return x.getEndPos(), - .file => |x| if (!has_file) unreachable else return x.getEndPos(), - } - } - - pub fn getPos(self: *StreamSource) GetSeekPosError!u64 { - switch (self.*) { - .buffer => |*x| return x.getPos(), - .const_buffer => |*x| return x.getPos(), - .file => |x| if (!has_file) unreachable else return x.getPos(), - } - } - - pub fn reader(self: *StreamSource) Reader { - return .{ .context = self }; - } - - pub fn writer(self: *StreamSource) Writer { - return .{ .context = self }; - } - - pub fn seekableStream(self: *StreamSource) SeekableStream { - return .{ .context = self }; - } -}; - -test "refs" { - std.testing.refAllDecls(StreamSource); -} - -test "mutable buffer" { - var buffer: [64]u8 = undefined; - var source = StreamSource{ .buffer = std.io.fixedBufferStream(&buffer) }; - - var writer = source.writer(); - - try writer.writeAll("Hello, World!"); - - try std.testing.expectEqualStrings("Hello, World!", source.buffer.getWritten()); -} - -test "const buffer" { - const buffer: [64]u8 = "Hello, World!".* ++ ([1]u8{0xAA} ** 51); - var source = StreamSource{ .const_buffer = std.io.fixedBufferStream(&buffer) }; - - var reader = source.reader(); - - var dst_buffer: [13]u8 = undefined; - try reader.readNoEof(&dst_buffer); - - try std.testing.expectEqualStrings("Hello, World!", &dst_buffer); -} From abed0f5129c5e03fce61c5c48cdc4bb396805ce2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 17:05:57 -0700 Subject: [PATCH 21/76] std.Io: delete BufferedAtomicFile this is now redundant --- lib/std/Io.zig | 3 -- lib/std/Io/buffered_atomic_file.zig | 55 ----------------------------- 2 files changed, 58 deletions(-) delete mode 100644 lib/std/Io/buffered_atomic_file.zig diff --git a/lib/std/Io.zig b/lib/std/Io.zig index cc79ecade5..26838517cd 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -471,8 +471,6 @@ pub const changeDetectionStream = @import("Io/change_detection_stream.zig").chan pub const FindByteWriter = @import("Io/find_byte_writer.zig").FindByteWriter; pub const findByteWriter = @import("Io/find_byte_writer.zig").findByteWriter; -pub const BufferedAtomicFile = @import("Io/buffered_atomic_file.zig").BufferedAtomicFile; - pub const tty = @import("Io/tty.zig"); /// A Writer that doesn't write to anything. @@ -895,7 +893,6 @@ test { _ = Writer; _ = @import("Io/bit_reader.zig"); _ = @import("Io/bit_writer.zig"); - _ = @import("Io/buffered_atomic_file.zig"); _ = @import("Io/buffered_reader.zig"); _ = @import("Io/buffered_writer.zig"); _ = @import("Io/counting_writer.zig"); diff --git a/lib/std/Io/buffered_atomic_file.zig b/lib/std/Io/buffered_atomic_file.zig deleted file mode 100644 index 48510bde52..0000000000 --- a/lib/std/Io/buffered_atomic_file.zig +++ /dev/null @@ -1,55 +0,0 @@ -const std = @import("../std.zig"); -const mem = std.mem; -const fs = std.fs; -const File = std.fs.File; - -pub const BufferedAtomicFile = struct { - atomic_file: fs.AtomicFile, - file_writer: File.Writer, - buffered_writer: BufferedWriter, - allocator: mem.Allocator, - - pub const buffer_size = 4096; - pub const BufferedWriter = std.io.BufferedWriter(buffer_size, File.Writer); - pub const Writer = std.io.GenericWriter(*BufferedWriter, BufferedWriter.Error, BufferedWriter.write); - - /// TODO when https://github.com/ziglang/zig/issues/2761 is solved - /// this API will not need an allocator - pub fn create( - allocator: mem.Allocator, - dir: fs.Dir, - dest_path: []const u8, - atomic_file_options: fs.Dir.AtomicFileOptions, - ) !*BufferedAtomicFile { - var self = try allocator.create(BufferedAtomicFile); - self.* = BufferedAtomicFile{ - .atomic_file = undefined, - .file_writer = undefined, - .buffered_writer = undefined, - .allocator = allocator, - }; - errdefer allocator.destroy(self); - - self.atomic_file = try dir.atomicFile(dest_path, atomic_file_options); - errdefer self.atomic_file.deinit(); - - self.file_writer = self.atomic_file.file.deprecatedWriter(); - self.buffered_writer = .{ .unbuffered_writer = self.file_writer }; - return self; - } - - /// always call destroy, even after successful finish() - pub fn destroy(self: *BufferedAtomicFile) void { - self.atomic_file.deinit(); - self.allocator.destroy(self); - } - - pub fn finish(self: *BufferedAtomicFile) !void { - try self.buffered_writer.flush(); - try self.atomic_file.finish(); - } - - pub fn writer(self: *BufferedAtomicFile) Writer { - return .{ .context = &self.buffered_writer }; - } -}; From d9a5a3e8c55b501afe0d9df232d613f6b445f14f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 17:09:15 -0700 Subject: [PATCH 22/76] std.Io: delete MultiWriter nah --- lib/std/Io.zig | 3 --- lib/std/Io/multi_writer.zig | 53 ------------------------------------- 2 files changed, 56 deletions(-) delete mode 100644 lib/std/Io/multi_writer.zig diff --git a/lib/std/Io.zig b/lib/std/Io.zig index 26838517cd..df5ef7aef8 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -456,9 +456,6 @@ pub const countingWriter = @import("Io/counting_writer.zig").countingWriter; pub const CountingReader = @import("Io/counting_reader.zig").CountingReader; pub const countingReader = @import("Io/counting_reader.zig").countingReader; -pub const MultiWriter = @import("Io/multi_writer.zig").MultiWriter; -pub const multiWriter = @import("Io/multi_writer.zig").multiWriter; - pub const BitReader = @import("Io/bit_reader.zig").BitReader; pub const bitReader = @import("Io/bit_reader.zig").bitReader; diff --git a/lib/std/Io/multi_writer.zig b/lib/std/Io/multi_writer.zig deleted file mode 100644 index 20e9e782de..0000000000 --- a/lib/std/Io/multi_writer.zig +++ /dev/null @@ -1,53 +0,0 @@ -const std = @import("../std.zig"); -const io = std.io; - -/// Takes a tuple of streams, and constructs a new stream that writes to all of them -pub fn MultiWriter(comptime Writers: type) type { - comptime var ErrSet = error{}; - inline for (@typeInfo(Writers).@"struct".fields) |field| { - const StreamType = field.type; - ErrSet = ErrSet || StreamType.Error; - } - - return struct { - const Self = @This(); - - streams: Writers, - - pub const Error = ErrSet; - pub const Writer = io.GenericWriter(*Self, Error, write); - - pub fn writer(self: *Self) Writer { - return .{ .context = self }; - } - - pub fn write(self: *Self, bytes: []const u8) Error!usize { - inline for (self.streams) |stream| - try stream.writeAll(bytes); - return bytes.len; - } - }; -} - -pub fn multiWriter(streams: anytype) MultiWriter(@TypeOf(streams)) { - return .{ .streams = streams }; -} - -const testing = std.testing; - -test "MultiWriter" { - var tmp = testing.tmpDir(.{}); - defer tmp.cleanup(); - var f = try tmp.dir.createFile("t.txt", .{}); - - var buf1: [255]u8 = undefined; - var fbs1 = io.fixedBufferStream(&buf1); - var buf2: [255]u8 = undefined; - var stream = multiWriter(.{ fbs1.writer(), f.writer() }); - - try stream.writer().print("HI", .{}); - f.close(); - - try testing.expectEqualSlices(u8, "HI", fbs1.getWritten()); - try testing.expectEqualSlices(u8, "HI", try tmp.dir.readFile("t.txt", &buf2)); -} From 03a6892189891f1566b9e63780129834bea7eb1e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 17:13:23 -0700 Subject: [PATCH 23/76] std.Io: delete ChangeDetectionStream dead code --- lib/std/Io.zig | 3 -- lib/std/Io/change_detection_stream.zig | 55 -------------------------- 2 files changed, 58 deletions(-) delete mode 100644 lib/std/Io/change_detection_stream.zig diff --git a/lib/std/Io.zig b/lib/std/Io.zig index df5ef7aef8..1ccc9a4edc 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -462,9 +462,6 @@ pub const bitReader = @import("Io/bit_reader.zig").bitReader; pub const BitWriter = @import("Io/bit_writer.zig").BitWriter; pub const bitWriter = @import("Io/bit_writer.zig").bitWriter; -pub const ChangeDetectionStream = @import("Io/change_detection_stream.zig").ChangeDetectionStream; -pub const changeDetectionStream = @import("Io/change_detection_stream.zig").changeDetectionStream; - pub const FindByteWriter = @import("Io/find_byte_writer.zig").FindByteWriter; pub const findByteWriter = @import("Io/find_byte_writer.zig").findByteWriter; diff --git a/lib/std/Io/change_detection_stream.zig b/lib/std/Io/change_detection_stream.zig deleted file mode 100644 index d9da1c4a0e..0000000000 --- a/lib/std/Io/change_detection_stream.zig +++ /dev/null @@ -1,55 +0,0 @@ -const std = @import("../std.zig"); -const io = std.io; -const mem = std.mem; -const assert = std.debug.assert; - -/// Used to detect if the data written to a stream differs from a source buffer -pub fn ChangeDetectionStream(comptime WriterType: type) type { - return struct { - const Self = @This(); - pub const Error = WriterType.Error; - pub const Writer = io.GenericWriter(*Self, Error, write); - - anything_changed: bool, - underlying_writer: WriterType, - source_index: usize, - source: []const u8, - - pub fn writer(self: *Self) Writer { - return .{ .context = self }; - } - - fn write(self: *Self, bytes: []const u8) Error!usize { - if (!self.anything_changed) { - const end = self.source_index + bytes.len; - if (end > self.source.len) { - self.anything_changed = true; - } else { - const src_slice = self.source[self.source_index..end]; - self.source_index += bytes.len; - if (!mem.eql(u8, bytes, src_slice)) { - self.anything_changed = true; - } - } - } - - return self.underlying_writer.write(bytes); - } - - pub fn changeDetected(self: *Self) bool { - return self.anything_changed or (self.source_index != self.source.len); - } - }; -} - -pub fn changeDetectionStream( - source: []const u8, - underlying_writer: anytype, -) ChangeDetectionStream(@TypeOf(underlying_writer)) { - return ChangeDetectionStream(@TypeOf(underlying_writer)){ - .anything_changed = false, - .underlying_writer = underlying_writer, - .source_index = 0, - .source = source, - }; -} From af0a02a2de8fad56029cccbfeb6254a2c2169b51 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 17:15:09 -0700 Subject: [PATCH 24/76] std.Io: delete FindByteWriter dead --- lib/std/Io.zig | 3 --- lib/std/Io/find_byte_writer.zig | 40 --------------------------------- 2 files changed, 43 deletions(-) delete mode 100644 lib/std/Io/find_byte_writer.zig diff --git a/lib/std/Io.zig b/lib/std/Io.zig index 1ccc9a4edc..9228a61287 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -462,9 +462,6 @@ pub const bitReader = @import("Io/bit_reader.zig").bitReader; pub const BitWriter = @import("Io/bit_writer.zig").BitWriter; pub const bitWriter = @import("Io/bit_writer.zig").bitWriter; -pub const FindByteWriter = @import("Io/find_byte_writer.zig").FindByteWriter; -pub const findByteWriter = @import("Io/find_byte_writer.zig").findByteWriter; - pub const tty = @import("Io/tty.zig"); /// A Writer that doesn't write to anything. diff --git a/lib/std/Io/find_byte_writer.zig b/lib/std/Io/find_byte_writer.zig deleted file mode 100644 index fe6836f603..0000000000 --- a/lib/std/Io/find_byte_writer.zig +++ /dev/null @@ -1,40 +0,0 @@ -const std = @import("../std.zig"); -const io = std.io; -const assert = std.debug.assert; - -/// A Writer that returns whether the given character has been written to it. -/// The contents are not written to anything. -pub fn FindByteWriter(comptime UnderlyingWriter: type) type { - return struct { - const Self = @This(); - pub const Error = UnderlyingWriter.Error; - pub const Writer = io.GenericWriter(*Self, Error, write); - - underlying_writer: UnderlyingWriter, - byte_found: bool, - byte: u8, - - pub fn writer(self: *Self) Writer { - return .{ .context = self }; - } - - fn write(self: *Self, bytes: []const u8) Error!usize { - if (!self.byte_found) { - self.byte_found = blk: { - for (bytes) |b| - if (b == self.byte) break :blk true; - break :blk false; - }; - } - return self.underlying_writer.write(bytes); - } - }; -} - -pub fn findByteWriter(byte: u8, underlying_writer: anytype) FindByteWriter(@TypeOf(underlying_writer)) { - return FindByteWriter(@TypeOf(underlying_writer)){ - .underlying_writer = underlying_writer, - .byte = byte, - .byte_found = false, - }; -} From 2ac81c76e3d176d4ac0c568d195d5b979078a938 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 17:21:33 -0700 Subject: [PATCH 25/76] std.Io: add deprecation warnings --- lib/std/Io.zig | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/lib/std/Io.zig b/lib/std/Io.zig index 9228a61287..2380b3abbf 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -435,25 +435,33 @@ pub fn GenericWriter( pub const AnyReader = @import("Io/DeprecatedReader.zig"); /// Deprecated in favor of `Writer`. pub const AnyWriter = @import("Io/DeprecatedWriter.zig"); - +/// Deprecated in favor of `File.Reader` and `File.Writer`. pub const SeekableStream = @import("Io/seekable_stream.zig").SeekableStream; - +/// Deprecated in favor of `Writer`. pub const BufferedWriter = @import("Io/buffered_writer.zig").BufferedWriter; +/// Deprecated in favor of `Writer`. pub const bufferedWriter = @import("Io/buffered_writer.zig").bufferedWriter; - +/// Deprecated in favor of `Reader`. pub const BufferedReader = @import("Io/buffered_reader.zig").BufferedReader; +/// Deprecated in favor of `Reader`. pub const bufferedReader = @import("Io/buffered_reader.zig").bufferedReader; +/// Deprecated in favor of `Reader`. pub const bufferedReaderSize = @import("Io/buffered_reader.zig").bufferedReaderSize; - +/// Deprecated in favor of `Reader`. pub const FixedBufferStream = @import("Io/fixed_buffer_stream.zig").FixedBufferStream; +/// Deprecated in favor of `Reader`. pub const fixedBufferStream = @import("Io/fixed_buffer_stream.zig").fixedBufferStream; - +/// Deprecated in favor of `Reader.Limited`. pub const LimitedReader = @import("Io/limited_reader.zig").LimitedReader; +/// Deprecated in favor of `Reader.Limited`. pub const limitedReader = @import("Io/limited_reader.zig").limitedReader; - +/// Deprecated with no replacement; inefficient pattern pub const CountingWriter = @import("Io/counting_writer.zig").CountingWriter; +/// Deprecated with no replacement; inefficient pattern pub const countingWriter = @import("Io/counting_writer.zig").countingWriter; +/// Deprecated with no replacement; inefficient pattern pub const CountingReader = @import("Io/counting_reader.zig").CountingReader; +/// Deprecated with no replacement; inefficient pattern pub const countingReader = @import("Io/counting_reader.zig").countingReader; pub const BitReader = @import("Io/bit_reader.zig").BitReader; @@ -464,9 +472,9 @@ pub const bitWriter = @import("Io/bit_writer.zig").bitWriter; pub const tty = @import("Io/tty.zig"); -/// A Writer that doesn't write to anything. +/// Deprecated in favor of `Writer.Discarding`. pub const null_writer: NullWriter = .{ .context = {} }; - +/// Deprecated in favor of `Writer.Discarding`. pub const NullWriter = GenericWriter(void, error{}, dummyWrite); fn dummyWrite(context: void, data: []const u8) error{}!usize { _ = context; @@ -882,13 +890,14 @@ test { _ = Reader; _ = Reader.Limited; _ = Writer; - _ = @import("Io/bit_reader.zig"); - _ = @import("Io/bit_writer.zig"); - _ = @import("Io/buffered_reader.zig"); - _ = @import("Io/buffered_writer.zig"); - _ = @import("Io/counting_writer.zig"); - _ = @import("Io/counting_reader.zig"); - _ = @import("Io/fixed_buffer_stream.zig"); - _ = @import("Io/seekable_stream.zig"); + _ = BitReader; + _ = BitWriter; + _ = BufferedReader; + _ = BufferedWriter; + _ = CountingWriter; + _ = CountingReader; + _ = FixedBufferStream; + _ = SeekableStream; + _ = tty; _ = @import("Io/test.zig"); } From 1dcea220a4daf537c1a75835de45076fac429895 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 20:14:28 -0700 Subject: [PATCH 26/76] std.tar: update to new I/O API --- lib/std/Build/Fuzz/WebServer.zig | 13 +- lib/std/Io/Reader.zig | 6 + lib/std/crypto/md5.zig | 12 +- lib/std/tar.zig | 636 ++++++++++++++----------------- lib/std/tar/Writer.zig | 498 ++++++++++++++++++++++++ lib/std/tar/test.zig | 350 +++++++++-------- lib/std/tar/writer.zig | 497 ------------------------ src/Compilation.zig | 37 +- src/Package/Fetch.zig | 24 +- 9 files changed, 1028 insertions(+), 1045 deletions(-) create mode 100644 lib/std/tar/Writer.zig delete mode 100644 lib/std/tar/writer.zig diff --git a/lib/std/Build/Fuzz/WebServer.zig b/lib/std/Build/Fuzz/WebServer.zig index b28a6e185c..0df43408f1 100644 --- a/lib/std/Build/Fuzz/WebServer.zig +++ b/lib/std/Build/Fuzz/WebServer.zig @@ -522,7 +522,9 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void { var cwd_cache: ?[]const u8 = null; - var archiver = std.tar.writer(response.writer()); + var adapter = response.writer().adaptToNewApi(); + var archiver: std.tar.Writer = .{ .underlying_writer = &adapter.new_interface }; + var read_buffer: [1024]u8 = undefined; for (deduped_paths) |joined_path| { var file = joined_path.root_dir.handle.openFile(joined_path.sub_path, .{}) catch |err| { @@ -530,13 +532,14 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void { continue; }; defer file.close(); - + const stat = try file.stat(); + var file_reader: std.fs.File.Reader = .initSize(file, &read_buffer, stat.size); archiver.prefix = joined_path.root_dir.path orelse try memoizedCwd(arena, &cwd_cache); - try archiver.writeFile(joined_path.sub_path, file); + try archiver.writeFile(joined_path.sub_path, &file_reader, stat.mtime); } - // intentionally omitting the pointless trailer - //try archiver.finish(); + // intentionally not calling `archiver.finishPedantically` + try adapter.new_interface.flush(); try response.end(); } diff --git a/lib/std/Io/Reader.zig b/lib/std/Io/Reader.zig index f25e113522..5c7fdafe76 100644 --- a/lib/std/Io/Reader.zig +++ b/lib/std/Io/Reader.zig @@ -179,6 +179,12 @@ pub fn streamExact(r: *Reader, w: *Writer, n: usize) StreamError!void { while (remaining != 0) remaining -= try r.stream(w, .limited(remaining)); } +/// "Pump" exactly `n` bytes from the reader to the writer. +pub fn streamExact64(r: *Reader, w: *Writer, n: u64) StreamError!void { + var remaining = n; + while (remaining != 0) remaining -= try r.stream(w, .limited64(remaining)); +} + /// "Pump" data from the reader to the writer, handling `error.EndOfStream` as /// a success case. /// diff --git a/lib/std/crypto/md5.zig b/lib/std/crypto/md5.zig index 92c8dac796..a580f826f3 100644 --- a/lib/std/crypto/md5.zig +++ b/lib/std/crypto/md5.zig @@ -54,12 +54,20 @@ pub const Md5 = struct { }; } - pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void { + pub fn hash(data: []const u8, out: *[digest_length]u8, options: Options) void { var d = Md5.init(options); - d.update(b); + d.update(data); d.final(out); } + pub fn hashResult(data: []const u8) [digest_length]u8 { + var out: [digest_length]u8 = undefined; + var d = Md5.init(.{}); + d.update(data); + d.final(&out); + return out; + } + pub fn update(d: *Self, b: []const u8) void { var off: usize = 0; diff --git a/lib/std/tar.zig b/lib/std/tar.zig index 729a07db0a..e397677cf3 100644 --- a/lib/std/tar.zig +++ b/lib/std/tar.zig @@ -19,7 +19,7 @@ const std = @import("std"); const assert = std.debug.assert; const testing = std.testing; -pub const writer = @import("tar/writer.zig").writer; +pub const Writer = @import("tar/Writer.zig"); /// Provide this to receive detailed error messages. /// When this is provided, some errors which would otherwise be returned @@ -293,28 +293,6 @@ fn nullStr(str: []const u8) []const u8 { return str; } -/// Options for iterator. -/// Buffers should be provided by the caller. -pub const IteratorOptions = struct { - /// Use a buffer with length `std.fs.max_path_bytes` to match file system capabilities. - file_name_buffer: []u8, - /// Use a buffer with length `std.fs.max_path_bytes` to match file system capabilities. - link_name_buffer: []u8, - /// Collects error messages during unpacking - diagnostics: ?*Diagnostics = null, -}; - -/// Iterates over files in tar archive. -/// `next` returns each file in tar archive. -pub fn iterator(reader: anytype, options: IteratorOptions) Iterator(@TypeOf(reader)) { - return .{ - .reader = reader, - .diagnostics = options.diagnostics, - .file_name_buffer = options.file_name_buffer, - .link_name_buffer = options.link_name_buffer, - }; -} - /// Type of the file returned by iterator `next` method. pub const FileKind = enum { directory, @@ -323,206 +301,192 @@ pub const FileKind = enum { }; /// Iterator over entries in the tar file represented by reader. -pub fn Iterator(comptime ReaderType: type) type { - return struct { - reader: ReaderType, - diagnostics: ?*Diagnostics = null, +pub const Iterator = struct { + reader: *std.Io.Reader, + diagnostics: ?*Diagnostics = null, - // buffers for heeader and file attributes - header_buffer: [Header.SIZE]u8 = undefined, + // buffers for heeader and file attributes + header_buffer: [Header.SIZE]u8 = undefined, + file_name_buffer: []u8, + link_name_buffer: []u8, + + // bytes of padding to the end of the block + padding: usize = 0, + // not consumed bytes of file from last next iteration + unread_file_bytes: u64 = 0, + + /// Options for iterator. + /// Buffers should be provided by the caller. + pub const Options = struct { + /// Use a buffer with length `std.fs.max_path_bytes` to match file system capabilities. file_name_buffer: []u8, + /// Use a buffer with length `std.fs.max_path_bytes` to match file system capabilities. link_name_buffer: []u8, + /// Collects error messages during unpacking + diagnostics: ?*Diagnostics = null, + }; - // bytes of padding to the end of the block - padding: usize = 0, - // not consumed bytes of file from last next iteration - unread_file_bytes: u64 = 0, - - pub const File = struct { - name: []const u8, // name of file, symlink or directory - link_name: []const u8, // target name of symlink - size: u64 = 0, // size of the file in bytes - mode: u32 = 0, - kind: FileKind = .file, - - unread_bytes: *u64, - parent_reader: ReaderType, - - pub const Reader = std.io.GenericReader(File, ReaderType.Error, File.read); - - pub fn reader(self: File) Reader { - return .{ .context = self }; - } - - pub fn read(self: File, dest: []u8) ReaderType.Error!usize { - const buf = dest[0..@min(dest.len, self.unread_bytes.*)]; - const n = try self.parent_reader.read(buf); - self.unread_bytes.* -= n; - return n; - } - - // Writes file content to writer. - pub fn writeAll(self: File, out_writer: anytype) !void { - var buffer: [4096]u8 = undefined; - - while (self.unread_bytes.* > 0) { - const buf = buffer[0..@min(buffer.len, self.unread_bytes.*)]; - try self.parent_reader.readNoEof(buf); - try out_writer.writeAll(buf); - self.unread_bytes.* -= buf.len; - } - } + /// Iterates over files in tar archive. + /// `next` returns each file in tar archive. + pub fn init(reader: *std.Io.Reader, options: Options) Iterator { + return .{ + .reader = reader, + .diagnostics = options.diagnostics, + .file_name_buffer = options.file_name_buffer, + .link_name_buffer = options.link_name_buffer, }; + } - const Self = @This(); - - fn readHeader(self: *Self) !?Header { - if (self.padding > 0) { - try self.reader.skipBytes(self.padding, .{}); - } - const n = try self.reader.readAll(&self.header_buffer); - if (n == 0) return null; - if (n < Header.SIZE) return error.UnexpectedEndOfStream; - const header = Header{ .bytes = self.header_buffer[0..Header.SIZE] }; - if (try header.checkChksum() == 0) return null; - return header; - } - - fn readString(self: *Self, size: usize, buffer: []u8) ![]const u8 { - if (size > buffer.len) return error.TarInsufficientBuffer; - const buf = buffer[0..size]; - try self.reader.readNoEof(buf); - return nullStr(buf); - } - - fn newFile(self: *Self) File { - return .{ - .name = self.file_name_buffer[0..0], - .link_name = self.link_name_buffer[0..0], - .parent_reader = self.reader, - .unread_bytes = &self.unread_file_bytes, - }; - } - - // Number of padding bytes in the last file block. - fn blockPadding(size: u64) usize { - const block_rounded = std.mem.alignForward(u64, size, Header.SIZE); // size rounded to te block boundary - return @intCast(block_rounded - size); - } - - /// Iterates through the tar archive as if it is a series of files. - /// Internally, the tar format often uses entries (header with optional - /// content) to add meta data that describes the next file. These - /// entries should not normally be visible to the outside. As such, this - /// loop iterates through one or more entries until it collects a all - /// file attributes. - pub fn next(self: *Self) !?File { - if (self.unread_file_bytes > 0) { - // If file content was not consumed by caller - try self.reader.skipBytes(self.unread_file_bytes, .{}); - self.unread_file_bytes = 0; - } - var file: File = self.newFile(); - - while (try self.readHeader()) |header| { - const kind = header.kind(); - const size: u64 = try header.size(); - self.padding = blockPadding(size); - - switch (kind) { - // File types to return upstream - .directory, .normal, .symbolic_link => { - file.kind = switch (kind) { - .directory => .directory, - .normal => .file, - .symbolic_link => .sym_link, - else => unreachable, - }; - file.mode = try header.mode(); - - // set file attributes if not already set by prefix/extended headers - if (file.size == 0) { - file.size = size; - } - if (file.link_name.len == 0) { - file.link_name = try header.linkName(self.link_name_buffer); - } - if (file.name.len == 0) { - file.name = try header.fullName(self.file_name_buffer); - } - - self.padding = blockPadding(file.size); - self.unread_file_bytes = file.size; - return file; - }, - // Prefix header types - .gnu_long_name => { - file.name = try self.readString(@intCast(size), self.file_name_buffer); - }, - .gnu_long_link => { - file.link_name = try self.readString(@intCast(size), self.link_name_buffer); - }, - .extended_header => { - // Use just attributes from last extended header. - file = self.newFile(); - - var rdr = paxIterator(self.reader, @intCast(size)); - while (try rdr.next()) |attr| { - switch (attr.kind) { - .path => { - file.name = try attr.value(self.file_name_buffer); - }, - .linkpath => { - file.link_name = try attr.value(self.link_name_buffer); - }, - .size => { - var buf: [pax_max_size_attr_len]u8 = undefined; - file.size = try std.fmt.parseInt(u64, try attr.value(&buf), 10); - }, - } - } - }, - // Ignored header type - .global_extended_header => { - self.reader.skipBytes(size, .{}) catch return error.TarHeadersTooBig; - }, - // All other are unsupported header types - else => { - const d = self.diagnostics orelse return error.TarUnsupportedHeader; - try d.errors.append(d.allocator, .{ .unsupported_file_type = .{ - .file_name = try d.allocator.dupe(u8, header.name()), - .file_type = kind, - } }); - if (kind == .gnu_sparse) { - try self.skipGnuSparseExtendedHeaders(header); - } - self.reader.skipBytes(size, .{}) catch return error.TarHeadersTooBig; - }, - } - } - return null; - } - - fn skipGnuSparseExtendedHeaders(self: *Self, header: Header) !void { - var is_extended = header.bytes[482] > 0; - while (is_extended) { - var buf: [Header.SIZE]u8 = undefined; - const n = try self.reader.readAll(&buf); - if (n < Header.SIZE) return error.UnexpectedEndOfStream; - is_extended = buf[504] > 0; - } - } + pub const File = struct { + name: []const u8, // name of file, symlink or directory + link_name: []const u8, // target name of symlink + size: u64 = 0, // size of the file in bytes + mode: u32 = 0, + kind: FileKind = .file, }; -} -/// Pax attributes iterator. -/// Size is length of pax extended header in reader. -fn paxIterator(reader: anytype, size: usize) PaxIterator(@TypeOf(reader)) { - return PaxIterator(@TypeOf(reader)){ - .reader = reader, - .size = size, - }; -} + fn readHeader(self: *Iterator) !?Header { + if (self.padding > 0) { + try self.reader.discardAll(self.padding); + } + const n = try self.reader.readSliceShort(&self.header_buffer); + if (n == 0) return null; + if (n < Header.SIZE) return error.UnexpectedEndOfStream; + const header = Header{ .bytes = self.header_buffer[0..Header.SIZE] }; + if (try header.checkChksum() == 0) return null; + return header; + } + + fn readString(self: *Iterator, size: usize, buffer: []u8) ![]const u8 { + if (size > buffer.len) return error.TarInsufficientBuffer; + const buf = buffer[0..size]; + try self.reader.readSliceAll(buf); + return nullStr(buf); + } + + fn newFile(self: *Iterator) File { + return .{ + .name = self.file_name_buffer[0..0], + .link_name = self.link_name_buffer[0..0], + }; + } + + // Number of padding bytes in the last file block. + fn blockPadding(size: u64) usize { + const block_rounded = std.mem.alignForward(u64, size, Header.SIZE); // size rounded to te block boundary + return @intCast(block_rounded - size); + } + + /// Iterates through the tar archive as if it is a series of files. + /// Internally, the tar format often uses entries (header with optional + /// content) to add meta data that describes the next file. These + /// entries should not normally be visible to the outside. As such, this + /// loop iterates through one or more entries until it collects a all + /// file attributes. + pub fn next(self: *Iterator) !?File { + if (self.unread_file_bytes > 0) { + // If file content was not consumed by caller + try self.reader.discardAll64(self.unread_file_bytes); + self.unread_file_bytes = 0; + } + var file: File = self.newFile(); + + while (try self.readHeader()) |header| { + const kind = header.kind(); + const size: u64 = try header.size(); + self.padding = blockPadding(size); + + switch (kind) { + // File types to return upstream + .directory, .normal, .symbolic_link => { + file.kind = switch (kind) { + .directory => .directory, + .normal => .file, + .symbolic_link => .sym_link, + else => unreachable, + }; + file.mode = try header.mode(); + + // set file attributes if not already set by prefix/extended headers + if (file.size == 0) { + file.size = size; + } + if (file.link_name.len == 0) { + file.link_name = try header.linkName(self.link_name_buffer); + } + if (file.name.len == 0) { + file.name = try header.fullName(self.file_name_buffer); + } + + self.padding = blockPadding(file.size); + self.unread_file_bytes = file.size; + return file; + }, + // Prefix header types + .gnu_long_name => { + file.name = try self.readString(@intCast(size), self.file_name_buffer); + }, + .gnu_long_link => { + file.link_name = try self.readString(@intCast(size), self.link_name_buffer); + }, + .extended_header => { + // Use just attributes from last extended header. + file = self.newFile(); + + var rdr: PaxIterator = .{ + .reader = self.reader, + .size = @intCast(size), + }; + while (try rdr.next()) |attr| { + switch (attr.kind) { + .path => { + file.name = try attr.value(self.file_name_buffer); + }, + .linkpath => { + file.link_name = try attr.value(self.link_name_buffer); + }, + .size => { + var buf: [pax_max_size_attr_len]u8 = undefined; + file.size = try std.fmt.parseInt(u64, try attr.value(&buf), 10); + }, + } + } + }, + // Ignored header type + .global_extended_header => { + self.reader.discardAll64(size) catch return error.TarHeadersTooBig; + }, + // All other are unsupported header types + else => { + const d = self.diagnostics orelse return error.TarUnsupportedHeader; + try d.errors.append(d.allocator, .{ .unsupported_file_type = .{ + .file_name = try d.allocator.dupe(u8, header.name()), + .file_type = kind, + } }); + if (kind == .gnu_sparse) { + try self.skipGnuSparseExtendedHeaders(header); + } + self.reader.discardAll64(size) catch return error.TarHeadersTooBig; + }, + } + } + return null; + } + + pub fn streamRemaining(it: *Iterator, file: File, w: *std.Io.Writer) std.Io.Reader.StreamError!void { + try it.reader.streamExact64(w, file.size); + it.unread_file_bytes = 0; + } + + fn skipGnuSparseExtendedHeaders(self: *Iterator, header: Header) !void { + var is_extended = header.bytes[482] > 0; + while (is_extended) { + var buf: [Header.SIZE]u8 = undefined; + try self.reader.readSliceAll(&buf); + is_extended = buf[504] > 0; + } + } +}; const PaxAttributeKind = enum { path, @@ -533,108 +497,99 @@ const PaxAttributeKind = enum { // maxInt(u64) has 20 chars, base 10 in practice we got 24 chars const pax_max_size_attr_len = 64; -fn PaxIterator(comptime ReaderType: type) type { - return struct { - size: usize, // cumulative size of all pax attributes - reader: ReaderType, - // scratch buffer used for reading attribute length and keyword - scratch: [128]u8 = undefined, +pub const PaxIterator = struct { + size: usize, // cumulative size of all pax attributes + reader: *std.Io.Reader, - const Self = @This(); + const Self = @This(); - const Attribute = struct { - kind: PaxAttributeKind, - len: usize, // length of the attribute value - reader: ReaderType, // reader positioned at value start + const Attribute = struct { + kind: PaxAttributeKind, + len: usize, // length of the attribute value + reader: *std.Io.Reader, // reader positioned at value start - // Copies pax attribute value into destination buffer. - // Must be called with destination buffer of size at least Attribute.len. - pub fn value(self: Attribute, dst: []u8) ![]const u8 { - if (self.len > dst.len) return error.TarInsufficientBuffer; - // assert(self.len <= dst.len); - const buf = dst[0..self.len]; - const n = try self.reader.readAll(buf); - if (n < self.len) return error.UnexpectedEndOfStream; - try validateAttributeEnding(self.reader); - if (hasNull(buf)) return error.PaxNullInValue; - return buf; - } - }; - - // Iterates over pax attributes. Returns known only known attributes. - // Caller has to call value in Attribute, to advance reader across value. - pub fn next(self: *Self) !?Attribute { - // Pax extended header consists of one or more attributes, each constructed as follows: - // "%d %s=%s\n", , , - while (self.size > 0) { - const length_buf = try self.readUntil(' '); - const length = try std.fmt.parseInt(usize, length_buf, 10); // record length in bytes - - const keyword = try self.readUntil('='); - if (hasNull(keyword)) return error.PaxNullInKeyword; - - // calculate value_len - const value_start = length_buf.len + keyword.len + 2; // 2 separators - if (length < value_start + 1 or self.size < length) return error.UnexpectedEndOfStream; - const value_len = length - value_start - 1; // \n separator at end - self.size -= length; - - const kind: PaxAttributeKind = if (eql(keyword, "path")) - .path - else if (eql(keyword, "linkpath")) - .linkpath - else if (eql(keyword, "size")) - .size - else { - try self.reader.skipBytes(value_len, .{}); - try validateAttributeEnding(self.reader); - continue; - }; - if (kind == .size and value_len > pax_max_size_attr_len) { - return error.PaxSizeAttrOverflow; - } - return Attribute{ - .kind = kind, - .len = value_len, - .reader = self.reader, - }; - } - - return null; - } - - fn readUntil(self: *Self, delimiter: u8) ![]const u8 { - var fbs = std.io.fixedBufferStream(&self.scratch); - try self.reader.streamUntilDelimiter(fbs.writer(), delimiter, null); - return fbs.getWritten(); - } - - fn eql(a: []const u8, b: []const u8) bool { - return std.mem.eql(u8, a, b); - } - - fn hasNull(str: []const u8) bool { - return (std.mem.indexOfScalar(u8, str, 0)) != null; - } - - // Checks that each record ends with new line. - fn validateAttributeEnding(reader: ReaderType) !void { - if (try reader.readByte() != '\n') return error.PaxInvalidAttributeEnd; + // Copies pax attribute value into destination buffer. + // Must be called with destination buffer of size at least Attribute.len. + pub fn value(self: Attribute, dst: []u8) ![]const u8 { + if (self.len > dst.len) return error.TarInsufficientBuffer; + // assert(self.len <= dst.len); + const buf = dst[0..self.len]; + const n = try self.reader.readSliceShort(buf); + if (n < self.len) return error.UnexpectedEndOfStream; + try validateAttributeEnding(self.reader); + if (hasNull(buf)) return error.PaxNullInValue; + return buf; } }; -} + + // Iterates over pax attributes. Returns known only known attributes. + // Caller has to call value in Attribute, to advance reader across value. + pub fn next(self: *Self) !?Attribute { + // Pax extended header consists of one or more attributes, each constructed as follows: + // "%d %s=%s\n", , , + while (self.size > 0) { + const length_buf = try self.reader.takeSentinel(' '); + const length = try std.fmt.parseInt(usize, length_buf, 10); // record length in bytes + + const keyword = try self.reader.takeSentinel('='); + if (hasNull(keyword)) return error.PaxNullInKeyword; + + // calculate value_len + const value_start = length_buf.len + keyword.len + 2; // 2 separators + if (length < value_start + 1 or self.size < length) return error.UnexpectedEndOfStream; + const value_len = length - value_start - 1; // \n separator at end + self.size -= length; + + const kind: PaxAttributeKind = if (eql(keyword, "path")) + .path + else if (eql(keyword, "linkpath")) + .linkpath + else if (eql(keyword, "size")) + .size + else { + try self.reader.discardAll(value_len); + try validateAttributeEnding(self.reader); + continue; + }; + if (kind == .size and value_len > pax_max_size_attr_len) { + return error.PaxSizeAttrOverflow; + } + return .{ + .kind = kind, + .len = value_len, + .reader = self.reader, + }; + } + + return null; + } + + fn eql(a: []const u8, b: []const u8) bool { + return std.mem.eql(u8, a, b); + } + + fn hasNull(str: []const u8) bool { + return (std.mem.indexOfScalar(u8, str, 0)) != null; + } + + // Checks that each record ends with new line. + fn validateAttributeEnding(reader: *std.Io.Reader) !void { + if (try reader.takeByte() != '\n') return error.PaxInvalidAttributeEnd; + } +}; /// Saves tar file content to the file systems. -pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions) !void { +pub fn pipeToFileSystem(dir: std.fs.Dir, reader: *std.Io.Reader, options: PipeOptions) !void { var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; - var iter = iterator(reader, .{ + var file_contents_buffer: [1024]u8 = undefined; + var it: Iterator = .init(reader, .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer, .diagnostics = options.diagnostics, }); - while (try iter.next()) |file| { + while (try it.next()) |file| { const file_name = stripComponents(file.name, options.strip_components); if (file_name.len == 0 and file.kind != .directory) { const d = options.diagnostics orelse return error.TarComponentsOutsideStrippedPrefix; @@ -656,7 +611,9 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions) .file => { if (createDirAndFile(dir, file_name, fileMode(file.mode, options))) |fs_file| { defer fs_file.close(); - try file.writeAll(fs_file); + var file_writer = fs_file.writer(&file_contents_buffer); + try it.streamRemaining(file, &file_writer.interface); + try file_writer.interface.flush(); } else |err| { const d = options.diagnostics orelse return err; try d.errors.append(d.allocator, .{ .unable_to_create_file = .{ @@ -826,11 +783,14 @@ test PaxIterator { var buffer: [1024]u8 = undefined; outer: for (cases) |case| { - var stream = std.io.fixedBufferStream(case.data); - var iter = paxIterator(stream.reader(), case.data.len); + var reader: std.Io.Reader = .fixed(case.data); + var it: PaxIterator = .{ + .size = case.data.len, + .reader = &reader, + }; var i: usize = 0; - while (iter.next() catch |err| { + while (it.next() catch |err| { if (case.err) |e| { try testing.expectEqual(e, err); continue; @@ -853,12 +813,6 @@ test PaxIterator { } } -test { - _ = @import("tar/test.zig"); - _ = @import("tar/writer.zig"); - _ = Diagnostics; -} - test "header parse size" { const cases = [_]struct { in: []const u8, @@ -941,7 +895,7 @@ test "create file and symlink" { file.close(); } -test iterator { +test Iterator { // Example tar file is created from this tree structure: // $ tree example // example @@ -962,19 +916,19 @@ test iterator { // example/empty/ const data = @embedFile("tar/testdata/example.tar"); - var fbs = std.io.fixedBufferStream(data); + var reader: std.Io.Reader = .fixed(data); // User provided buffers to the iterator var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; // Create iterator - var iter = iterator(fbs.reader(), .{ + var it: Iterator = .init(&reader, .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer, }); // Iterate over files in example.tar var file_no: usize = 0; - while (try iter.next()) |file| : (file_no += 1) { + while (try it.next()) |file| : (file_no += 1) { switch (file.kind) { .directory => { switch (file_no) { @@ -987,10 +941,10 @@ test iterator { }, .file => { try testing.expectEqualStrings("example/a/file", file.name); - // Read file content var buf: [16]u8 = undefined; - const n = try file.reader().readAll(&buf); - try testing.expectEqualStrings("content\n", buf[0..n]); + var w: std.Io.Writer = .fixed(&buf); + try it.streamRemaining(file, &w); + try testing.expectEqualStrings("content\n", w.buffered()); }, .sym_link => { try testing.expectEqualStrings("example/b/symlink", file.name); @@ -1021,15 +975,14 @@ test pipeToFileSystem { // example/empty/ const data = @embedFile("tar/testdata/example.tar"); - var fbs = std.io.fixedBufferStream(data); - const reader = fbs.reader(); + var reader: std.Io.Reader = .fixed(data); var tmp = testing.tmpDir(.{ .no_follow = true }); defer tmp.cleanup(); const dir = tmp.dir; - // Save tar from `reader` to the file system `dir` - pipeToFileSystem(dir, reader, .{ + // Save tar from reader to the file system `dir` + pipeToFileSystem(dir, &reader, .{ .mode_mode = .ignore, .strip_components = 1, .exclude_empty_directories = true, @@ -1053,8 +1006,7 @@ test pipeToFileSystem { test "pipeToFileSystem root_dir" { const data = @embedFile("tar/testdata/example.tar"); - var fbs = std.io.fixedBufferStream(data); - const reader = fbs.reader(); + var reader: std.Io.Reader = .fixed(data); // with strip_components = 1 { @@ -1063,7 +1015,7 @@ test "pipeToFileSystem root_dir" { var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; defer diagnostics.deinit(); - pipeToFileSystem(tmp.dir, reader, .{ + pipeToFileSystem(tmp.dir, &reader, .{ .strip_components = 1, .diagnostics = &diagnostics, }) catch |err| { @@ -1079,13 +1031,13 @@ test "pipeToFileSystem root_dir" { // with strip_components = 0 { - fbs.reset(); + reader = .fixed(data); var tmp = testing.tmpDir(.{ .no_follow = true }); defer tmp.cleanup(); var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; defer diagnostics.deinit(); - pipeToFileSystem(tmp.dir, reader, .{ + pipeToFileSystem(tmp.dir, &reader, .{ .strip_components = 0, .diagnostics = &diagnostics, }) catch |err| { @@ -1102,45 +1054,42 @@ test "pipeToFileSystem root_dir" { test "findRoot with single file archive" { const data = @embedFile("tar/testdata/22752.tar"); - var fbs = std.io.fixedBufferStream(data); - const reader = fbs.reader(); + var reader: std.Io.Reader = .fixed(data); var tmp = testing.tmpDir(.{}); defer tmp.cleanup(); var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; defer diagnostics.deinit(); - try pipeToFileSystem(tmp.dir, reader, .{ .diagnostics = &diagnostics }); + try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics }); try testing.expectEqualStrings("", diagnostics.root_dir); } test "findRoot without explicit root dir" { const data = @embedFile("tar/testdata/19820.tar"); - var fbs = std.io.fixedBufferStream(data); - const reader = fbs.reader(); + var reader: std.Io.Reader = .fixed(data); var tmp = testing.tmpDir(.{}); defer tmp.cleanup(); var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; defer diagnostics.deinit(); - try pipeToFileSystem(tmp.dir, reader, .{ .diagnostics = &diagnostics }); + try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics }); try testing.expectEqualStrings("root", diagnostics.root_dir); } test "pipeToFileSystem strip_components" { const data = @embedFile("tar/testdata/example.tar"); - var fbs = std.io.fixedBufferStream(data); - const reader = fbs.reader(); + var reader: std.Io.Reader = .fixed(data); var tmp = testing.tmpDir(.{ .no_follow = true }); defer tmp.cleanup(); var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; defer diagnostics.deinit(); - pipeToFileSystem(tmp.dir, reader, .{ + pipeToFileSystem(tmp.dir, &reader, .{ .strip_components = 3, .diagnostics = &diagnostics, }) catch |err| { @@ -1194,13 +1143,12 @@ test "executable bit" { const data = @embedFile("tar/testdata/example.tar"); for ([_]PipeOptions.ModeMode{ .ignore, .executable_bit_only }) |opt| { - var fbs = std.io.fixedBufferStream(data); - const reader = fbs.reader(); + var reader: std.Io.Reader = .fixed(data); var tmp = testing.tmpDir(.{ .no_follow = true }); //defer tmp.cleanup(); - pipeToFileSystem(tmp.dir, reader, .{ + pipeToFileSystem(tmp.dir, &reader, .{ .strip_components = 1, .exclude_empty_directories = true, .mode_mode = opt, @@ -1226,3 +1174,9 @@ test "executable bit" { } } } + +test { + _ = @import("tar/test.zig"); + _ = Writer; + _ = Diagnostics; +} diff --git a/lib/std/tar/Writer.zig b/lib/std/tar/Writer.zig new file mode 100644 index 0000000000..78baa69d84 --- /dev/null +++ b/lib/std/tar/Writer.zig @@ -0,0 +1,498 @@ +const std = @import("std"); +const assert = std.debug.assert; +const testing = std.testing; +const Writer = @This(); + +const block_size = @sizeOf(Header); + +/// Options for writing file/dir/link. If left empty 0o664 is used for +/// file mode and current time for mtime. +pub const Options = struct { + /// File system permission mode. + mode: u32 = 0, + /// File system modification time. + mtime: u64 = 0, +}; + +underlying_writer: *std.Io.Writer, +prefix: []const u8 = "", +mtime_now: u64 = 0, + +const Error = error{ + WriteFailed, + OctalOverflow, + NameTooLong, +}; + +/// Sets prefix for all other write* method paths. +pub fn setRoot(w: *Writer, root: []const u8) Error!void { + if (root.len > 0) + try w.writeDir(root, .{}); + + w.prefix = root; +} + +pub fn writeDir(w: *Writer, sub_path: []const u8, options: Options) Error!void { + try w.writeHeader(.directory, sub_path, "", 0, options); +} + +pub const WriteFileError = std.Io.Writer.FileError || Error || std.fs.File.GetEndPosError; + +pub fn writeFile( + w: *Writer, + sub_path: []const u8, + file_reader: *std.fs.File.Reader, + stat_mtime: i128, +) WriteFileError!void { + const size = try file_reader.getSize(); + const mtime: u64 = @intCast(@divFloor(stat_mtime, std.time.ns_per_s)); + + var header: Header = .{}; + try w.setPath(&header, sub_path); + try header.setSize(size); + try header.setMtime(mtime); + try header.updateChecksum(); + + try w.underlying_writer.writeAll(@ptrCast((&header)[0..1])); + _ = try w.underlying_writer.sendFileAll(file_reader, .unlimited); + try w.writePadding(size); +} + +pub const WriteFileStreamError = Error || std.Io.Reader.StreamError; + +/// Writes file reading file content from `reader`. Reads exactly `size` bytes +/// from `reader`, or returns `error.EndOfStream`. +pub fn writeFileStream( + w: *Writer, + sub_path: []const u8, + size: u64, + reader: *std.Io.Reader, + options: Options, +) WriteFileStreamError!void { + try w.writeHeader(.regular, sub_path, "", size, options); + try reader.streamExact64(w.underlying_writer, size); + try w.writePadding(size); +} + +/// Writes file using bytes buffer `content` for size and file content. +pub fn writeFileBytes(w: *Writer, sub_path: []const u8, content: []const u8, options: Options) Error!void { + try w.writeHeader(.regular, sub_path, "", content.len, options); + try w.underlying_writer.writeAll(content); + try w.writePadding(content.len); +} + +pub fn writeLink(w: *Writer, sub_path: []const u8, link_name: []const u8, options: Options) Error!void { + try w.writeHeader(.symbolic_link, sub_path, link_name, 0, options); +} + +/// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and +/// default for entry mode . +pub fn writeEntry(w: *Writer, entry: std.fs.Dir.Walker.Entry) Error!void { + switch (entry.kind) { + .directory => { + try w.writeDir(entry.path, .{ .mtime = try entryMtime(entry) }); + }, + .file => { + var file = try entry.dir.openFile(entry.basename, .{}); + defer file.close(); + const stat = try file.stat(); + try w.writeFile(entry.path, file, stat); + }, + .sym_link => { + var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; + const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer); + try w.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) }); + }, + else => { + return error.UnsupportedWalkerEntryKind; + }, + } +} + +fn writeHeader( + w: *Writer, + typeflag: Header.FileType, + sub_path: []const u8, + link_name: []const u8, + size: u64, + options: Options, +) Error!void { + var header = Header.init(typeflag); + try w.setPath(&header, sub_path); + try header.setSize(size); + try header.setMtime(if (options.mtime != 0) options.mtime else w.mtimeNow()); + if (options.mode != 0) + try header.setMode(options.mode); + if (typeflag == .symbolic_link) + header.setLinkname(link_name) catch |err| switch (err) { + error.NameTooLong => try w.writeExtendedHeader(.gnu_long_link, &.{link_name}), + else => return err, + }; + try header.write(w.underlying_writer); +} + +fn mtimeNow(w: *Writer) u64 { + if (w.mtime_now == 0) + w.mtime_now = @intCast(std.time.timestamp()); + return w.mtime_now; +} + +fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 { + const stat = try entry.dir.statFile(entry.basename); + return @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); +} + +/// Writes path in posix header, if don't fit (in name+prefix; 100+155 +/// bytes) writes it in gnu extended header. +fn setPath(w: *Writer, header: *Header, sub_path: []const u8) Error!void { + header.setPath(w.prefix, sub_path) catch |err| switch (err) { + error.NameTooLong => { + // write extended header + const buffers: []const []const u8 = if (w.prefix.len == 0) + &.{sub_path} + else + &.{ w.prefix, "/", sub_path }; + try w.writeExtendedHeader(.gnu_long_name, buffers); + }, + else => return err, + }; +} + +/// Writes gnu extended header: gnu_long_name or gnu_long_link. +fn writeExtendedHeader(w: *Writer, typeflag: Header.FileType, buffers: []const []const u8) Error!void { + var len: usize = 0; + for (buffers) |buf| len += buf.len; + + var header: Header = .init(typeflag); + try header.setSize(len); + try header.write(w.underlying_writer); + for (buffers) |buf| + try w.underlying_writer.writeAll(buf); + try w.writePadding(len); +} + +fn writePadding(w: *Writer, bytes: usize) std.Io.Writer.Error!void { + const pos = bytes % block_size; + if (pos == 0) return; + try w.underlying_writer.splatByteAll(0, block_size - pos); +} + +/// According to the specification, tar should finish with two zero blocks, but +/// "reasonable system must not assume that such a block exists when reading an +/// archive". Therefore, the Zig standard library recommends to not call this +/// function. +pub fn finishPedantically(w: *Writer) std.Io.Writer.Error!void { + try w.underlying_writer.splatByteAll(0, block_size * 2); +} + +/// A struct that is exactly 512 bytes and matches tar file format. This is +/// intended to be used for outputting tar files; for parsing there is +/// `std.tar.Header`. +pub const Header = extern struct { + // This struct was originally copied from + // https://github.com/mattnite/tar/blob/main/src/main.zig which is MIT + // licensed. + // + // The name, linkname, magic, uname, and gname are null-terminated character + // strings. All other fields are zero-filled octal numbers in ASCII. Each + // numeric field of width w contains w minus 1 digits, and a null. + // Reference: https://www.gnu.org/software/tar/manual/html_node/Standard.html + // POSIX header: byte offset + name: [100]u8 = [_]u8{0} ** 100, // 0 + mode: [7:0]u8 = default_mode.file, // 100 + uid: [7:0]u8 = [_:0]u8{0} ** 7, // unused 108 + gid: [7:0]u8 = [_:0]u8{0} ** 7, // unused 116 + size: [11:0]u8 = [_:0]u8{'0'} ** 11, // 124 + mtime: [11:0]u8 = [_:0]u8{'0'} ** 11, // 136 + checksum: [7:0]u8 = [_:0]u8{' '} ** 7, // 148 + typeflag: FileType = .regular, // 156 + linkname: [100]u8 = [_]u8{0} ** 100, // 157 + magic: [6]u8 = [_]u8{ 'u', 's', 't', 'a', 'r', 0 }, // 257 + version: [2]u8 = [_]u8{ '0', '0' }, // 263 + uname: [32]u8 = [_]u8{0} ** 32, // unused 265 + gname: [32]u8 = [_]u8{0} ** 32, // unused 297 + devmajor: [7:0]u8 = [_:0]u8{0} ** 7, // unused 329 + devminor: [7:0]u8 = [_:0]u8{0} ** 7, // unused 337 + prefix: [155]u8 = [_]u8{0} ** 155, // 345 + pad: [12]u8 = [_]u8{0} ** 12, // unused 500 + + pub const FileType = enum(u8) { + regular = '0', + symbolic_link = '2', + directory = '5', + gnu_long_name = 'L', + gnu_long_link = 'K', + }; + + const default_mode = struct { + const file = [_:0]u8{ '0', '0', '0', '0', '6', '6', '4' }; // 0o664 + const dir = [_:0]u8{ '0', '0', '0', '0', '7', '7', '5' }; // 0o775 + const sym_link = [_:0]u8{ '0', '0', '0', '0', '7', '7', '7' }; // 0o777 + const other = [_:0]u8{ '0', '0', '0', '0', '0', '0', '0' }; // 0o000 + }; + + pub fn init(typeflag: FileType) Header { + return .{ + .typeflag = typeflag, + .mode = switch (typeflag) { + .directory => default_mode.dir, + .symbolic_link => default_mode.sym_link, + .regular => default_mode.file, + else => default_mode.other, + }, + }; + } + + pub fn setSize(w: *Header, size: u64) error{OctalOverflow}!void { + try octal(&w.size, size); + } + + fn octal(buf: []u8, value: u64) error{OctalOverflow}!void { + var remainder: u64 = value; + var pos: usize = buf.len; + while (remainder > 0 and pos > 0) { + pos -= 1; + const c: u8 = @as(u8, @intCast(remainder % 8)) + '0'; + buf[pos] = c; + remainder /= 8; + if (pos == 0 and remainder > 0) return error.OctalOverflow; + } + } + + pub fn setMode(w: *Header, mode: u32) error{OctalOverflow}!void { + try octal(&w.mode, mode); + } + + // Integer number of seconds since January 1, 1970, 00:00 Coordinated Universal Time. + // mtime == 0 will use current time + pub fn setMtime(w: *Header, mtime: u64) error{OctalOverflow}!void { + try octal(&w.mtime, mtime); + } + + pub fn updateChecksum(w: *Header) !void { + var checksum: usize = ' '; // other 7 w.checksum bytes are initialized to ' ' + for (std.mem.asBytes(w)) |val| + checksum += val; + try octal(&w.checksum, checksum); + } + + pub fn write(h: *Header, bw: *std.Io.Writer) error{ OctalOverflow, WriteFailed }!void { + try h.updateChecksum(); + try bw.writeAll(std.mem.asBytes(h)); + } + + pub fn setLinkname(w: *Header, link: []const u8) !void { + if (link.len > w.linkname.len) return error.NameTooLong; + @memcpy(w.linkname[0..link.len], link); + } + + pub fn setPath(w: *Header, prefix: []const u8, sub_path: []const u8) !void { + const max_prefix = w.prefix.len; + const max_name = w.name.len; + const sep = std.fs.path.sep_posix; + + if (prefix.len + sub_path.len > max_name + max_prefix or prefix.len > max_prefix) + return error.NameTooLong; + + // both fit into name + if (prefix.len > 0 and prefix.len + sub_path.len < max_name) { + @memcpy(w.name[0..prefix.len], prefix); + w.name[prefix.len] = sep; + @memcpy(w.name[prefix.len + 1 ..][0..sub_path.len], sub_path); + return; + } + + // sub_path fits into name + // there is no prefix or prefix fits into prefix + if (sub_path.len <= max_name) { + @memcpy(w.name[0..sub_path.len], sub_path); + @memcpy(w.prefix[0..prefix.len], prefix); + return; + } + + if (prefix.len > 0) { + @memcpy(w.prefix[0..prefix.len], prefix); + w.prefix[prefix.len] = sep; + } + const prefix_pos = if (prefix.len > 0) prefix.len + 1 else 0; + + // add as much to prefix as you can, must split at / + const prefix_remaining = max_prefix - prefix_pos; + if (std.mem.lastIndexOf(u8, sub_path[0..@min(prefix_remaining, sub_path.len)], &.{'/'})) |sep_pos| { + @memcpy(w.prefix[prefix_pos..][0..sep_pos], sub_path[0..sep_pos]); + if ((sub_path.len - sep_pos - 1) > max_name) return error.NameTooLong; + @memcpy(w.name[0..][0 .. sub_path.len - sep_pos - 1], sub_path[sep_pos + 1 ..]); + return; + } + + return error.NameTooLong; + } + + comptime { + assert(@sizeOf(Header) == 512); + } + + test "setPath" { + const cases = [_]struct { + in: []const []const u8, + out: []const []const u8, + }{ + .{ + .in = &.{ "", "123456789" }, + .out = &.{ "", "123456789" }, + }, + // can fit into name + .{ + .in = &.{ "prefix", "sub_path" }, + .out = &.{ "", "prefix/sub_path" }, + }, + // no more both fits into name + .{ + .in = &.{ "prefix", "0123456789/" ** 8 ++ "basename" }, + .out = &.{ "prefix", "0123456789/" ** 8 ++ "basename" }, + }, + // put as much as you can into prefix the rest goes into name + .{ + .in = &.{ "prefix", "0123456789/" ** 10 ++ "basename" }, + .out = &.{ "prefix/" ++ "0123456789/" ** 9 ++ "0123456789", "basename" }, + }, + + .{ + .in = &.{ "prefix", "0123456789/" ** 15 ++ "basename" }, + .out = &.{ "prefix/" ++ "0123456789/" ** 12 ++ "0123456789", "0123456789/0123456789/basename" }, + }, + .{ + .in = &.{ "prefix", "0123456789/" ** 21 ++ "basename" }, + .out = &.{ "prefix/" ++ "0123456789/" ** 12 ++ "0123456789", "0123456789/" ** 8 ++ "basename" }, + }, + .{ + .in = &.{ "", "012345678/" ** 10 ++ "foo" }, + .out = &.{ "012345678/" ** 9 ++ "012345678", "foo" }, + }, + }; + + for (cases) |case| { + var header = Header.init(.regular); + try header.setPath(case.in[0], case.in[1]); + try testing.expectEqualStrings(case.out[0], str(&header.prefix)); + try testing.expectEqualStrings(case.out[1], str(&header.name)); + } + + const error_cases = [_]struct { + in: []const []const u8, + }{ + // basename can't fit into name (106 characters) + .{ .in = &.{ "zig", "test/cases/compile_errors/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig" } }, + // cant fit into 255 + sep + .{ .in = &.{ "prefix", "0123456789/" ** 22 ++ "basename" } }, + // can fit but sub_path can't be split (there is no separator) + .{ .in = &.{ "prefix", "0123456789" ** 10 ++ "a" } }, + .{ .in = &.{ "prefix", "0123456789" ** 14 ++ "basename" } }, + }; + + for (error_cases) |case| { + var header = Header.init(.regular); + try testing.expectError( + error.NameTooLong, + header.setPath(case.in[0], case.in[1]), + ); + } + } + + // Breaks string on first null character. + fn str(s: []const u8) []const u8 { + for (s, 0..) |c, i| { + if (c == 0) return s[0..i]; + } + return s; + } +}; + +test { + _ = Header; +} + +test "write files" { + const files = [_]struct { + path: []const u8, + content: []const u8, + }{ + .{ .path = "foo", .content = "bar" }, + .{ .path = "a12345678/" ** 10 ++ "foo", .content = "a" ** 511 }, + .{ .path = "b12345678/" ** 24 ++ "foo", .content = "b" ** 512 }, + .{ .path = "c12345678/" ** 25 ++ "foo", .content = "c" ** 513 }, + .{ .path = "d12345678/" ** 51 ++ "foo", .content = "d" ** 1025 }, + .{ .path = "e123456789" ** 11, .content = "e" }, + }; + + var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; + var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; + + // with root + { + const root = "root"; + + var output: std.Io.Writer.Allocating = .init(testing.allocator); + var w: Writer = .{ .underlying_writer = &output.writer }; + defer output.deinit(); + try w.setRoot(root); + for (files) |file| + try w.writeFileBytes(file.path, file.content, .{}); + + var input: std.Io.Reader = .fixed(output.getWritten()); + var it: std.tar.Iterator = .init(&input, .{ + .file_name_buffer = &file_name_buffer, + .link_name_buffer = &link_name_buffer, + }); + + // first entry is directory with prefix + { + const actual = (try it.next()).?; + try testing.expectEqualStrings(root, actual.name); + try testing.expectEqual(std.tar.FileKind.directory, actual.kind); + } + + var i: usize = 0; + while (try it.next()) |actual| { + defer i += 1; + const expected = files[i]; + try testing.expectEqualStrings(root, actual.name[0..root.len]); + try testing.expectEqual('/', actual.name[root.len..][0]); + try testing.expectEqualStrings(expected.path, actual.name[root.len + 1 ..]); + + var content: std.Io.Writer.Allocating = .init(testing.allocator); + defer content.deinit(); + try it.streamRemaining(actual, &content.writer); + try testing.expectEqualSlices(u8, expected.content, content.getWritten()); + } + } + // without root + { + var output: std.Io.Writer.Allocating = .init(testing.allocator); + var w: Writer = .{ .underlying_writer = &output.writer }; + defer output.deinit(); + for (files) |file| { + var content: std.Io.Reader = .fixed(file.content); + try w.writeFileStream(file.path, file.content.len, &content, .{}); + } + + var input: std.Io.Reader = .fixed(output.getWritten()); + var it: std.tar.Iterator = .init(&input, .{ + .file_name_buffer = &file_name_buffer, + .link_name_buffer = &link_name_buffer, + }); + + var i: usize = 0; + while (try it.next()) |actual| { + defer i += 1; + const expected = files[i]; + try testing.expectEqualStrings(expected.path, actual.name); + + var content: std.Io.Writer.Allocating = .init(testing.allocator); + defer content.deinit(); + try it.streamRemaining(actual, &content.writer); + try testing.expectEqualSlices(u8, expected.content, content.getWritten()); + } + try w.finishPedantically(); + } +} diff --git a/lib/std/tar/test.zig b/lib/std/tar/test.zig index 3bcb5af90c..3356baacb5 100644 --- a/lib/std/tar/test.zig +++ b/lib/std/tar/test.zig @@ -18,31 +18,72 @@ const Case = struct { err: ?anyerror = null, // parsing should fail with this error }; -const cases = [_]Case{ - .{ - .data = @embedFile("testdata/gnu.tar"), - .files = &[_]Case.File{ - .{ - .name = "small.txt", - .size = 5, - .mode = 0o640, - }, - .{ - .name = "small2.txt", - .size = 11, - .mode = 0o640, - }, +const gnu_case: Case = .{ + .data = @embedFile("testdata/gnu.tar"), + .files = &[_]Case.File{ + .{ + .name = "small.txt", + .size = 5, + .mode = 0o640, }, - .chksums = &[_][]const u8{ - "e38b27eaccb4391bdec553a7f3ae6b2f", - "c65bd2e50a56a2138bf1716f2fd56fe9", + .{ + .name = "small2.txt", + .size = 11, + .mode = 0o640, }, }, - .{ + .chksums = &[_][]const u8{ + "e38b27eaccb4391bdec553a7f3ae6b2f", + "c65bd2e50a56a2138bf1716f2fd56fe9", + }, +}; + +const gnu_multi_headers_case: Case = .{ + .data = @embedFile("testdata/gnu-multi-hdrs.tar"), + .files = &[_]Case.File{ + .{ + .name = "GNU2/GNU2/long-path-name", + .link_name = "GNU4/GNU4/long-linkpath-name", + .kind = .sym_link, + }, + }, +}; + +const trailing_slash_case: Case = .{ + .data = @embedFile("testdata/trailing-slash.tar"), + .files = &[_]Case.File{ + .{ + .name = "123456789/" ** 30, + .kind = .directory, + }, + }, +}; + +const writer_big_long_case: Case = .{ + // Size in gnu extended format, and name in pax attribute. + .data = @embedFile("testdata/writer-big-long.tar"), + .files = &[_]Case.File{ + .{ + .name = "longname/" ** 15 ++ "16gig.txt", + .size = 16 * 1024 * 1024 * 1024, + .mode = 0o644, + .truncated = true, + }, + }, +}; + +const fuzz1_case: Case = .{ + .data = @embedFile("testdata/fuzz1.tar"), + .err = error.TarInsufficientBuffer, +}; + +test "run test cases" { + try testCase(gnu_case); + try testCase(.{ .data = @embedFile("testdata/sparse-formats.tar"), .err = error.TarUnsupportedHeader, - }, - .{ + }); + try testCase(.{ .data = @embedFile("testdata/star.tar"), .files = &[_]Case.File{ .{ @@ -60,8 +101,8 @@ const cases = [_]Case{ "e38b27eaccb4391bdec553a7f3ae6b2f", "c65bd2e50a56a2138bf1716f2fd56fe9", }, - }, - .{ + }); + try testCase(.{ .data = @embedFile("testdata/v7.tar"), .files = &[_]Case.File{ .{ @@ -79,8 +120,8 @@ const cases = [_]Case{ "e38b27eaccb4391bdec553a7f3ae6b2f", "c65bd2e50a56a2138bf1716f2fd56fe9", }, - }, - .{ + }); + try testCase(.{ .data = @embedFile("testdata/pax.tar"), .files = &[_]Case.File{ .{ @@ -99,13 +140,13 @@ const cases = [_]Case{ .chksums = &[_][]const u8{ "3c382e8f5b6631aa2db52643912ffd4a", }, - }, - .{ + }); + try testCase(.{ // pax attribute don't end with \n .data = @embedFile("testdata/pax-bad-hdr-file.tar"), .err = error.PaxInvalidAttributeEnd, - }, - .{ + }); + try testCase(.{ // size is in pax attribute .data = @embedFile("testdata/pax-pos-size-file.tar"), .files = &[_]Case.File{ @@ -119,8 +160,8 @@ const cases = [_]Case{ .chksums = &[_][]const u8{ "0afb597b283fe61b5d4879669a350556", }, - }, - .{ + }); + try testCase(.{ // has pax records which we are not interested in .data = @embedFile("testdata/pax-records.tar"), .files = &[_]Case.File{ @@ -128,8 +169,8 @@ const cases = [_]Case{ .name = "file", }, }, - }, - .{ + }); + try testCase(.{ // has global records which we are ignoring .data = @embedFile("testdata/pax-global-records.tar"), .files = &[_]Case.File{ @@ -146,8 +187,8 @@ const cases = [_]Case{ .name = "file4", }, }, - }, - .{ + }); + try testCase(.{ .data = @embedFile("testdata/nil-uid.tar"), .files = &[_]Case.File{ .{ @@ -160,8 +201,8 @@ const cases = [_]Case{ .chksums = &[_][]const u8{ "08d504674115e77a67244beac19668f5", }, - }, - .{ + }); + try testCase(.{ // has xattrs and pax records which we are ignoring .data = @embedFile("testdata/xattrs.tar"), .files = &[_]Case.File{ @@ -182,23 +223,14 @@ const cases = [_]Case{ "e38b27eaccb4391bdec553a7f3ae6b2f", "c65bd2e50a56a2138bf1716f2fd56fe9", }, - }, - .{ - .data = @embedFile("testdata/gnu-multi-hdrs.tar"), - .files = &[_]Case.File{ - .{ - .name = "GNU2/GNU2/long-path-name", - .link_name = "GNU4/GNU4/long-linkpath-name", - .kind = .sym_link, - }, - }, - }, - .{ + }); + try testCase(gnu_multi_headers_case); + try testCase(.{ // has gnu type D (directory) and S (sparse) blocks .data = @embedFile("testdata/gnu-incremental.tar"), .err = error.TarUnsupportedHeader, - }, - .{ + }); + try testCase(.{ // should use values only from last pax header .data = @embedFile("testdata/pax-multi-hdrs.tar"), .files = &[_]Case.File{ @@ -208,8 +240,8 @@ const cases = [_]Case{ .kind = .sym_link, }, }, - }, - .{ + }); + try testCase(.{ .data = @embedFile("testdata/gnu-long-nul.tar"), .files = &[_]Case.File{ .{ @@ -217,8 +249,8 @@ const cases = [_]Case{ .mode = 0o644, }, }, - }, - .{ + }); + try testCase(.{ .data = @embedFile("testdata/gnu-utf8.tar"), .files = &[_]Case.File{ .{ @@ -226,8 +258,8 @@ const cases = [_]Case{ .mode = 0o644, }, }, - }, - .{ + }); + try testCase(.{ .data = @embedFile("testdata/gnu-not-utf8.tar"), .files = &[_]Case.File{ .{ @@ -235,33 +267,33 @@ const cases = [_]Case{ .mode = 0o644, }, }, - }, - .{ + }); + try testCase(.{ // null in pax key .data = @embedFile("testdata/pax-nul-xattrs.tar"), .err = error.PaxNullInKeyword, - }, - .{ + }); + try testCase(.{ .data = @embedFile("testdata/pax-nul-path.tar"), .err = error.PaxNullInValue, - }, - .{ + }); + try testCase(.{ .data = @embedFile("testdata/neg-size.tar"), .err = error.TarHeader, - }, - .{ + }); + try testCase(.{ .data = @embedFile("testdata/issue10968.tar"), .err = error.TarHeader, - }, - .{ + }); + try testCase(.{ .data = @embedFile("testdata/issue11169.tar"), .err = error.TarHeader, - }, - .{ + }); + try testCase(.{ .data = @embedFile("testdata/issue12435.tar"), .err = error.TarHeaderChksum, - }, - .{ + }); + try testCase(.{ // has magic with space at end instead of null .data = @embedFile("testdata/invalid-go17.tar"), .files = &[_]Case.File{ @@ -269,8 +301,8 @@ const cases = [_]Case{ .name = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/foo", }, }, - }, - .{ + }); + try testCase(.{ .data = @embedFile("testdata/ustar-file-devs.tar"), .files = &[_]Case.File{ .{ @@ -278,17 +310,9 @@ const cases = [_]Case{ .mode = 0o644, }, }, - }, - .{ - .data = @embedFile("testdata/trailing-slash.tar"), - .files = &[_]Case.File{ - .{ - .name = "123456789/" ** 30, - .kind = .directory, - }, - }, - }, - .{ + }); + try testCase(trailing_slash_case); + try testCase(.{ // Has size in gnu extended format. To represent size bigger than 8 GB. .data = @embedFile("testdata/writer-big.tar"), .files = &[_]Case.File{ @@ -299,120 +323,92 @@ const cases = [_]Case{ .mode = 0o640, }, }, - }, - .{ - // Size in gnu extended format, and name in pax attribute. - .data = @embedFile("testdata/writer-big-long.tar"), - .files = &[_]Case.File{ - .{ - .name = "longname/" ** 15 ++ "16gig.txt", - .size = 16 * 1024 * 1024 * 1024, - .mode = 0o644, - .truncated = true, - }, - }, - }, - .{ - .data = @embedFile("testdata/fuzz1.tar"), - .err = error.TarInsufficientBuffer, - }, - .{ + }); + try testCase(writer_big_long_case); + try testCase(fuzz1_case); + try testCase(.{ .data = @embedFile("testdata/fuzz2.tar"), .err = error.PaxSizeAttrOverflow, - }, -}; + }); +} -// used in test to calculate file chksum -const Md5Writer = struct { - h: std.crypto.hash.Md5 = std.crypto.hash.Md5.init(.{}), - - pub fn writeAll(self: *Md5Writer, buf: []const u8) !void { - self.h.update(buf); - } - - pub fn writeByte(self: *Md5Writer, byte: u8) !void { - self.h.update(&[_]u8{byte}); - } - - pub fn chksum(self: *Md5Writer) [32]u8 { - var s = [_]u8{0} ** 16; - self.h.final(&s); - return std.fmt.bytesToHex(s, .lower); - } -}; - -test "run test cases" { +fn testCase(case: Case) !void { var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; - for (cases) |case| { - var fsb = std.io.fixedBufferStream(case.data); - var iter = tar.iterator(fsb.reader(), .{ - .file_name_buffer = &file_name_buffer, - .link_name_buffer = &link_name_buffer, - }); - var i: usize = 0; - while (iter.next() catch |err| { - if (case.err) |e| { - try testing.expectEqual(e, err); - continue; - } else { - return err; - } - }) |actual| : (i += 1) { - const expected = case.files[i]; - try testing.expectEqualStrings(expected.name, actual.name); - try testing.expectEqual(expected.size, actual.size); - try testing.expectEqual(expected.kind, actual.kind); - try testing.expectEqual(expected.mode, actual.mode); - try testing.expectEqualStrings(expected.link_name, actual.link_name); + var br: std.io.Reader = .fixed(case.data); + var it: tar.Iterator = .init(&br, .{ + .file_name_buffer = &file_name_buffer, + .link_name_buffer = &link_name_buffer, + }); + var i: usize = 0; + while (it.next() catch |err| { + if (case.err) |e| { + try testing.expectEqual(e, err); + return; + } else { + return err; + } + }) |actual| : (i += 1) { + const expected = case.files[i]; + try testing.expectEqualStrings(expected.name, actual.name); + try testing.expectEqual(expected.size, actual.size); + try testing.expectEqual(expected.kind, actual.kind); + try testing.expectEqual(expected.mode, actual.mode); + try testing.expectEqualStrings(expected.link_name, actual.link_name); - if (case.chksums.len > i) { - var md5writer = Md5Writer{}; - try actual.writeAll(&md5writer); - const chksum = md5writer.chksum(); - try testing.expectEqualStrings(case.chksums[i], &chksum); - } else { - if (expected.truncated) { - iter.unread_file_bytes = 0; - } + if (case.chksums.len > i) { + var aw: std.Io.Writer.Allocating = .init(std.testing.allocator); + defer aw.deinit(); + try it.streamRemaining(actual, &aw.writer); + const chksum = std.fmt.bytesToHex(std.crypto.hash.Md5.hashResult(aw.getWritten()), .lower); + try testing.expectEqualStrings(case.chksums[i], &chksum); + } else { + if (expected.truncated) { + it.unread_file_bytes = 0; } } - try testing.expectEqual(case.files.len, i); } + try testing.expectEqual(case.files.len, i); } test "pax/gnu long names with small buffer" { + try testLongNameCase(gnu_multi_headers_case); + try testLongNameCase(trailing_slash_case); + try testLongNameCase(.{ + .data = @embedFile("testdata/fuzz1.tar"), + .err = error.TarInsufficientBuffer, + }); +} + +fn testLongNameCase(case: Case) !void { // should fail with insufficient buffer error var min_file_name_buffer: [256]u8 = undefined; var min_link_name_buffer: [100]u8 = undefined; - const long_name_cases = [_]Case{ cases[11], cases[25], cases[28] }; - for (long_name_cases) |case| { - var fsb = std.io.fixedBufferStream(case.data); - var iter = tar.iterator(fsb.reader(), .{ - .file_name_buffer = &min_file_name_buffer, - .link_name_buffer = &min_link_name_buffer, - }); + var br: std.io.Reader = .fixed(case.data); + var iter: tar.Iterator = .init(&br, .{ + .file_name_buffer = &min_file_name_buffer, + .link_name_buffer = &min_link_name_buffer, + }); - var iter_err: ?anyerror = null; - while (iter.next() catch |err| brk: { - iter_err = err; - break :brk null; - }) |_| {} + var iter_err: ?anyerror = null; + while (iter.next() catch |err| brk: { + iter_err = err; + break :brk null; + }) |_| {} - try testing.expect(iter_err != null); - try testing.expectEqual(error.TarInsufficientBuffer, iter_err.?); - } + try testing.expect(iter_err != null); + try testing.expectEqual(error.TarInsufficientBuffer, iter_err.?); } test "insufficient buffer in Header name filed" { var min_file_name_buffer: [9]u8 = undefined; var min_link_name_buffer: [100]u8 = undefined; - var fsb = std.io.fixedBufferStream(cases[0].data); - var iter = tar.iterator(fsb.reader(), .{ + var br: std.io.Reader = .fixed(gnu_case.data); + var iter: tar.Iterator = .init(&br, .{ .file_name_buffer = &min_file_name_buffer, .link_name_buffer = &min_link_name_buffer, }); @@ -466,21 +462,21 @@ test "should not overwrite existing file" { // This ensures that file is not overwritten. // const data = @embedFile("testdata/overwrite_file.tar"); - var fsb = std.io.fixedBufferStream(data); + var r: std.io.Reader = .fixed(data); // Unpack with strip_components = 1 should fail var root = std.testing.tmpDir(.{}); defer root.cleanup(); try testing.expectError( error.PathAlreadyExists, - tar.pipeToFileSystem(root.dir, fsb.reader(), .{ .mode_mode = .ignore, .strip_components = 1 }), + tar.pipeToFileSystem(root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }), ); // Unpack with strip_components = 0 should pass - fsb.reset(); + r = .fixed(data); var root2 = std.testing.tmpDir(.{}); defer root2.cleanup(); - try tar.pipeToFileSystem(root2.dir, fsb.reader(), .{ .mode_mode = .ignore, .strip_components = 0 }); + try tar.pipeToFileSystem(root2.dir, &r, .{ .mode_mode = .ignore, .strip_components = 0 }); } test "case sensitivity" { @@ -494,12 +490,12 @@ test "case sensitivity" { // 18089/alacritty/Darkermatrix.yml // const data = @embedFile("testdata/18089.tar"); - var fsb = std.io.fixedBufferStream(data); + var r: std.io.Reader = .fixed(data); var root = std.testing.tmpDir(.{}); defer root.cleanup(); - tar.pipeToFileSystem(root.dir, fsb.reader(), .{ .mode_mode = .ignore, .strip_components = 1 }) catch |err| { + tar.pipeToFileSystem(root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }) catch |err| { // on case insensitive fs we fail on overwrite existing file try testing.expectEqual(error.PathAlreadyExists, err); return; diff --git a/lib/std/tar/writer.zig b/lib/std/tar/writer.zig deleted file mode 100644 index 4ced287eec..0000000000 --- a/lib/std/tar/writer.zig +++ /dev/null @@ -1,497 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const testing = std.testing; - -/// Creates tar Writer which will write tar content to the `underlying_writer`. -/// Use setRoot to nest all following entries under single root. If file don't -/// fit into posix header (name+prefix: 100+155 bytes) gnu extented header will -/// be used for long names. Options enables setting file premission mode and -/// mtime. Default is to use current time for mtime and 0o664 for file mode. -pub fn writer(underlying_writer: anytype) Writer(@TypeOf(underlying_writer)) { - return .{ .underlying_writer = underlying_writer }; -} - -pub fn Writer(comptime WriterType: type) type { - return struct { - const block_size = @sizeOf(Header); - const empty_block: [block_size]u8 = [_]u8{0} ** block_size; - - /// Options for writing file/dir/link. If left empty 0o664 is used for - /// file mode and current time for mtime. - pub const Options = struct { - /// File system permission mode. - mode: u32 = 0, - /// File system modification time. - mtime: u64 = 0, - }; - const Self = @This(); - - underlying_writer: WriterType, - prefix: []const u8 = "", - mtime_now: u64 = 0, - - /// Sets prefix for all other write* method paths. - pub fn setRoot(self: *Self, root: []const u8) !void { - if (root.len > 0) - try self.writeDir(root, .{}); - - self.prefix = root; - } - - /// Writes directory. - pub fn writeDir(self: *Self, sub_path: []const u8, opt: Options) !void { - try self.writeHeader(.directory, sub_path, "", 0, opt); - } - - /// Writes file system file. - pub fn writeFile(self: *Self, sub_path: []const u8, file: std.fs.File) !void { - const stat = try file.stat(); - const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); - - var header = Header{}; - try self.setPath(&header, sub_path); - try header.setSize(stat.size); - try header.setMtime(mtime); - try header.write(self.underlying_writer); - - try self.underlying_writer.writeFile(file); - try self.writePadding(stat.size); - } - - /// Writes file reading file content from `reader`. Number of bytes in - /// reader must be equal to `size`. - pub fn writeFileStream(self: *Self, sub_path: []const u8, size: usize, reader: anytype, opt: Options) !void { - try self.writeHeader(.regular, sub_path, "", @intCast(size), opt); - - var counting_reader = std.io.countingReader(reader); - var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init(); - try fifo.pump(counting_reader.reader(), self.underlying_writer); - if (counting_reader.bytes_read != size) return error.WrongReaderSize; - try self.writePadding(size); - } - - /// Writes file using bytes buffer `content` for size and file content. - pub fn writeFileBytes(self: *Self, sub_path: []const u8, content: []const u8, opt: Options) !void { - try self.writeHeader(.regular, sub_path, "", @intCast(content.len), opt); - try self.underlying_writer.writeAll(content); - try self.writePadding(content.len); - } - - /// Writes symlink. - pub fn writeLink(self: *Self, sub_path: []const u8, link_name: []const u8, opt: Options) !void { - try self.writeHeader(.symbolic_link, sub_path, link_name, 0, opt); - } - - /// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and - /// default for entry mode . - pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void { - switch (entry.kind) { - .directory => { - try self.writeDir(entry.path, .{ .mtime = try entryMtime(entry) }); - }, - .file => { - var file = try entry.dir.openFile(entry.basename, .{}); - defer file.close(); - try self.writeFile(entry.path, file); - }, - .sym_link => { - var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; - const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer); - try self.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) }); - }, - else => { - return error.UnsupportedWalkerEntryKind; - }, - } - } - - fn writeHeader( - self: *Self, - typeflag: Header.FileType, - sub_path: []const u8, - link_name: []const u8, - size: u64, - opt: Options, - ) !void { - var header = Header.init(typeflag); - try self.setPath(&header, sub_path); - try header.setSize(size); - try header.setMtime(if (opt.mtime != 0) opt.mtime else self.mtimeNow()); - if (opt.mode != 0) - try header.setMode(opt.mode); - if (typeflag == .symbolic_link) - header.setLinkname(link_name) catch |err| switch (err) { - error.NameTooLong => try self.writeExtendedHeader(.gnu_long_link, &.{link_name}), - else => return err, - }; - try header.write(self.underlying_writer); - } - - fn mtimeNow(self: *Self) u64 { - if (self.mtime_now == 0) - self.mtime_now = @intCast(std.time.timestamp()); - return self.mtime_now; - } - - fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 { - const stat = try entry.dir.statFile(entry.basename); - return @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); - } - - /// Writes path in posix header, if don't fit (in name+prefix; 100+155 - /// bytes) writes it in gnu extended header. - fn setPath(self: *Self, header: *Header, sub_path: []const u8) !void { - header.setPath(self.prefix, sub_path) catch |err| switch (err) { - error.NameTooLong => { - // write extended header - const buffers: []const []const u8 = if (self.prefix.len == 0) - &.{sub_path} - else - &.{ self.prefix, "/", sub_path }; - try self.writeExtendedHeader(.gnu_long_name, buffers); - }, - else => return err, - }; - } - - /// Writes gnu extended header: gnu_long_name or gnu_long_link. - fn writeExtendedHeader(self: *Self, typeflag: Header.FileType, buffers: []const []const u8) !void { - var len: usize = 0; - for (buffers) |buf| - len += buf.len; - - var header = Header.init(typeflag); - try header.setSize(len); - try header.write(self.underlying_writer); - for (buffers) |buf| - try self.underlying_writer.writeAll(buf); - try self.writePadding(len); - } - - fn writePadding(self: *Self, bytes: u64) !void { - const pos: usize = @intCast(bytes % block_size); - if (pos == 0) return; - try self.underlying_writer.writeAll(empty_block[pos..]); - } - - /// Tar should finish with two zero blocks, but 'reasonable system must - /// not assume that such a block exists when reading an archive' (from - /// reference). In practice it is safe to skip this finish. - pub fn finish(self: *Self) !void { - try self.underlying_writer.writeAll(&empty_block); - try self.underlying_writer.writeAll(&empty_block); - } - }; -} - -/// A struct that is exactly 512 bytes and matches tar file format. This is -/// intended to be used for outputting tar files; for parsing there is -/// `std.tar.Header`. -const Header = extern struct { - // This struct was originally copied from - // https://github.com/mattnite/tar/blob/main/src/main.zig which is MIT - // licensed. - // - // The name, linkname, magic, uname, and gname are null-terminated character - // strings. All other fields are zero-filled octal numbers in ASCII. Each - // numeric field of width w contains w minus 1 digits, and a null. - // Reference: https://www.gnu.org/software/tar/manual/html_node/Standard.html - // POSIX header: byte offset - name: [100]u8 = [_]u8{0} ** 100, // 0 - mode: [7:0]u8 = default_mode.file, // 100 - uid: [7:0]u8 = [_:0]u8{0} ** 7, // unused 108 - gid: [7:0]u8 = [_:0]u8{0} ** 7, // unused 116 - size: [11:0]u8 = [_:0]u8{'0'} ** 11, // 124 - mtime: [11:0]u8 = [_:0]u8{'0'} ** 11, // 136 - checksum: [7:0]u8 = [_:0]u8{' '} ** 7, // 148 - typeflag: FileType = .regular, // 156 - linkname: [100]u8 = [_]u8{0} ** 100, // 157 - magic: [6]u8 = [_]u8{ 'u', 's', 't', 'a', 'r', 0 }, // 257 - version: [2]u8 = [_]u8{ '0', '0' }, // 263 - uname: [32]u8 = [_]u8{0} ** 32, // unused 265 - gname: [32]u8 = [_]u8{0} ** 32, // unused 297 - devmajor: [7:0]u8 = [_:0]u8{0} ** 7, // unused 329 - devminor: [7:0]u8 = [_:0]u8{0} ** 7, // unused 337 - prefix: [155]u8 = [_]u8{0} ** 155, // 345 - pad: [12]u8 = [_]u8{0} ** 12, // unused 500 - - pub const FileType = enum(u8) { - regular = '0', - symbolic_link = '2', - directory = '5', - gnu_long_name = 'L', - gnu_long_link = 'K', - }; - - const default_mode = struct { - const file = [_:0]u8{ '0', '0', '0', '0', '6', '6', '4' }; // 0o664 - const dir = [_:0]u8{ '0', '0', '0', '0', '7', '7', '5' }; // 0o775 - const sym_link = [_:0]u8{ '0', '0', '0', '0', '7', '7', '7' }; // 0o777 - const other = [_:0]u8{ '0', '0', '0', '0', '0', '0', '0' }; // 0o000 - }; - - pub fn init(typeflag: FileType) Header { - return .{ - .typeflag = typeflag, - .mode = switch (typeflag) { - .directory => default_mode.dir, - .symbolic_link => default_mode.sym_link, - .regular => default_mode.file, - else => default_mode.other, - }, - }; - } - - pub fn setSize(self: *Header, size: u64) !void { - try octal(&self.size, size); - } - - fn octal(buf: []u8, value: u64) !void { - var remainder: u64 = value; - var pos: usize = buf.len; - while (remainder > 0 and pos > 0) { - pos -= 1; - const c: u8 = @as(u8, @intCast(remainder % 8)) + '0'; - buf[pos] = c; - remainder /= 8; - if (pos == 0 and remainder > 0) return error.OctalOverflow; - } - } - - pub fn setMode(self: *Header, mode: u32) !void { - try octal(&self.mode, mode); - } - - // Integer number of seconds since January 1, 1970, 00:00 Coordinated Universal Time. - // mtime == 0 will use current time - pub fn setMtime(self: *Header, mtime: u64) !void { - try octal(&self.mtime, mtime); - } - - pub fn updateChecksum(self: *Header) !void { - var checksum: usize = ' '; // other 7 self.checksum bytes are initialized to ' ' - for (std.mem.asBytes(self)) |val| - checksum += val; - try octal(&self.checksum, checksum); - } - - pub fn write(self: *Header, output_writer: anytype) !void { - try self.updateChecksum(); - try output_writer.writeAll(std.mem.asBytes(self)); - } - - pub fn setLinkname(self: *Header, link: []const u8) !void { - if (link.len > self.linkname.len) return error.NameTooLong; - @memcpy(self.linkname[0..link.len], link); - } - - pub fn setPath(self: *Header, prefix: []const u8, sub_path: []const u8) !void { - const max_prefix = self.prefix.len; - const max_name = self.name.len; - const sep = std.fs.path.sep_posix; - - if (prefix.len + sub_path.len > max_name + max_prefix or prefix.len > max_prefix) - return error.NameTooLong; - - // both fit into name - if (prefix.len > 0 and prefix.len + sub_path.len < max_name) { - @memcpy(self.name[0..prefix.len], prefix); - self.name[prefix.len] = sep; - @memcpy(self.name[prefix.len + 1 ..][0..sub_path.len], sub_path); - return; - } - - // sub_path fits into name - // there is no prefix or prefix fits into prefix - if (sub_path.len <= max_name) { - @memcpy(self.name[0..sub_path.len], sub_path); - @memcpy(self.prefix[0..prefix.len], prefix); - return; - } - - if (prefix.len > 0) { - @memcpy(self.prefix[0..prefix.len], prefix); - self.prefix[prefix.len] = sep; - } - const prefix_pos = if (prefix.len > 0) prefix.len + 1 else 0; - - // add as much to prefix as you can, must split at / - const prefix_remaining = max_prefix - prefix_pos; - if (std.mem.lastIndexOf(u8, sub_path[0..@min(prefix_remaining, sub_path.len)], &.{'/'})) |sep_pos| { - @memcpy(self.prefix[prefix_pos..][0..sep_pos], sub_path[0..sep_pos]); - if ((sub_path.len - sep_pos - 1) > max_name) return error.NameTooLong; - @memcpy(self.name[0..][0 .. sub_path.len - sep_pos - 1], sub_path[sep_pos + 1 ..]); - return; - } - - return error.NameTooLong; - } - - comptime { - assert(@sizeOf(Header) == 512); - } - - test setPath { - const cases = [_]struct { - in: []const []const u8, - out: []const []const u8, - }{ - .{ - .in = &.{ "", "123456789" }, - .out = &.{ "", "123456789" }, - }, - // can fit into name - .{ - .in = &.{ "prefix", "sub_path" }, - .out = &.{ "", "prefix/sub_path" }, - }, - // no more both fits into name - .{ - .in = &.{ "prefix", "0123456789/" ** 8 ++ "basename" }, - .out = &.{ "prefix", "0123456789/" ** 8 ++ "basename" }, - }, - // put as much as you can into prefix the rest goes into name - .{ - .in = &.{ "prefix", "0123456789/" ** 10 ++ "basename" }, - .out = &.{ "prefix/" ++ "0123456789/" ** 9 ++ "0123456789", "basename" }, - }, - - .{ - .in = &.{ "prefix", "0123456789/" ** 15 ++ "basename" }, - .out = &.{ "prefix/" ++ "0123456789/" ** 12 ++ "0123456789", "0123456789/0123456789/basename" }, - }, - .{ - .in = &.{ "prefix", "0123456789/" ** 21 ++ "basename" }, - .out = &.{ "prefix/" ++ "0123456789/" ** 12 ++ "0123456789", "0123456789/" ** 8 ++ "basename" }, - }, - .{ - .in = &.{ "", "012345678/" ** 10 ++ "foo" }, - .out = &.{ "012345678/" ** 9 ++ "012345678", "foo" }, - }, - }; - - for (cases) |case| { - var header = Header.init(.regular); - try header.setPath(case.in[0], case.in[1]); - try testing.expectEqualStrings(case.out[0], str(&header.prefix)); - try testing.expectEqualStrings(case.out[1], str(&header.name)); - } - - const error_cases = [_]struct { - in: []const []const u8, - }{ - // basename can't fit into name (106 characters) - .{ .in = &.{ "zig", "test/cases/compile_errors/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig" } }, - // cant fit into 255 + sep - .{ .in = &.{ "prefix", "0123456789/" ** 22 ++ "basename" } }, - // can fit but sub_path can't be split (there is no separator) - .{ .in = &.{ "prefix", "0123456789" ** 10 ++ "a" } }, - .{ .in = &.{ "prefix", "0123456789" ** 14 ++ "basename" } }, - }; - - for (error_cases) |case| { - var header = Header.init(.regular); - try testing.expectError( - error.NameTooLong, - header.setPath(case.in[0], case.in[1]), - ); - } - } - - // Breaks string on first null character. - fn str(s: []const u8) []const u8 { - for (s, 0..) |c, i| { - if (c == 0) return s[0..i]; - } - return s; - } -}; - -test { - _ = Header; -} - -test "write files" { - const files = [_]struct { - path: []const u8, - content: []const u8, - }{ - .{ .path = "foo", .content = "bar" }, - .{ .path = "a12345678/" ** 10 ++ "foo", .content = "a" ** 511 }, - .{ .path = "b12345678/" ** 24 ++ "foo", .content = "b" ** 512 }, - .{ .path = "c12345678/" ** 25 ++ "foo", .content = "c" ** 513 }, - .{ .path = "d12345678/" ** 51 ++ "foo", .content = "d" ** 1025 }, - .{ .path = "e123456789" ** 11, .content = "e" }, - }; - - var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; - var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; - - // with root - { - const root = "root"; - - var output = std.ArrayList(u8).init(testing.allocator); - defer output.deinit(); - var wrt = writer(output.writer()); - try wrt.setRoot(root); - for (files) |file| - try wrt.writeFileBytes(file.path, file.content, .{}); - - var input = std.io.fixedBufferStream(output.items); - var iter = std.tar.iterator( - input.reader(), - .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer }, - ); - - // first entry is directory with prefix - { - const actual = (try iter.next()).?; - try testing.expectEqualStrings(root, actual.name); - try testing.expectEqual(std.tar.FileKind.directory, actual.kind); - } - - var i: usize = 0; - while (try iter.next()) |actual| { - defer i += 1; - const expected = files[i]; - try testing.expectEqualStrings(root, actual.name[0..root.len]); - try testing.expectEqual('/', actual.name[root.len..][0]); - try testing.expectEqualStrings(expected.path, actual.name[root.len + 1 ..]); - - var content = std.ArrayList(u8).init(testing.allocator); - defer content.deinit(); - try actual.writeAll(content.writer()); - try testing.expectEqualSlices(u8, expected.content, content.items); - } - } - // without root - { - var output = std.ArrayList(u8).init(testing.allocator); - defer output.deinit(); - var wrt = writer(output.writer()); - for (files) |file| { - var content = std.io.fixedBufferStream(file.content); - try wrt.writeFileStream(file.path, file.content.len, content.reader(), .{}); - } - - var input = std.io.fixedBufferStream(output.items); - var iter = std.tar.iterator( - input.reader(), - .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer }, - ); - - var i: usize = 0; - while (try iter.next()) |actual| { - defer i += 1; - const expected = files[i]; - try testing.expectEqualStrings(expected.path, actual.name); - - var content = std.ArrayList(u8).init(testing.allocator); - defer content.deinit(); - try actual.writeAll(content.writer()); - try testing.expectEqualSlices(u8, expected.content, content.items); - } - try wrt.finish(); - } -} diff --git a/src/Compilation.zig b/src/Compilation.zig index 649288dab2..dfdae8aa14 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -4862,6 +4862,9 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { }; defer tar_file.close(); + var buffer: [1024]u8 = undefined; + var tar_file_writer = tar_file.writer(&buffer); + var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, []const u8) = .empty; defer seen_table.deinit(comp.gpa); @@ -4871,7 +4874,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { var i: usize = 0; while (i < seen_table.count()) : (i += 1) { const mod = seen_table.keys()[i]; - try comp.docsCopyModule(mod, seen_table.values()[i], tar_file); + try comp.docsCopyModule(mod, seen_table.values()[i], &tar_file_writer); const deps = mod.deps.values(); try seen_table.ensureUnusedCapacity(comp.gpa, deps.len); @@ -4879,24 +4882,29 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { } } -fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, tar_file: fs.File) !void { +fn docsCopyModule( + comp: *Compilation, + module: *Package.Module, + name: []const u8, + tar_file_writer: *fs.File.Writer, +) !void { const root = module.root; var mod_dir = d: { const root_dir, const sub_path = root.openInfo(comp.dirs); break :d root_dir.openDir(sub_path, .{ .iterate = true }); } catch |err| { - return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {s}", .{ - root.fmt(comp), @errorName(err), - }); + return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {t}", .{ root.fmt(comp), err }); }; defer mod_dir.close(); var walker = try mod_dir.walk(comp.gpa); defer walker.deinit(); - var archiver = std.tar.writer(tar_file.deprecatedWriter().any()); + var archiver: std.tar.Writer = .{ .underlying_writer = &tar_file_writer.interface }; archiver.prefix = name; + var buffer: [1024]u8 = undefined; + while (try walker.next()) |entry| { switch (entry.kind) { .file => { @@ -4907,14 +4915,17 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, else => continue, } var file = mod_dir.openFile(entry.path, .{}) catch |err| { - return comp.lockAndSetMiscFailure(.docs_copy, "unable to open '{f}{s}': {s}", .{ - root.fmt(comp), entry.path, @errorName(err), + return comp.lockAndSetMiscFailure(.docs_copy, "unable to open {f}{s}: {t}", .{ + root.fmt(comp), entry.path, err, }); }; defer file.close(); - archiver.writeFile(entry.path, file) catch |err| { - return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive '{f}{s}': {s}", .{ - root.fmt(comp), entry.path, @errorName(err), + const stat = try file.stat(); + var file_reader: fs.File.Reader = .initSize(file, &buffer, stat.size); + + archiver.writeFile(entry.path, &file_reader, stat.mtime) catch |err| { + return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive {f}{s}: {t}", .{ + root.fmt(comp), entry.path, err, }); }; } @@ -4926,9 +4937,7 @@ fn workerDocsWasm(comp: *Compilation, parent_prog_node: std.Progress.Node) void workerDocsWasmFallible(comp, prog_node) catch |err| switch (err) { error.SubCompilationFailed => return, // error reported already - else => comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {s}", .{ - @errorName(err), - }), + else => comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {t}", .{err}), }; } diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig index a97b60a17c..69fdfb2d9e 100644 --- a/src/Package/Fetch.zig +++ b/src/Package/Fetch.zig @@ -1197,12 +1197,16 @@ fn unpackResource( }; switch (file_type) { - .tar => return try unpackTarball(f, tmp_directory.handle, resource.reader()), + .tar => { + var adapter = resource.reader().adaptToNewApi(); + return unpackTarball(f, tmp_directory.handle, &adapter.new_interface); + }, .@"tar.gz" => { const reader = resource.reader(); var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader); var dcp = std.compress.gzip.decompressor(br.reader()); - return try unpackTarball(f, tmp_directory.handle, dcp.reader()); + var adapter = dcp.reader().adaptToNewApi(); + return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface); }, .@"tar.xz" => { const gpa = f.arena.child_allocator; @@ -1215,7 +1219,8 @@ fn unpackResource( )); }; defer dcp.deinit(); - return try unpackTarball(f, tmp_directory.handle, dcp.reader()); + var adapter = dcp.reader().adaptToNewApi(); + return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface); }, .@"tar.zst" => { const window_size = std.compress.zstd.DecompressorOptions.default_window_buffer_len; @@ -1225,7 +1230,8 @@ fn unpackResource( var dcp = std.compress.zstd.decompressor(br.reader(), .{ .window_buffer = window_buffer, }); - return try unpackTarball(f, tmp_directory.handle, dcp.reader()); + var adapter = dcp.reader().adaptToNewApi(); + return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface); }, .git_pack => return unpackGitPack(f, tmp_directory.handle, &resource.git) catch |err| switch (err) { error.FetchFailed => return error.FetchFailed, @@ -1239,7 +1245,7 @@ fn unpackResource( } } -fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult { +fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: *std.Io.Reader) RunError!UnpackResult { const eb = &f.error_bundle; const arena = f.arena.allocator(); @@ -1250,10 +1256,10 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackRes .strip_components = 0, .mode_mode = .ignore, .exclude_empty_directories = true, - }) catch |err| return f.fail(f.location_tok, try eb.printString( - "unable to unpack tarball to temporary directory: {s}", - .{@errorName(err)}, - )); + }) catch |err| return f.fail( + f.location_tok, + try eb.printString("unable to unpack tarball to temporary directory: {t}", .{err}), + ); var res: UnpackResult = .{ .root_dir = diagnostics.root_dir }; if (diagnostics.errors.items.len > 0) { From cc334b4ee2c8dcceba4f8c6739207f5ddfa6a358 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 20:54:15 -0700 Subject: [PATCH 27/76] std.tar.Writer: fix 32-bit --- lib/std/tar/Writer.zig | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/std/tar/Writer.zig b/lib/std/tar/Writer.zig index 78baa69d84..4c41251d05 100644 --- a/lib/std/tar/Writer.zig +++ b/lib/std/tar/Writer.zig @@ -55,7 +55,7 @@ pub fn writeFile( try w.underlying_writer.writeAll(@ptrCast((&header)[0..1])); _ = try w.underlying_writer.sendFileAll(file_reader, .unlimited); - try w.writePadding(size); + try w.writePadding64(size); } pub const WriteFileStreamError = Error || std.Io.Reader.StreamError; @@ -71,7 +71,7 @@ pub fn writeFileStream( ) WriteFileStreamError!void { try w.writeHeader(.regular, sub_path, "", size, options); try reader.streamExact64(w.underlying_writer, size); - try w.writePadding(size); + try w.writePadding64(size); } /// Writes file using bytes buffer `content` for size and file content. @@ -172,7 +172,14 @@ fn writeExtendedHeader(w: *Writer, typeflag: Header.FileType, buffers: []const [ } fn writePadding(w: *Writer, bytes: usize) std.Io.Writer.Error!void { - const pos = bytes % block_size; + return writePaddingPos(w, bytes % block_size); +} + +fn writePadding64(w: *Writer, bytes: u64) std.Io.Writer.Error!void { + return writePaddingPos(w, @intCast(bytes % block_size)); +} + +fn writePaddingPos(w: *Writer, pos: usize) std.Io.Writer.Error!void { if (pos == 0) return; try w.underlying_writer.splatByteAll(0, block_size - pos); } From 6ae1bcd8bdf284b28bc708ab6bdafd4e0a5f7ac5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 20:56:03 -0700 Subject: [PATCH 28/76] fix docs wasm std.tar API usage --- lib/docs/wasm/main.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/docs/wasm/main.zig b/lib/docs/wasm/main.zig index 7e9ffa5e4c..d3043cd917 100644 --- a/lib/docs/wasm/main.zig +++ b/lib/docs/wasm/main.zig @@ -772,10 +772,10 @@ export fn decl_type_html(decl_index: Decl.Index) String { const Oom = error{OutOfMemory}; fn unpackInner(tar_bytes: []u8) !void { - var fbs = std.io.fixedBufferStream(tar_bytes); + var reader: std.Io.Reader = .fixed(tar_bytes); var file_name_buffer: [1024]u8 = undefined; var link_name_buffer: [1024]u8 = undefined; - var it = std.tar.iterator(fbs.reader(), .{ + var it: std.tar.Iterator = .init(&reader, .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer, }); @@ -796,7 +796,7 @@ fn unpackInner(tar_bytes: []u8) !void { { gop.value_ptr.* = file; } - const file_bytes = tar_bytes[fbs.pos..][0..@intCast(tar_file.size)]; + const file_bytes = tar_bytes[reader.seek..][0..@intCast(tar_file.size)]; assert(file == try Walk.add_file(file_name, file_bytes)); } } else { From 91640f5f819de5bb6211d6bfa3c778737fa822aa Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jul 2025 21:08:40 -0700 Subject: [PATCH 29/76] give the Reader API adapter a buffer it needs one or else it always asserts --- lib/std/Io.zig | 4 ++-- src/Package/Fetch.zig | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/std/Io.zig b/lib/std/Io.zig index 2380b3abbf..b27217ece0 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -314,11 +314,11 @@ pub fn GenericReader( } /// Helper for bridging to the new `Reader` API while upgrading. - pub fn adaptToNewApi(self: *const Self) Adapter { + pub fn adaptToNewApi(self: *const Self, buffer: []u8) Adapter { return .{ .derp_reader = self.*, .new_interface = .{ - .buffer = &.{}, + .buffer = buffer, .vtable = &.{ .stream = Adapter.stream }, .seek = 0, .end = 0, diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig index 69fdfb2d9e..5d6819149f 100644 --- a/src/Package/Fetch.zig +++ b/src/Package/Fetch.zig @@ -1205,7 +1205,8 @@ fn unpackResource( const reader = resource.reader(); var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader); var dcp = std.compress.gzip.decompressor(br.reader()); - var adapter = dcp.reader().adaptToNewApi(); + var adapter_buffer: [1024]u8 = undefined; + var adapter = dcp.reader().adaptToNewApi(&adapter_buffer); return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface); }, .@"tar.xz" => { @@ -1219,7 +1220,8 @@ fn unpackResource( )); }; defer dcp.deinit(); - var adapter = dcp.reader().adaptToNewApi(); + var adapter_buffer: [1024]u8 = undefined; + var adapter = dcp.reader().adaptToNewApi(&adapter_buffer); return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface); }, .@"tar.zst" => { @@ -1230,7 +1232,8 @@ fn unpackResource( var dcp = std.compress.zstd.decompressor(br.reader(), .{ .window_buffer = window_buffer, }); - var adapter = dcp.reader().adaptToNewApi(); + var adapter_buffer: [1024]u8 = undefined; + var adapter = dcp.reader().adaptToNewApi(&adapter_buffer); return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface); }, .git_pack => return unpackGitPack(f, tmp_directory.handle, &resource.git) catch |err| switch (err) { From 687370237fdd80bf0693679cbc11598f14151f0a Mon Sep 17 00:00:00 2001 From: Matthew Lugg Date: Tue, 22 Jul 2025 04:50:34 -0400 Subject: [PATCH 30/76] llvm: fix switch loop on larger than pointer integer --- src/codegen/llvm.zig | 6 +++--- test/behavior/switch_loop.zig | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index a570dd5ec0..c60b857fd9 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -6050,10 +6050,10 @@ pub const FuncGen = struct { const target_blocks = dispatch_info.case_blocks[0..target_blocks_len]; // Make sure to cast the index to a usize so it's not treated as negative! - const table_index = try self.wip.cast( - .zext, + const table_index = try self.wip.conv( + .unsigned, try self.wip.bin(.@"sub nuw", cond, jmp_table.min.toValue(), ""), - try o.lowerType(pt, Type.usize), + try o.lowerType(pt, .usize), "", ); const target_ptr_ptr = try self.wip.gep( diff --git a/test/behavior/switch_loop.zig b/test/behavior/switch_loop.zig index 98605692be..35cc857b62 100644 --- a/test/behavior/switch_loop.zig +++ b/test/behavior/switch_loop.zig @@ -226,3 +226,28 @@ test "unanalyzed continue with operand" { true => {}, } } + +test "switch loop on larger than pointer integer" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + var entry: @Type(.{ .int = .{ + .signedness = .unsigned, + .bits = @bitSizeOf(usize) + 1, + } }) = undefined; + entry = 0; + loop: switch (entry) { + 0 => { + entry += 1; + continue :loop 1; + }, + 1 => |x| { + entry += 1; + continue :loop x + 1; + }, + 2 => entry += 1, + else => unreachable, + } + try expect(entry == 3); +} From ec5cdb2fe394b6a8ca3d30b7652049f39c1aecdb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 22 Jul 2025 17:06:25 -0700 Subject: [PATCH 31/76] std: fix deprecated writer not handling the buffer --- lib/std/Io.zig | 7 ++++++- lib/std/Io/DeprecatedWriter.zig | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/std/Io.zig b/lib/std/Io.zig index b27217ece0..3f98ec3043 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -419,9 +419,14 @@ pub fn GenericWriter( new_interface: Writer, err: ?Error = null, - fn drain(w: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize { + fn drain(w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { _ = splat; const a: *@This() = @alignCast(@fieldParentPtr("new_interface", w)); + const buffered = w.buffered(); + if (buffered.len != 0) return w.consume(a.derp_writer.write(buffered) catch |err| { + a.err = err; + return error.WriteFailed; + }); return a.derp_writer.write(data[0]) catch |err| { a.err = err; return error.WriteFailed; diff --git a/lib/std/Io/DeprecatedWriter.zig b/lib/std/Io/DeprecatedWriter.zig index 391b985357..81774b357c 100644 --- a/lib/std/Io/DeprecatedWriter.zig +++ b/lib/std/Io/DeprecatedWriter.zig @@ -100,7 +100,12 @@ pub const Adapter = struct { fn drain(w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { _ = splat; - const a: *@This() = @fieldParentPtr("new_interface", w); + const a: *@This() = @alignCast(@fieldParentPtr("new_interface", w)); + const buffered = w.buffered(); + if (buffered.len != 0) return w.consume(a.derp_writer.write(buffered) catch |err| { + a.err = err; + return error.WriteFailed; + }); return a.derp_writer.write(data[0]) catch |err| { a.err = err; return error.WriteFailed; From 11a81bc659aa44caf084046e3e1048a4ca0957a6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 22 Jul 2025 17:07:03 -0700 Subject: [PATCH 32/76] std.tar.Writer: delete ill-advised API dependency on time is sus --- lib/std/tar/Writer.zig | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/lib/std/tar/Writer.zig b/lib/std/tar/Writer.zig index 4c41251d05..f5ebd8f803 100644 --- a/lib/std/tar/Writer.zig +++ b/lib/std/tar/Writer.zig @@ -85,30 +85,6 @@ pub fn writeLink(w: *Writer, sub_path: []const u8, link_name: []const u8, option try w.writeHeader(.symbolic_link, sub_path, link_name, 0, options); } -/// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and -/// default for entry mode . -pub fn writeEntry(w: *Writer, entry: std.fs.Dir.Walker.Entry) Error!void { - switch (entry.kind) { - .directory => { - try w.writeDir(entry.path, .{ .mtime = try entryMtime(entry) }); - }, - .file => { - var file = try entry.dir.openFile(entry.basename, .{}); - defer file.close(); - const stat = try file.stat(); - try w.writeFile(entry.path, file, stat); - }, - .sym_link => { - var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; - const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer); - try w.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) }); - }, - else => { - return error.UnsupportedWalkerEntryKind; - }, - } -} - fn writeHeader( w: *Writer, typeflag: Header.FileType, @@ -120,7 +96,7 @@ fn writeHeader( var header = Header.init(typeflag); try w.setPath(&header, sub_path); try header.setSize(size); - try header.setMtime(if (options.mtime != 0) options.mtime else w.mtimeNow()); + try header.setMtime(options.mtime); if (options.mode != 0) try header.setMode(options.mode); if (typeflag == .symbolic_link) @@ -131,17 +107,6 @@ fn writeHeader( try header.write(w.underlying_writer); } -fn mtimeNow(w: *Writer) u64 { - if (w.mtime_now == 0) - w.mtime_now = @intCast(std.time.timestamp()); - return w.mtime_now; -} - -fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 { - const stat = try entry.dir.statFile(entry.basename); - return @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); -} - /// Writes path in posix header, if don't fit (in name+prefix; 100+155 /// bytes) writes it in gnu extended header. fn setPath(w: *Writer, header: *Header, sub_path: []const u8) Error!void { From 2e8dbcac9ab9f09e0890507c32ea2105c55cbf09 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 22 Jul 2025 17:07:19 -0700 Subject: [PATCH 33/76] zig std: update for new tar I/O API --- lib/compiler/std-docs.zig | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/compiler/std-docs.zig b/lib/compiler/std-docs.zig index b5bc742717..33304b8c5d 100644 --- a/lib/compiler/std-docs.zig +++ b/lib/compiler/std-docs.zig @@ -60,7 +60,9 @@ pub fn main() !void { const should_open_browser = force_open_browser orelse (listen_port == 0); const address = std.net.Address.parseIp("127.0.0.1", listen_port) catch unreachable; - var http_server = try address.listen(.{}); + var http_server = try address.listen(.{ + .reuse_address = true, + }); const port = http_server.listen_address.in.getPort(); const url_with_newline = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port}); std.fs.File.stdout().writeAll(url_with_newline) catch {}; @@ -189,7 +191,11 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void { var walker = try std_dir.walk(gpa); defer walker.deinit(); - var archiver = std.tar.writer(response.writer()); + var adapter_buffer: [500]u8 = undefined; + var response_writer = response.writer().adaptToNewApi(); + response_writer.new_interface.buffer = &adapter_buffer; + + var archiver: std.tar.Writer = .{ .underlying_writer = &response_writer.new_interface }; archiver.prefix = "std"; while (try walker.next()) |entry| { @@ -204,7 +210,13 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void { } var file = try entry.dir.openFile(entry.basename, .{}); defer file.close(); - try archiver.writeFile(entry.path, file); + const stat = try file.stat(); + var file_reader: std.fs.File.Reader = .{ + .file = file, + .interface = std.fs.File.Reader.initInterface(&.{}), + .size = stat.size, + }; + try archiver.writeFile(entry.path, &file_reader, stat.mtime); } { From 6038192fadbd785894368d483e98b9713b746135 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 22 Jul 2025 17:40:12 -0700 Subject: [PATCH 34/76] std.tar: delete function redundant with std.mem --- lib/std/tar/Writer.zig | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/std/tar/Writer.zig b/lib/std/tar/Writer.zig index f5ebd8f803..61ae00b24e 100644 --- a/lib/std/tar/Writer.zig +++ b/lib/std/tar/Writer.zig @@ -346,8 +346,8 @@ pub const Header = extern struct { for (cases) |case| { var header = Header.init(.regular); try header.setPath(case.in[0], case.in[1]); - try testing.expectEqualStrings(case.out[0], str(&header.prefix)); - try testing.expectEqualStrings(case.out[1], str(&header.name)); + try testing.expectEqualStrings(case.out[0], std.mem.sliceTo(&header.prefix, 0)); + try testing.expectEqualStrings(case.out[1], std.mem.sliceTo(&header.name, 0)); } const error_cases = [_]struct { @@ -370,14 +370,6 @@ pub const Header = extern struct { ); } } - - // Breaks string on first null character. - fn str(s: []const u8) []const u8 { - for (s, 0..) |c, i| { - if (c == 0) return s[0..i]; - } - return s; - } }; test { From 4fcb479de95775d056f378fdf8a0b9570bc315b7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 22 Jul 2025 18:42:54 -0700 Subject: [PATCH 35/76] don't forget to advance in the deprecated adapter --- lib/std/Io.zig | 4 +++- lib/std/Io/DeprecatedReader.zig | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/std/Io.zig b/lib/std/Io.zig index 3f98ec3043..a93c31954b 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -334,10 +334,12 @@ pub fn GenericReader( fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize { const a: *@This() = @alignCast(@fieldParentPtr("new_interface", r)); const buf = limit.slice(try w.writableSliceGreedy(1)); - return a.derp_reader.read(buf) catch |err| { + const n = a.derp_reader.read(buf) catch |err| { a.err = err; return error.ReadFailed; }; + w.advance(n); + return n; } }; }; diff --git a/lib/std/Io/DeprecatedReader.zig b/lib/std/Io/DeprecatedReader.zig index f6cb9f61d5..4d51b05148 100644 --- a/lib/std/Io/DeprecatedReader.zig +++ b/lib/std/Io/DeprecatedReader.zig @@ -393,10 +393,12 @@ pub const Adapter = struct { fn stream(r: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize { const a: *@This() = @alignCast(@fieldParentPtr("new_interface", r)); const buf = limit.slice(try w.writableSliceGreedy(1)); - return a.derp_reader.read(buf) catch |err| { + const n = a.derp_reader.read(buf) catch |err| { a.err = err; return error.ReadFailed; }; + w.advance(n); + return n; } }; From a023b9b22b6593ebd5a86736a4a9955840d1bfa1 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 22 Jul 2025 05:29:19 -0400 Subject: [PATCH 36/76] stage1: update zig1.wasm Compiler needs cbe packed union fix. --- stage1/zig1.wasm | Bin 2889638 -> 2897241 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm index b6d4e8ba0024c9817a98487ca46c4f91fff58863..0cc1a56393d2370a2043b0076b3eb90cac9e8e77 100644 GIT binary patch delta 1011042 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

vmK?29PLCwk^d`hgmO4AqCGV3r3 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�dxW^qZPw55dQ+d8PgRI z13WbD$#g~xG$>=nbOJ;(f$qF8W4Zv6{~(g31X^KsMl4H-&(T0&5hr-6gh`+AhlmoR zD~p5UB+x;npf${(+qkD+e!!w{!>hok!N8&@0HPQ`Bhro^L_t^Bf;T)dfqe2pRDnrB z&7ApyDCjsCQP4`}1EN_9>;iMA+dX8Fsed5~I#~gx(h0i#>VSv>6O6q>M1cu()X@eI z&0)s021GNPF>L|S9FU!6N`hugD?r}<0k+|SXqJ+Qf`EV&sQzjYQ(}azsQV+TBw)t0 z2c#3UQdLx`Uf7HYWPxLcSeAl_0x#r*fC)%idc>3%&6tirwRDIn@tQG#oTtER#?%4w zoPZfq3y2mrV`>1=pi;(+sRzVFEciEL`T;V59dsUmv>DSE5J%8))z$h{SF045rOlW? zk*2^7S{=p!=Km2<;8WmoWD%Ih32pFz{NUIj0uDhD&MB1$^u%pZgmSV3u5&78TOL4g%Cy$;p}s@@d9idhwOKzdj}Np1$C zIl1~>yS^?*X2(~PMDL^C;>EdWhJOaRGm5Ca8mk4To1u;T#+aQX)&pB-YD zsei+C?k6nz^?aaYFQ5p{1U!loARdRJIEZ3VkzNMO=u{2;2t$jb~`sG-61 zMpQ`(no&R}kBTbELb8h^D5r`jh=X+MGlKIdRL37tC2=#R384G~$)j?R+yu>{5|CUy zK}@M0Zb^@rl871845*e4F(nBzrYRtvnmO|ZP{DIRG)oC|_|OK?EF~ocUV-W0p^+mn zck-GsEdVKJ(qK9uss!3&3F1LC%PS};@Coby&kn#f@R>2K5Uq#!@PH_&fLJ2RRIeZi zDkeciSd}6>q&`y=fYMx`yUrZJ6(6V>#H}c(zyz*QK;^Kq8Pfw0En>!W2SiJlF@Xwm z1vyCBtRM?5uR+VVLGprTOnbyYd;QqWn09~!K*b@57BFK1C4L1yN1hxrrZ*rVUPqA} zGo~jXrnnx{(W=u!Kz*n_y5CffEhA4ADv&Sn$AX{`kh-5*Nu8abs zqsh%hPePS1YMqEx@-*lcmf z{uwjG;Rm4eGB|<+6&MlM7=r~ImxELp3K&Rn3m7RdI67pjFgP*_gfeg|a0;+XDS&Ee zkX@h+fiuLi1mWpGh;H4Q(ysAcc3%47J!zxJA&pf75Kn~xWIYl>8D<@*ouLh zHsDI?2}}*6z=i3uuUI71aoNtKpkmJa0#y2fnjfswV_vb?)+6nTW^(Lc&2rrE9=;Em z3AFbTb^3k{YnI~-Bo&~7?geOZz=iu$#ld&c>|uqJuQON`n4p`m8O)i!fYhvb582hs z+yIgTuLP)PVlZdw0dXflC7G6hcsp3L9G4*3<2VN@&Ab65y@3^Su-X#VEJaYmZU!sl zyt5uw(1poNjt#8P1KC(0=cT=10p0(@qQR5{N?%N%`j}NZHJcgK5_4>rZvKWv zHV$0IfX+Z-0WGk20V-w~A;k?Me86o$@U}VTAEKb%TDBsni^BuzOEWoc5Xn;Hf|iot zg$$tO$KX{A6U3$`s40oocZh+O7flocca$7K?q>p523!KmIKk}-Sg`C7F=Ltoasud1 zFHnsj2FgYqVxSZ2G?*r^Dhh%NIZzleIf9Cc<*-l!UqA+FxI7TeQV;{pGOd70))#_g zHJDzADsh0!dn2kO=E#!+>U}VnF>xp`g3e(Eb#TBvEheyLB{4ImH=xi4?Vc6^?EnS& znH9A58PZc{0{H`Uj6SF$RALoa$q5P*P=^lYDbP{U;Qg}o8$f*o(9o19sQ-iTH5;f? z1=0!XZZK&ufxN#2$@}0|2iUV3Og}`ycf>3Z%TnM_5EEDh^;;n?J7~;B0er&18&UAy zSdbr)jjG=wV#b7K7HDi4VU{8zsQhIGwJ@JBgSPI2YlRt%kY*;6;~!>Fdle)BZfr6+ zenAodZw`6`7hrNUfVMZ(&6z<wG{}Gm8dO2P3pu!3wU*z|}pA z22%|rC4q{)7Dgq|X=tEEIjE7f2DGvTbkP(@5Zu&Z(O{~8DhG*yTj-#EC1^XhG^CjV zTH6F_A%3U_6;kJ5T{3Xj2GoTD6*k}+mlIMGJ3i^1CJwHhVf`281E97aqZPw75WNT7 z$OP4-tO9c(>mXf0sY{>njF=;%8!sd1+AM6PWj#m&T$VFpFRU4nYeQZnjw7f8%fk(# zK-CdEkqg`g7l0z5(RFD1oEN+wok@df1uHlMZV=4^XBdSn0o^Z*pekhtsL2Fg(y~Pq zvgl@mC}^V?sE`0qu46G4aRfE)0jwkhZcPgqccE?xnpCeY|E zC|o+gYoJ=h!6)P@L3ea6l6h;MygC@9bwfUWJCsBCLxS%VTCl#K|LT) zy{^HuK@8Mc2M4{FBU1_3wcsML0WIi3nPml|$n@BcEYkHC;HgN7RREHVZip%|g4$k8 zjxR*Al(@k~lB@!^f`kIQ0BHLeJOIEauDuWe-9m+sVFFDFK|=?+JNAb#xP$?ZqRe0c zHMkl?piNE>P%~YV>4UI2a|dY5Uj&lnA&KY;G!paK!R`~()#pouV0qL%-{ zB3l0tyc&-~NdOYAJc^9qZQ;mG195oO$Am3WZ($X91a1d{0v25PgF{vT6p35Jlo%a( za+KIv96+}qX)tYIRbU5I)z}g>sNJE#w1ZXPF$*|RGi?DUYH*+`2r7tx5<4qs=nK^I z5`m|3Q2Rjy(gFnEn&qefx_xdVyMmkovp@@zf-Hm*R$vzRz^EXvz$`G8SwTvHSzs-v zf_S|GGpOJIl|)ddYaq8QK`Y!~MkCs{9H4?{0t=`+&&=Qm87P{;0zDHAT$XmQKx0J$ zN^>|eD2icmo-zUVft)w}%2yW0dI2-03ycaZ3L<7qXF#-|8Pf?64La!$M1wk0AX?0f zX%C3zFk{*QqS?)uwt#2}Go}roidEg58QiSVFlPpL(p1fv!JRYEs1T^K6)|H174e{A zU=N5d2B`_^L1R{1KmwZP%%BlAP*nk{GC)<+3P#Y@oDE`3^&s9F@bDU>-zWq1zc7>* zNAw$6G?%)34swh=m8o- z0|gCeQ~`9zC#V*N)}o+F8afKd46el)tr(_(8dZP5BTfrgvK%=D<}yohgMvbbmj$I_ zw1f9@Sdc11(3~kET{0udIIafOlT0v?>Ha@h3>gniZ~Va`q5z&|QUDb@3X%frU`;1b z0R}N^`qm#T>Y=z)F(LI9nYkUAxvd!9AlKHQ@&=Sa8pN|y7{DiUfjXI>+{GerXu9D~ z7MXfh=wLOUf+%Rn7PO8SRQ@u74!Y+8HS9oTog!%FZw_OYA}_Op0u!iaV*~ZkG?*rU zMs7gk@rRkg7pW*Rf+*176dPzR6Ey4x9zq`t3cgYpJT44gY|Q95b$ttH0Z=w*H5+6W`^&Osgb2uIpw)s_3^I-kio&2dd^Sf5 z(7t#!P#2QT(ExP&6UbOr$1UtxpstL-OExA41vY&~7f=AODTtaec_`Ggfrjc8K=lN> z0-NIr2Jr2JZ2F8HpqvBpOaDx$!l=OJc!fbNOF>itO2X51 zezQb^hM#jlleuP0847F)3T8|x3W^GBj!zh}1a>fUD=;cbb1Q%rVu0FMpbI>hc))Xx zY@jNM1$59Fiw2X5KsYD}cod~U6o(=cG@_V6^dDA5R!CGTs(|8y3c@E0Sqh?{DP9F|dXWU(Xve0{SOUs< zOrVO5Re^iD?q3!kM(*iVe_2`?FHHN#q5xaAr}mFUgVBGw|38*Hj6KtJ{CgVNm@>|uD#O~$*gtgvt1;uksaIIz7<;B0GqPqe_DrA0$lAm7pLx0t z6RR;}!}J6uRw>5Y)2o?SRTw*`FJNMoV0<}!CljlU-YeK}5oi$uB<->&aDh&5f{cBG zRxoma9L}J?CGdK>GBc|Z?|KPtZUzMg1x7~=fnD2!m|3}*KnI7jvR(xp9KOqi*=u_p zJ8LS46UWLbwf!FlYacVyi96H#cvufHo}3=Y%PP)zYI-Iwt0EWV+F1oQfyvXS@Umty zKA9fK&#E+CfseHl#y-Qx+QRr`dmuk66C>l3?I8lJYd|!k5bH(|y;+!bCZqlt#1IE~ zU)T}oC)IGORubiWW`rRj6tFoB%q7b3h2CiMO-Q}gr*lB}|fm#43jWHn_>oUYTyAvyi8 zB&#)J+ICARR%=G)4~>(imrJuMG47r|OPV#Farg9#@~q;VN^Fh{0=wB9S*GhLvKmeI zkzv(^NQq4ElVKHL+&z813~Me#NR*cubiy-OJ);8ibOS|J@$GK1ta6M{c@CKT^i?XX zs?(Rtv07-p0^L0WSt#-vx@m#~bWjVEqeHd;vgC9Qc~&Q=LDLiDS=kwPPtTBN&437j z-0i2tDlwf$fmMg`)pSb*R$qvWC}-Oc9Mz%)HjiB)_0Ss7OL>2DQTt&vr6bAa|Iauh1D2<)Ejr^H$c zkrZcx1Q*C?kVTy;V2i+>?Nw%VK(SkOx`+y^pwb)A1}R2eh8fHPFy>4Ia~89}o9XT< ztd5Mkrz1==bAAH~HAY>AxnQNt3XHl8^AODW2<8F=b0LDc2xP3XD%e;=XsAwKt;)*J z_-6WUh|EQKR#8|;OR2G%FrJw1ug0p+_;h-`8fyaM@97WJSfvFD8x|}+z z0^^bC_Uf!!&PPG(9Ck2+PBohgT1lk9<|qTIg;)eOF>@=iflC<28_Zb>kOTACKxgl; zYB1ekR$_-Ay|YH0)zbvM9%OMusRtpuO70+TrDSlta(}v}2CEk1%jqE+tfoR&85LOd z89y*9F@e@KDX<7!pFUfIRbKo$BSh~DWW5jWPrs*JVl`zvHhmL_IzIh{5o;~u z@#$&CtmTZyr{6PXt!F&GJB}v`hRo} z+yUt^Le|6VxCG7Oz9-Yf9i>s#Y(P`95~PL|Rm~nWHS0iXWCf;Av1Jt$LJpzRAPIr# zzZ_T-r%TweiZf+M;8L*raYgVXUgNEatU7pDTV;}sNLoQ_YPO#kM<+QGb{ankfgN7fdm z>)WQYJF$kNxuAag(`n+4rU?+%R4(_TEK^_z!B2|UKIIr&!*Qqvu;E4SMpBvzUPu!hxayGqeOy1x-QA7V13heKfE1laaptfLTLaR<7LpS4rZ;-9I-&&` z+jCHm$xW~EW0hiSeKk$oQE>Vn5F0tX*L$++Fg@Qk{jMjg0@LTM)Bk(2x}%w+F%6_w z7CHVz6j(3{`^~SWpY>v`;QYes2&z?DXHWO@W>t}U`wz71oQH|qkz0||@!j?YXl(`J z9hx?Mf;Vdf^S5ga(+_gVNKQX6frDi_hYzcG{l(uc;)+Z>oZOC}E&uzQz&s9aM^;5v z$0?IrL2~R6xp}<}ARZfp_xn>bh{p=yJzWHrV}bBqodfG*hVbrpfX!rrn0XT9OwjQT zjw~P>w$Jln6$I6M8+_pmRe)!92x*ytgL4YT7Plwy&|an9>$$n)_EObTo$ zwagZfycDt-{3!D0K=K-JdC&?8)N1M*NP#?DfdUg+H8=ImG;v3iYEBTvg3Ta#VPyS0 zDDuZZ@^A;#gOQh*W)94PX0-cA#DL~$THiu`Vnydkm!m_bw0D2;+QAT^2t z29A=TfgDhOP=N)-kluIG_xQ7Rv!A`(B<{HE)O5c9aF#%dK`o~Kchf%vu!`{^*QF4B zxx$Rxpr-V6@IE)kBMe!NyS7Z963D8-7&v`zAgdmu*Yr1mtks&=Sd`eo?FrD00}6}+ z*I5)86xgj99Y6yyObX17D;gR=-Sw2|6M|Tc8E;HK62z)5c#TDg3q{xTKS8X~aua&s zJEvJeqcNZCqgbR$IeR(e>n0O$&LMBWP zj$l;|=Qn3gP+)d^Aq1MyW`gbYV0Jtr44oAK&9^b_0S#_LPT$`mtiY_mZ_c~|M6;SP z?Eulxlg&4PlNcHiA{69=wi%S%XOiv#7=$oz`#cIs| z;S;>a#_agw)AZaZRwqXO=^LV0<&=397zK904iX1-F+n*}fl*)sCurd`$a`$lKSr?% zYx03clR;yO8#$FAYl=`+Gdq4@0PW|PI$bxKRmuZ&u@&g(0!OASfn(UshwA|O=>Y?1 zyAXo{i#4MHs1#y$Tp*a`_+`fQ{%F=%rZ1nSzl&y-W_mMYI(H1Ktq;<|6lTX8!k~f% zzPFDV)CK&&uf%W8{6a{98Fq<}Ir9f0NJ=>YN)^z+HD|ssy(flMV!HMn4(@t((5@3! z&_YQbZbcSQNDE~ta)S64id>+A1cpJo8#I_qlt2@ypd~0=SxOwBlSv%^Gk}h?W!GQ= z%>}c7*S>>B;FZ`whA?C)vFI`|I4Wf;@i_AOIx;viD)5vzEt`&WA!`vORt2^!(4f8|3uvPSXtWu$wo`!x9KoekPy?3%x(q*sK{E@?ju(VMZUb#<0ZrC& z!d9*Df|e~YYcTy0GGl5H0i|3GrY}O^8FFR~rVql99Vc@H>J@nucojg)w;M#V1eS9u zL3d0+X4;v+*`3Rb37oa-&6w5*D=>r4^#nyKXc06sI01w6ufQfwP+I5^QQ`+*&Hy(F zRK=YT&QjoCE^vhd$pTR2Q~yUufekdG&ZfWu_CI(-1jsuNgtL^`K&xs%DFfz9HU)$a znIXOc`4H?ZW{3|#B@@I^8cYv_6+pUI2xoy}@`5mkydo^HnG-Z@#|_%~Q}0O79wrLx zf%z6R;SIVwj=_xSiZE#Mi$#$Mv}cr|-il!pC`>ubn7|G{z+lY?4r~T9razz@#H7HM z4LYKDjWD<-S7ZXY8eCk$LjqK#IWj7O7BnH8`UPYvG)O*xVrv2;Xvq;MI6eqN_a8Yj z2!w#b0yL@3?07;LbQc4pHW1js=*XxDO2VL~6QrP?AqXmPT0pT0G7DU2VJ%cxr+X!` z>N75!UX{pd%D83vhD25^Rl@ole|(z$Kao}498{RGII`w|7JuzVDa`OXVR~#5tF}5Q z9f9_%Fl#WK5CDy+u_>^CC@>#X%4jeh5m02EzCMXnl!sMdE2k9bB*ZL5*6A0LSQVjm zGnP0q7737QcQlgScMx`iOOYD_N^Fp+WKbG>AOJdik5vJx0V=^Ft;hzFy(0iFX;?tP z4!RjnkzIjx`nqIRYh}=$I7L&iOo@Cxul)jZJ|MG?@$D zpx+^&$fCdpYI%Sc$}oe%;|wTiu}$|%VRbP8)k$9%K~?PyA;`F=BmQvSm%^%Q0BS;g zX9nqdLbNW)={l*beAa}L0w`ll5COGU4ly#a)+;kO8e}W6s4zG_-#)!Gl{JLv`S$6j zQ&}w;XG~{JV~uBAIz2UwRhRMd^vP+ghZ!$T4^L-x(EiXk3AQH^lz~|UzJsR97(vZ+ zB}RdVpz&M*(15al!1w8g(pmMz7c(hARxyHFuHf}?pu0GhOy|g8t!2D0y)A<^fbsnF z>lv(pjOV9oX0iq`o}XTm$?C^=e){Q5*6B>k*{7F^F&b^3mc^RF2$~#jwXB7l_d$z*6qp6vw!f=o?PFxzIK8%>Rf*Ac z`ht4ag^VYrJ2kKxF>aq;+Q6#8xPAIO2z4AneQ03SW!yepu8~!eaq4u7MpiAx_1lvh zS$UZmCrvMGVZFmRX}Vu4s}|#=>6H*_Nh@nJ{E)#2e4YNPleJQ6KdfQ}w`5ry7cheME(>G{Or2ia#cC0UTOM>I zmjbc|W=94^(6K|HmC7ujy~}$+t>p$L(7tb0ZZXgl0td99W&oebBG58jxSKVaargB6 zZq_KqN7GMrv$`=po-WwK8qfG-dSMT%^K^k8*5v8py{yjDw}4oCds&}K9Dpyd0Bzm| zC0o#L{)3#;4_sqXn0~8|Rgv-B^gn&9Um4F#|J2VK2%4UCoxrN=0J*zO1GEVPv~QOQ zeDET8qb-vrvw{+%z->109U!0!SiwhygIeS5;E5kr1xA6}(>G0ERTX>%zbKIrG&L*m zdiskAtj^p^L7Qbj*VYL1PB)v#>cIGTdig|FdCdhZpf$iupb2?Kfw!Pr{XmO$6<8IR z1wc|f3QVBcP)32b)Avtg6*YUs4mK35kQKD*LnKQHG?2^!TJg6TNfLDaEGVd16&M7z zOy`=!8pil`dg3HjNypdh;A2}rgEMAKF`(IqkX4PUmG(BiCtA_BM)$j&36UZFL7ptfD zPG&XYzp@&9Nv=7Q59mPr)zi;SW|d@IGyTP6)>DjYr*EFZx`J`t^q8rv^%9^3M2>5~ zn;w2JW`T~N)?gCJ7U-G&c`B=(@R?4~?NJv%8^bxW6c`jZ1vX4KnZ{}?_JRpK=)eow z{|!3HgAo)UFQ(T{V^w6Vo4#Ng>olqLpyNbA?E+pR%9Wa~K95y^OGkkPbZ0ZOz?A9hXR*qNL$0yrRpLOy4)RP zfYkIqvsgt0JHY!b1Qb{tZ!lyjfHW%3W))|AJl%3Ot2X1I>8Z1k?D#jEm2dj`*{odJ zkSmpV6%?2S4sn9J0}4Fy;8jfm3T&XI8VYEZ{hQ4y;SSXWTA&BjCC?)VIwcxziX4wD z3SX8-2JCXsY7-X67f>h0&SBMrdwkIxRz=1s(~rzyb>e`UDmz{NA*(1iXfOrI$MVyC z=dyAsLLDKcz=m+V6ptim*@pro1S;mTD#4B4JC9X#`sul>T#`_Y637}QKxRyTH|9?CJIMP+cJJ0X0wr zq5u-)A|T75OdesBa1-Vc!WSEM^I0W%phgOTOqrfMA1O%p&ST}BzI8sUgbGxRAhNZB zAPo>}!OZC&=d;Q)9-1z=fK^Wr>=#}JZXN-sd!`30K=Mo90#+qHsG)qI_PM~J>H8KS zQYs%0=!ibY9#EmLz%Foj`o{&}tS+;VRZ`*zsO!%x0M!omp9#n<(|s4R+A&U@-m{Q3 zi1Fz3`wLm)8Q)L0U&N}ycxZacB32!Bu&Z2oc@;n>a)H)HLsBg-BM&b(Hz-eo`gH>D zr*B`xswfRr%n6UXEO^9C|GbD*(+sKrba@+`iIkW)KzkC9;*}i|c+-OxvnnwjnqIn? z)kXoTj}>l*BXgD#XkP$m`#7_}`{@@Kv&u8RpZ;+%t1J&xF$>tQQcGAhC7~kBAQ4DR zfNsEM7C1CLW(ljN*fFpe3;4hWh)-R4S-7V=ZsZY}zJ3WSpT=>NkOUV29tg9*d>;^h z`qL$>+1wl16&OI38lynV^ysCm%8c#P>zA^c^S2qf?@)618!9%lSJ z-Fi8z3GYE(1<=BC1vUkKfkV@4ma{s8^2x#FtVWEVr+-<_YRC9_y73B_LW?W~7O=vS z6|CW6pFw-E0_@75KnbfKCl!RbUf1G`(^q zt2|@l^qDJJBVGykz_ID~ zSF@&a9OPACRp1x6J>6#wYZ%CbOV+UJfE>oBzy>-E#F15C&-8n1Salf>Pv=?7YQT78 zy6sxlV8$cUC$44n1Sw>81dZ&ng7&9Pf3cQTm;F7PA_osM_w)%XSY@VLtYeL0{5*Z~ zI@T~Nuy^l(4tfPC1_kdM2GC`p33cV@Rx=)-Zn=@wg7L)kqK&Mkj3=kB*vRV5_;LD|jjTybM|h_P-sBORp0|lrjq&jG zshhxoymJ$4tXv~EsN1uGS&0=i%Hp_&IZJ`raSk&mnt26|PB+;M4*J~9tbveF2RT7# z3#%G5z(L#cz#X$S;6v25FbW)-9=L_oobmJY&MmBJLbo{;K|P=ypbeV}oC+)gr=}m= z!WzwZdb;dZRz1eY(|xwG$}{epp0kxzlJW8MwymtzjAy1F+6rE4^0LWmg&99@pSOdRjfw3nuObVN=5&Q)tdi3Y?_yOD2McI`2A6d}!}kmtOdJYq0!OC* z+Qlj-0hUw;NuFRpl081%U^lBg*A4+38w) zSZyHoDMRdQ-NUNPcy{{AJ*)R+xTpFRLcwx#{71S=AZOPOsm~sw#1g zR|zs=$}10Q<0-H?ez-JUT;S~VJ$qU87|%_Ay_Z!TqFolGU1GYyK2}XOsG9hFtW}I( zrr+AfDyMv&7c_Rv3R-NUzzSM_q{Idqp=EV^0A8vzm6=BdWPr?c^Zl%P(qG{BOG|^T z${=t76rfTtK4_2TiTz;z{oK!Lpbl0o4wHqr z4x~X0RcLy^0kED%2(<}9JwCu{!+3VO!a=ZHAcSf<2o~HAq5d3XbznR@-S!ZxHsi(V znTJ^Q*e-(1=Yn`?=OI=FP&gc7Rp$Xag%fA8nlCo*1|{{Jwm6vt&=MHU4%fh*G$kFcI)JUjjU5!RKAm!{7=%4*1XY5M7-tojHg zOvhNm8P86SI>x%w`4TMpz+ENqxu&d+f0#g}0fzvRB%=Zwx4;!%&<+u(ya3$Fu;Z*2 zjAys^9|tAetGtS=Jet#EPP0l*-*S>wK^!cg0csklWGM)MjyxZ<5J`2A zq(e4B^7wRxQ>^lgSEoCig4Fvdr&!e)JEr%XV)bRbI{nruR(r;))1^+c+Av<79)6nD zkqvB#()7YBtRmAlon{qhygL2VX;xo|I5^!3Pd7Njs;zpBSAoTG4J)XH&H~zItHddA zomYWHpK%AP5-YE~0+#}(z|`ptXIQNmuTI~6hSdt812hD5fE6@MiljqMflGl6qC<|K zL4i?$9g_Y*4w}AyFRLgq*2*GT3vn_yuYjG*I-TVltEL1vNnYiJjd03<6Fs}Yjp?rE zSiKo&=RYLqLthNJpA!o3H4rpQ*xHbL2IaY1PThrg1W7TJYh|RM*DP`>#U|s7uu)mUSN%oxXlYX5Smee z#qj}4mJ%oU;3y?lfjiUZUSO5fhmSpj6BekfYGDH3a}2(mR)G@~YM^t@LDsMdOr8Gp z0;?b6?db_OSmo;Bdcpqa0L2z)iw=hZCx`;u2Z|<`c20q*%%DC13+U8rB@P9!tCc`D zoPz}z*b(3ehnew#B@4!U0A@~QRsdNrm6>Py#fz-6j8mt-zsMSAxtj$V=5V)gLmUAz z0Llazzzr&_z%Eb#F?nRBKfKE-#dvr6!b_}K`uBLjQxhPsfbQl6o$t;9T7cOC8ZZHA z2bXma?V!-Gy3DGs21-Lb&?1c8kwM@-C~HBBFm^{q2wxJC=x1LBC;H8oSq;>|`k;jw zQgQ@!6_8TsgXvsXSPdY_O$1^{$Q7_5IagQ>7#~cZdxg~oA}t7!{(Oa193mh95m31b zR&R3^oDnM_)V8av4iHs5)Ag^hs&axl`JjCm52tHgV>M-bI6dJSYX_dh#&{hwu_@t7 zY`l()g$k?+>~2NV7hYf$B{|s%-hd}NBhr)I^bI#y#ZAabWz&D(V3miaF*EYg*!1-` zS!KyhU}?8l)ful&@4Lm?i6<%yZqqR;9PUsQ75DG3ikp)Y70f)G)BoLIm7y>;?%jpQ zh9!yF9kd`D+)3e>UT}+5mhtNJz4urp86Qo*evdUu`7uf%#tEL!0?kJ&u?ai@6)T`x zKjc2^NzgLy2dv_ZkEWYFU@c*MJbm>8Rzt?e)9*fD)#re#6nV%R!gzIh=0jFb#z)gP zgLsdpb39^|QA4r^skUcvJObJofUwHz5vv8`)#=TTSX1Sug2zi46c`2E6&N5Rep8th z7(gRpN;653nz`5z}PgpG&+ov}?VGU>8 zHvPsE){TslrguGMZDQ&dna=l&b&ud=5yY|{76o2`DbsI1V|}Z2iV?JJY7QfK?7Smnx-edtZvKL`PH-xcX?zMI0@J1+d%;>FjxY^8 z8w56vM_}6Yz?ZC|QWHf$r@FcFf=+z{Uqb{s6J8)oV1mf>hL^0;jMJyjdC9udYX;0{ zaGk>j>hyv(Q3-qyRA2+08`{Rk0~w2AO(*+p{1PRTWKK~V~m?n}w zX3+K^0q71ZBylEg1#W@1>Gxi-rZIk)?)sWFFL$xGrDsX@%kU1bT><}MKS9rrJ!ggW8OmTrd)2-gH+A>a_Uh#%i zQx~>D#*>$YTY(*vEV!V@m`i}CVc0=C5116#bs3}tPE9}ehE;(dJS79(O9Pq^nmhgP z8`d<&Gt*PvvRX0D+dls-D<>o4yzMLBu}Uy8&f9+I1M7Pbf72&c8zxW&{=%vW-4Px-ib)zWOU`1ta71=_=n@k2B8S{^mPtJ0s)# z?Ik~1^FZ|DU#uG#Jt4W_$n)6f59m0X_lj}<%?oA;l!ma%2}oBynH z8MjUCV$)!}F?BQB2F54TbC}p{C&L305gr=MbGle2Auts`S| zT)~#5ATH3xqR0T9OaN_8bezJPr6i;v4!Nxuly2ETm)0u@gM_B5vaorBZ!HD|H|L&Y$A*u)2FhqDKLJVzKw-VQR5@C0+Zt!#w_r@Zzd&1ffmqNq2SVwNdbHc zkpjq3+ou0#VUrU_NP@=BzkqN5U=Y|g-Gr4*PXTPy1QyUK!?44}&VY8oYk;=#vI-oT z-o(mQ#n?IhFDqLGZ|c1@S%WK(DCn(oTU)}X!% zWD@A2JkVUp31-k~ILF|@1e!Qm!kOiGqkZ}tPBt@8dt8N!?IYvi>0;b$`Vza@K|%Y4 z3p5R_0QQO!g95w2pXssOY|@N-rdNWfz1yd9vvD#q?wdZJhixI_{^^dqY|4xWrl<0< z88IH5K7*Idgzd$LY2pHhreES^y9a9fZ{lMEwf(oh9?4K?mz^0^d7<{hS z8D1r3(5g?z3*c*18+fvmxExg!*aePE4-#PWV>~*2p#Ym6({KAAr4uP)x+lq;y5x290%JmgAZ&6j{+B19OTg{ z5G4xiU=hcE3<4+M6DFXLn!^VgaN~7cI;%n4kri_L_X3D9OpZ(VK-X6a8 z7sbjI5VgowE`eC-_?7{Oooo0&r%#^%-LiOcx{wf?8sn+ymO^aC!l1c$Uhvc#XiNAH zZqW6j^+If7jJu~#6JoolbQg1A8Y^iE+mH^wc~F9@?~ zFutAsQkhRcet}0Sp<$wcNAgsVthNjM}$p+v2XfP5jJh6 zH*2O}5@FK>t;YK+!luIC0@|(J4|3BCwk&}O(+xz~d}Kd>D|a?shFx5s!x$Ms(`k&b zNv7#5LRe%a6yW?UB}VX7tl*pC8Kz$mWs70lFx^m$O@i^mbT2VB)u0y8`68g=O8{XJ z$i@yf(Be3-=U6}mET|}eT-oOcI!e}YD(L7JXsN@?AO${}MF5mNJEtEMW0R7c2ntWf zsf>yYpv-cB4>U8&z|Sr4Yx);4HcO>POj3@Firk=kK-fU{h`@_E25>PaB+xe9Uz|-` zp*A6Du7BIPy{h(FfCyg*uVr@ zJ*U9w2s+9Uw8vUOi3z@0E>D6@f${nDehD^9wr9*rtO75lpOat{=eYX1S=^Cbpl148 z2{yO-c`Tr13O1kxZ_FSQERPmlT^1 zqM+OZx*=!FpXtw}*nE%+N>0Za%;193RhrEiQBbykJbCBS^cm7@a-foEhcuh9%A4!c z#X$@7m_V^{geA-I3$nl&mMq6V*QfK#ut`f_XrBQ-!HekxvjV3ArzTU5Inx3b1y08& z*SEXMuxT=KEa+_%cjOYNnO-K#rpDMaeXcB<9;kH+y55vU;N0}9vTWLnz0(=x*lHNJ zPcPJB^D){AiaTz!O%{xfhYrsWcSPES#pnnz8+3z%qZgYf0}gmJe^UM&0@Nn0-Gt+dM6y#&%Xn@ zUqk@DpAO0TS>ghQkhx~i&g;{MryDk~iK98kQ4#E%j}2@h)9)#=@iM-h?&!fL&I?LA zpwi_BLzY0_bO9wcdyXY5Tg4rD1Zt*-E3s)Z_DpY7Vl#pS8HWNW$o49+88G%vf2YJ& z3w1N`K?X4!e~_(EVN+#;1ljb$ts^0b4ydsyF}|JtSdC4Yv2QxN zI-5Jk&Xvue6Y*=NhpB@@q(L1PB8=b=*`p2)k+}E^lC-eldtmWcm~xHgQOrf`s5!9X11wUa*oA%+nLC*vg$D!524ny9FM4cNjAy6o>$9nXrsg6auqjM0(`OT8?*qH$!}N=K zY{JtQ>a%HZtX$p-DN8QugOkB;ebi)NZUFbh85Z(90kHzVCzOm3p71q7${!ZfHye?W z0^oL%m;$EznXvJ}$`Q~&C#W2`!2&8r8co<7Iqn~C7I)+msF{AsgiVtj68}G@Ga9go zPUkm8jeY}Da0W^=B_jhttic~-(&nfc=maY`0|_5t1)XGehE;(DbR4<>xIlKyW3!yT z)||~8ngWS0ZQw2;H6YzB;Q={4*OCpCgQ_gq966SJZGx1rC8At`PRJ1E6%VMk7J;3mL4 zM=}Bw?h?`hRCKzPGrS2fJ>D6d;&PnX964^bHABkmtQ=E?r87U58 zHvV8^b3>#!LpPKZH{Fel0D{{|S^$aguL1So*MN`mgw<}K=0K_kn~ZlNen5Q$Q!)rv-OM}C2t z=?j9u0d^_~HNe<{;pyuK7kTLmVg>$i`xt^qUoxR6>8mM}jPwP!lf(dpg#py1*asF^-99G*3oa6_`@y>Qg5`9B<-)(j%ZNNW&#@Q2x}NYu3U zg&UIA45DCZ4P5Y7N0AYJaQjIOKd~5i_)WKo0jD$17&b?aIk1466a!9Ydty-2*^d}_ zI(xuFUOIzVfj`V1$05=gUp!Jevz%TUPezjrZYQbX#GeQcC*ChSkaYHj2b9j764@L% z=ACYUbOpK-;pwc07n05{B%-FXkBRW0yTVIe&_S%jA9Qz;QIp#pUT|^~zQGG>aXjF~ zXmRAGkdg4?)e+8eoSTnsP4V>`SrJ*LgS83o}DxFS7 zE`^wlKiIBjz*F3`Or!*7F+DAljPQY5NkaH++|MS;#|N4r;X|nic<+D*xS1TU@PQJZ zNj95{{2?YKM$na5pcDFE@PSrJf_7>+wti{`ZN06TK0O;8iU+e%L-B7mI284A5TQ67 z6z~E>40A!u#vh6=a#0iC34U3s!kVjTN^HG`)Srmrc04+d)A1daOfAP>7W zfP$JGBix=Ip1zhPIsO=0U4j}z2L!+|B)mreR6HCJz$hMUN)gE)hf6Rc4DJ#VBW(KhGDPw4w+vi7 zaFw%pz|%V$D0>LN)BDq_;DbJDrWclj)BEgl)bxJ69A4&b5JV|+ail%WK!sR=KTr=< z!V8b-Z!1wskKigq@Zqo%Gx*?kk{W#Ps^P)MdqfaYUF{JBl^TjQNTCRtd%PeB55+q# zAroiQJ8Iyy*aJaG`aD~Mnm*svfYYaZEh2s5@D^rJLhQjGlsD^8)8_^uaQd7sUk@um zz^$dMdNP6)Za-7?K#*2!j%% ze;b<{G)se~9GM&sfKDq>09RqVcR?EhTiWmyzmGuy&x27Y;w^qNI@pvMd#3kvpcWD* zI^gj#Lj)yWu7fO*z_0`}WkVc|KVCL>A>!p;7gD?^PuK5e^JUyVy|$ap#|f*Q%#P@V z1hXUDPULuDc03K4_fY^JH~^mCWpdndkO5Q$HXLLCoru2^wCrZbbf+HhRM6=j@H_`7 zf%C2rfyB}h5l}1%^&%A+oC-{iJ4E0`#>{EZBBQbwp6*YGK+^rbUet7dzZYC&2=tLr zWI*h}AF!wTQHzWjqM#x}R0w>3*&I=f8ZCMP8My%N5aiHigoQSqS+;Kz;kjVC%p`CD zqB#jEV7U~S96|SyfF{a0vK)_rj?Q8esF^-t61Ya&H3>DbewzeOtQ}$~iIwPL7-9wf zFnu@$kyv@AA|+Of=|xk?2tK%-qy``Fba?Rb&Jlwo&naS{2|YVwOHURGTOm# zt4Rz+{t4m=OpX)8L4^R)_|hD3Y7CzPuFe+BVH4wMz19S2`|g_q&(<5nLD^b#I?G%( zG32>AmAUYg_(Pn$lnAj7e^BzzN2Eln`6wxI!F)1OBHT_A!*IIwLPSdJk$|Mc770*F z%v*?*5_uJv9A`+tQ{tnS&5#j-s|&#?@&7{9lxV#OoDy>uk&zN1X5$Y&wIzt)3tWN{ zeA}0h5qxkvNen*z21x}b#|BAw5=>kMo>*^P22OqFma&O(Y&Z)Y6@Ie}p86I@f>NKz zbi?JSl}gZZc{64YJ#B8gGCoLfmopu$~3VxUgX zTn$f?)B9J0v-6zQNQn{D{q2x~C&p)>J}Zkr&2;89;KZoA1~oBeu7L;Y11a(X6=DVc zKn+=kNR##JkkX{(^k?f3qkA|iH1w7bqa)l-QiHEy13dV6zequ{^cyKqmfpMpDHH`j zDOVaEil0DPnpL1?y3|H^GMyj|Nv81|QIl!IMsW7txRH$P4Y3D*P-bsNO`i{>A?fpu zG$?&Ok;X`$e>RhmKH)AQHGrpYg$MBTy<5TQ^VC+PkQD^o{)Y(J1)u@|v`Wix8#sMN zZ$nL=)3?FX=LH$^(kH|U{DIoE1Cc)0?m$YP7Sn}yk`a7xJ4p?`b-Uof$NNMEl0NUq zfYRr~T}YuQq`>6(K?a^aFFt7ycLX&dJ$A#>XM-#xefI7~O`q#_gVX2z-DIRsh&}j& za^_yt^m#!RoIa=D-wSI9fxGis`^X4Zxcwvq>&E@?-p=&b`@sqF$9`}P-_}`~i5-{eTADk^`tgck}=}F&>a3FEK)_!ykeh4j~fb?L)A{2wt7ybeN375^g66 zp#~aDoqp#CA~9Z(gCxc?a-hV>e-tS(g09GWAO}y3OV&0(CN9g4g0u93qo`T>&QWjz zs*0NvSrLLS~00(HKpOP+!c zOJ9(mE?CYcJl)|Gn;zq#>G`MF#5jKJX@TVG-c#_T`9dC&t1q2GO`4xi!IS0&1@e+6 z#5(+8d+!Wt*zQmOhpq4y1yJR)M**Yq$v;a*D8pSsVkl4NIuB2<(+$pp^SbSMq?8J} zxAcMnJf-eA3SINEyg^GEyqUZ2Y15^&%ppD_nwQba3(5c8QE| zgWE}3xQX&9f`)n&Q4%Nb9z{ro-=YZ0@F7>&>^T;KE;j)+gJxd=hu6_7sNuzU6`ly^ zC{6!xmyETX5G(Kp+nZ~MU=zQN5^S~C5y3|Ea%#ApBm^7FO>nKEeiPiK@xICC1e#2` z$tK3}=|A||xSHu}Zh`~p+D%v>K^9R9-2x{n=Ua$GH5C-Dfxmo;#40uAA?$88Y@we|m?_4>~04#tRxPIHC;C8NX(_QcD(WOxE%HhxbmzK`(4x%*&Ge7_I&gwX?tCn6t!J<_B=uL%a12;zpPOs&o2-w@cZTQGlXCGo`d~j z{v7O=qUR95%zO^^%jxGxegRz~e@6}Omm8;A#T|tOYNi{#0Q)881*%_Wyny>W4e^WRYp`FkUnBWNT7k*&i8|ab9iaY;kU-7!ORvFx z`STjpFBWg$e%Yfzo?jqV;P;F2JA_~S-hus6{toPyP46Inx%m$47w-2+evwgNa(tr! z_sa{=Vp`CKy`uMEzsz}$>X#eu;eI)yNuFOIR^a!`;g1Nvy!#0Di})w7UxGeC{8IS| z?3dM_ko+R6z~uNv6YiH46I#U`LGdE=8SEFE&!~Q>_zd^U87=bs09$uFRGZ;KAxFCSoj3Hk;0OU*A-zwG!0 z_sbm}^85m^0>57t|3UcW+#j%CzW)LH#po}@FOh%2e(C;;xNZ-At+ zPk+IFk@<(}mxzCGzdX?;&o2-w@cLz{Gdpb4)YLq74aWYd)7h;U&rZF>4%*f-^(Q;1 zuGeN{N35s-wf3gy!M(A0K`W%LpTx+n$=EY}45rM={+Q0k0`kaoa~64jM<4E&YoKZpl=$!I zuwRN4A%2;u2=>cqMI^syfes}%hx_Ff=$3fU&PF38uwP=7Q2jDP3GSCI7UcN_Vg-J` zG^-%|vQ7o;m+LBEzX+*9{9>sJ_Di-Zl3%nzT^9?uU)qj9`}mhs!G8Ipis}~&HMn2) zSd!-#h!yz#qO5`Ni=PJAFXb9wziiTg_~oVs*e~3gNPf`)bzLmset8NSuK>kMktWzL zb2L%?azhjDmm^l>`2}JHe!m>nM)>8OHrOxXI$*y9=|KEasRQ=QY8@oM=z_W~R&c+Z z2l)lG@kdA(>=zqdRKHZ{!u@i_nmoTitibP=WPOBR`t-qm*{%=v%O`z^UnC8{e(^Ry z@{67Vlj9$2xL>-DLx(Lk8G!wA#{ktY5{7WUT(Kd~FAyv6`-RyU;TJt)uwTNB!G4)! z4DriOW3XRd8zcEeUxCT7#TM?DKi8q{m;4qDI~XTuKK$k}AWZqKo2N&{rI*hw33 zuza>b4HkV{aIhrUk`XKrv+)OulszI?T@Gf*?w}Nf>$6+Vt`V+XFB!u@b zcXnmQx6|c3*i{+(rn`8sN7PT?wq|7D(FWa!z@Wgcz$O3@&_Wl`L>B;^84kL>5v~Pv zPB@By8oCx$bO9CadeHG`NcJkDD^WrhP(&9{Ko^il7XaVmf$Tf*MIK;*dZ>S8(Dg{8 z3rHaZCW6CE5?w$7T|gXNKnz_#v>shV1YH1pc?Q_60uXzJ&{YVc3xMypK-R*Ku7VFH zP|pT6l@}%g6W~D?;6@kVLKomf7vMk_U`H3IXG0fZMHc{F{|Zf4kN{vtSHXlXz=$RQ zTBv*AAOq+KFHZ0we4L;YGh3Jx7=%Elh6xBv0Nw4N2RYbk`U-D$0}b%GUA#;Rd*-QH?6xZKGr(BEXMhO^KmwVZc1=|@Fz}KOIj_+4cU==t#{iF}Oanu8L1y%(C zfrk+45$HC>7ofWpKnEr&2nal82b~^S0lH9BgQ);~m4(26kjFvij422Rw1Y0j1Yd9= zAg~jp8Fbnbs{)fiJL7agH%5`^S-$Mrj7O$V^JOn&JTjfbk3FC9$o2|9_FasO)215- zuxBwonLaOo{TSoZ>8XM20gMx;ZwqAK%lK@1Nf3K4R;ZvujBxu)z*+ z107?@g19AUdN8|^@CHWcS^nVD!$7w~ZJ2&0m_43x!gQSw_9cw#re6$UZ)IFRJv@{> zlySrKwV~|VxQ+ZA$_~1CNGuGjHYbc-fw5zHZy37)?^VziBLmQhi;M!>rk@I9*F>B? z35gO>(CL%Rh|?!oL4m0xpdgAkeUcRveoA~Gq3H(U?4Wbne8Sn~#7=^a9J&pP0MPM( z5+FiGpksPNIJ>&gHjvyN&~Zc>ObeJ4m<5hZ-xqS)0$yFdvObh;hr z>`W%d8?4|X9FwEi{g^JaPv0EHo~(HSUt&92FLX5|cVMRvyvE2neBuqz?l z#|t`ZvxO;3fl;7!x_u10I0yKoUS@%7)8k^;)tR2Gncg15?#{S(`uP}kYsTK`+_CKO zjAy53$Fj>YUZ36-%kIk9JN-f|yAtE|>7QfS-5EQlTgS1d>)v2jg5*kGX3zn>p!)nV zlN1jlHv>0Qy#fb|18AulN0tJ!0w`Uak7IXbJU?ADp1qp!@broC?3s)`(|^aaOG|%1 z@(n0{Kd_lGEdlL8dGT$!VFJ4Xh2)EMxn0 zk3@DC#>dlp6WO&H?@ZsB$S%*=KK*7QyFKIf=?jzD-6T)<&k%Q%f$rx7#TJ9(w_{D> zj!&kgu!}J*Sw4MXD!T~dj_JB7?BbxK+!zFQO!rD*_hP#9ak_jOyNb|-kI*wdc@&r( zMY0@ke4KtJg$62J&4h3S>)>{>(w z*WYyZ4Dk!>3LF9#LBu5xahY9_O@Tw;%JiBH_5{ZE>31{O(`62W4$S<(4N5yqjvbI3 z&H+jrpfl|lY%%HU@TQk`e81GNNmdS1}p}>MD8yP^yZZbd*voy$J zSF+r|2u-`LysX>`phcA(OrRTFK~)yWEbyV0bC|P0RTPtB2Q%nUOF;!uf%fU$S?rRL zh-!+-Q6o!16jV(ygKH?z#llRE-~vlvA`1`r20R$gkx`Kubma!ZI?#R~<}6TU$OO6s zM_|JAzgg^(j7O%6XR{mEgUSyLrX`HL3{3S3A_@{tOf5>Fq7-yKD2sz5=;nIR*}gC# zUPe%330&ieLh2z=0dQ?53aQOR1s;J)>I;mZi#tR?H5rpG!vjW8ylODr0F@FNS>U=1 zR0_AVC~$#_JFxF|PQRSZu4E6tyAGrU;YU!xuE4;{pa9y>4p!gEq67;KP>Bci|8$ca zb|sZv%-G~uKqUw~+@@FMum>`3n|>yTU5W9?^!GXJdP0!E$N-;7D*`IaTBhsgvddUQ zDti_O1r~7aF9@n?Uqc23`( z$F9J5V)~6d_VuVW&>v=S4Kynsxdz$-t%1Jfqt`$aAT>~M0dfuW2c-PYr|I(wFl(SI zkQ(S_0i*`fEM!;ZN2zC4e48Fy$lhT12XV9}6DYMHpS1}-W6KfgG)^YRC)cO*6|rkD z_D(l1VpkCQa&5XeC}es-Y3T=BmcZHRnMLfQi7Ds{x#`cohT%+F3w{x`OIc$El3&yo}tSGhi7N;8DlRq5#U9 z5?Km@pv(rTcwBiw;Q@|2fr%^%42q1Pi`JMNVIq!A`Cop6B z#1i&OP(j2BDu`GGF0m`H3S0&qqs=OCWx8T1dy7L0sP4w^U`GZ;aM=U14b(E73bK(A zbX@JzQua8;-P2vl*n=1!O`l%IZXofPO@URHfd_nlCj;n$6%GX^1r~uP)9;tDOHDss z#;!D7x}05L`p+_U#pyof>>-T1r!OpLcW1me{bf134&(jlVioKkMDBr(oLArg9nH<4 zz^DMaBJ9C*sY>=wAQ?u`jjrHZDIqcsrz=#kf8@Ex1`-zl-3#13UACHCSx|u$R6gzj z-7u-h3i8VI@M?Bl#uL+9tJ$3yS8P97%|3-u40hzZKQAMwEaTz@Rpv*g7uT{|Fdm)0 zrj|X=>LjBAhd!eW_yl;+WwM~_-*p+}Ko|6K=rgK7#5I@{6uCg9aDfst=rDd}1$Kd| z=^=IO;fzP7uc>1E@m6NsMQw&+241XZrGC z`sGgcON_gxFY97YV7xz_y_;Q^@xgS{Zgx$^htuP`*^QL{fzl@U416{XrX$P>?4Uax z89|p;fm-1@Iavb7rf=zH?}r!?F?~)CI|sxhRZb32g`>bM05(w(&IOyS#l?}O!0xD# zCGd}Nx?wN7rs#1lXfqzvpC&}3#1crZP`mpzH`%l1pX>}8CMU$%Spvm1dgPOhE6 zE-nF!HBXQhc1Ih~9czqP0w<@hnZPc?cxw8|3G51tRoh=pV9#Y@JU%^QGJ6o??&+&1 zv%h5AJw0y*yVUmeQ`ny|GVb0!Z5sP^5S=%J{Tw6X$?3MUzy?Ik0vk|0i@k@5@x*kF zx$Jq2yQi1WWq-lAdwaq>_WvL~2@BY-F*5F+o-mJHYJ1=!_6v;S;Clmm7{SFilLCX| z8St&Ir>0vhVeb$=4cZ>dn5D=BzQ!KZUztDs@)C9v@hVW!um`MbKIlG*6JX|<>2gci zr4$ddDKI!b0E;w(jN}0s-T-2K01LKFk6g-b$XGSKdnvmC_d-quMn`Zq$eVs_DZ7D& z0s|-;Yyo8hCFEuTw*sT%PVgaJ99fPU0w<;`E@L+ohnzPrqR7hRpuphxgbmc~Viedr zJ#!hmKjWk6JD0KR$bj1h;4T-70t4u-KTxuN!RE-AC9rBb<8pR2@ePd7DiB70OyBp)=>8;Dzl^M@ZU%8w;oAL2<(G~1U^`KjLL8sG!FDIVDqR0X%=XgMu z!$R)F6@cEm3zlR9T}lty`3=$s+R+5Mty=&r1-h>nd_y)!3bcM7T$h5Sz-^TtP)9+5 zL0}IP=m78rMhzww1*YlSR?x-iA2|k%y0(2V{=vLq7E7<)Qr%X3n$u1`h zHU?ZKJ^)3m0<%E-^z@bN35-*wpIFJR%eZy=x0UP}p`DCMpbLi`859|qK%E4ruRzTj zUXTdL<(ojKpz|^)usEu?ftni%%w|kHuzQH7fG;=T1s_2U@*3Ep&8yh;8K+Etyoxoc}ZZ&=Nq#?uZ;N|s}6+%{cw zFS|Zt=XBS->;{bQrae~Xs#$ey+K`&WxCUTb`kCsj11fYD?!An>52Q2iWsu|2&>3 zZpQS2QGr=Oz?}I3qXM%NgE{jIW(8))KaZ#D9%K&$joULTfG#GyHofB@y9(pC>1z+N zOE9)iKX#Bkn6YKL)FF0l#@Ex`4zU{xeTUxg&FuJsF-wWfaoyzU-G|tN1l}^it1|^Q z$KBhezdgim!1#T-++lVNxrQm7pcQEba3$Od;EPpvFe|VLyqlhKnB9o+{q*UF+0CRu z*#a~ax0hMqBiu*^1rEn;Q>VW;%&sEe3kwfkkf^o53nW!+0^QTKkFd+AoMQmBH5IrZ zLD&ZJ>;h2Eal8NyXaz>cjycoU9%olz{5t*IarP|xFYJztiY%bK3o2uoHJE-d3e09f z7y#}BIxb~&;{`=MUb7g#Oh0&(T~_NG6DaC;uqv^zI3NsCV0I*=d&)6(6{zkG5_Kzm z0bfAFuE4Cx+`wwi#G$~Tz$MVitcdW+^#0@QGEAu6w+3qiCE*Vkp(G9qGgbv=(6yh) zT!SnDaQGQcUvh$7m2v&_QzzIx>zkNBwX6YXe3;3R!Cis5i2DQw6H7gFoic;t0q$%i zb`=H%(EZGy{sxZ{cmO~^iBn($ivqg>iy4!G0z0T$kO8$g&6q?K*cCWI?J%BfGbRZI zCQT*=MQ)Hz4n<}Kc1IOZg~jeDk|pqqQGs2bQAbID2{cN>uEC_C$OzJ>GJU~Gc4hVn zOj$}y0{5q%I>|0yp8~NWL4nNCI;QxE9E$yHZZU9B=>>Hx9p zr@WjhZpPFCx*&*MgJ}t)5`!6214xF^ieVmz-T-!017nteKgd@NOiD~F4hjqc?4W@- z1$IY9D~1XMb_I4#<`<0S%mtwQZ^dwj3nZk$^nuZg=>nGmyJG`~8Pg50pyLFlEHkDn zAi)P*S@jC+j!(dYuWSnJju*JH1U9mOtXaT~X3YdHaNuxdIUayy9CpV!Tv>`7j`fO6 zO!c5(Vs=nq0u7F^JFei)Qs7Wv2j5=71Pb^$TpCO)f-In_pIwuA1-BBflS0RG&;U*S zf966ZE>N~`yugsn$Hc{&#u9=f*WN28g3;91<>tfOrFvLTfiRN15sYj4wByik_V~g$}(eG z!39zZv!B870)rbbBY0?A0n#aTJO^?qBLfpR$le)@ppgxBea1ChprV-FaROJCz*ZJ+ zMJ5FZdm9VLiUvjjcF<-CQ0D|(BeE;7nK6abE3hlDnlS}{lC~L>j{>^_k2#Zz0=ojE z8OU3pOke{^p%x143f$(*1`6y7Oa~pAOOzNKpM04mo~6OW0NS7zqX4?G`vFXZ!Hg*a zWIq!qz6A7{92~bCn=S76X!&$;M-}LJA1{OBmil9}#TD2c4YCBbL$3v9fT(O+F&(r+ z5q32NSWto8@dyKk%C2`)#T}WE%mf(;y0ikR4FIwVWdFhY6U7}F1q`IP1&p{I85Ehs zK=+It;0Biv+}sQbAbnf{`=%$IVL#5hVfid^T?PhMUPi|?%cq;2Wj6o~=4PB_*X3Hb zrA0hTmw`dx#q{}S*`>U|2e>=JE+uPb~MRSU>1NLue6>+QPF(|qXL5?N0#G;7c;~)m>A5M z7!(*BSG<@3z1IX(XgXx8FmUe>VUnz80Tpo#jM+*IDh!T24RgRAVR3NmX_$WM9J`e) zvjUR>lLE81v=Xzck~qjlMg=j)B@GM2vlN)8E1qYUu4n$k&A{#0(6B%pOlUAMC@^P% zY-Lhl&Q=6ncEX&c2ugj9EiDVg9hs~c!0k#V0e-MASR5Qr^fZV&s)8EyprpwJx-5>t z(I87v0(|G6q9pi^cSR|%w-lwB9UK`HnH3}*=QJ!3*JPT$`#igRJ%eKln8#qw%)soR z!0f01I^>JN(IHy_azS>M1_L-Km>pTN6hTK+aVs!rGC3&9fG7_|Sr8SVC&CIJNoC;m;hI!+&7H*>;k z25=oVJ>vq{QJ}kZU?mZ_R~Mti4C;pYWGR8KV5%v06ew3>0SV=RE=OiAcH}8nVpd=U z$+HwYa)2b+pfcRxrNj%8 z2vOn$Q7&0Zd?306tc6>FVY8TglRTN>) z;sqHe0Ctvuf@qeKr~-4bBgk3PS6yUZ4_79fr6jB%1Xd=bAd;md0#{ab2}v1l)4VPt zDZ_1=)D`x2PY$qCd9pxP1%rLgs=xsX86L3xJPMpyN}N!af`gVnONn0rs~=unVRusm z=>?m}rNFHKa$%Mdw*m{;U>2~!(*v)v%Ng>3)$o9P$E&~wmS$66&r)JnfY}St3-&t5 z-suajvL^_zD)4~=4Ccn^0@v6xH5n8H6hy(!6)S?!}LYh*sY8i6xb9vz{=Uome`gMu*VGF%W>i5ZkKIl;bXQ4oZt zOpph`X%XBmJ+KOQ$h;ZSXPiZW=sK~Tnx^t2N;m@Dkxtl zFoUWK(7+@ExFA8~Sw{y&W{@6G*Fr%&ONrI-2)HPMWc2B5H`qPvnH>e-Ib1=^kugh2 z4AkKecXY^B6bBFKFgZS8_GfWWU<4Orjt`jsa4~@92OdDmE6~;Oil9rvprsnP+yIwK zOs-1I;4%=bQGp4hk6QsG1Qu{)P+cd?vcROFbxP)k;2y3Q?j z0mc*CZEvwlGx7eK&&Z?)DZU?^ot}D!-I#Ib^qF_q6`6iBPTzBf-Gy<(bjG{v3iWr+ zGJ-~THJCJ%n9Z1OfOw7{&M<;<0chlW0V62Ovnj9(oMLfg%vNF-*vkSM4AEz7I1B0o zGAIZs@C%$~f%SwK6xcznCnm=OpfPMA1$Kd>EDB8ej7QEuRD)+L4x9n?IZrbxusVt` zW+}2VJ1DS%3}*#hL&oITF@4Kjb_MAbrx~*Zj>Aj_-D?UOSzo}IC9rM!`@8H7f(O7R zUtv^Y0S(pi3v8R-aF0Dk03zJO1RlR;71%cY%{}&L{?o9z9u@}$kYLz-_7JlVXTaC* ztzc3Fc?z_166|$WP;-0~lf!)&|+-Dbw+;A3jounh^N>0#<1|?>Y zPgxXLL1U|mV6_|0f(BX@SwJZg5-1&Anxx zRT;NUFMhyoC%)}Li@2jC)K7buzd^?+{>%M1R5(70eP^4Q;7}aSWt}&Iw1@cvS+|Sy5uaQ5;JH%UV~`@ zrxLpclY}C;$0DN02h!NXsl*Br;{mx}M3D<5w%{zIB50a`NmHJA0i%+EIrE28;ILi8 zsK~DX4%t(TS&nJ~@26jX$SzyIqYu{LP>=?-Mh^7BTO&-M=Hec3LWK17cYxRm2IkBg zzzicNg-&zk17{gQ&2`YZ0B0Gqlvo_+yqqfTC;@N4DS=!bE#IBo%{Vi%}~wFnhh zz-xF=8hHvVj=Mq17@>xN+F+n|jt0|#vy5g;8$cO`NrUMKh_eRD*#qLNU<6N{g2wwm zVS-0>Jw!P?U<7u-k|!wG9XFh2%yOJEwHub*nH+njc7q#e%qvcV=Jzg~ge5-5C;wYO zjbTWtzjBfhl(d}VmUIJF&zOhK#sj|lF^Lm z0Ep+XUc)IyfqSr4EQ^Bzrvi&W3lqpG zptM#G$pc_*ET9oe1t!NSoLK@dVZi{JC`IuANEezWQ2De3uO@J5v*t8-9QO~%Zy?YA zIK!w=&jj-P7qAe&856i10B2<;aN!5aS&*4w(3q|x$eAdPVRGDo2qP9y#%I!J+ye<7 z1tu)&HJEmQbHk2Pj7luoj!b$bplDKH(qIDRdr&R}u|aVQu53UB9kQjA|0y|l`6?iq6T9_5pKy(AM zB4|SrXrULoz;8w-2asR~GpOufa$ItjF$v)URsvlKxq0d{~S zz*DLXjEbP$Kr2|X6hS*_Zk%DvQj}zNP*6}%0}Ur>O!s}xu2%mLe6=Mng95W7Q;8xQ zIJ1IAj+h)lWs|4^v%qT>1twjFDV(4IbruK5536U0D{?q~0Z{^=guddA}1(@!RZ)Y;&FgN8C2G>D)1_B2|NLZA~;Ed zw1Kh*B!w_(Fg2WFG-CoK6Qoqa2}>p5mMr*;n z9MIAyP({t;2ohIf7T9SDn$-X$R(-}FXBfe=prF(UsvNelf*NSni~>A--~p>IXBZX1 zE8RYvnLhs|yPn7ekWqr5`^%wjV{$w({ozY?33f=q(lPB7dxA75oR0TB_0Tc|oK6gu3%p?gg=zz*BC~>!BBuhsB8LL#@>K;EM-EUsP>IE{ z-i@UmoP1D>Wq})ehB1p9G{68#i6FD4a5{oVuR!cMoYEju6hSlepjj3sM{o=<3p@iY ztzc1*&jPiJUVthy&>-HAlb`}0?4p`1Go}q7amNj(z&EoqIsQ1wn576R249?F%;E-{ z2~M)I3Q`Kp0?$Eqd;lMN3~n8934qrRy*LdkZk6OfE;26wktG5LSipIPNuTk}X;6L4 z01|$2nh}&E96x|G$tlPvNI=^LUrtYd_?lg={>n*4NR1521_B^0A5JqWf_5SQfM@}& z1Oa(MgXzvmMyTdLFbhE0pa+z4K^lLYW;A2!0P{G^m|DOLPBW$kFoVU636fv9pjkyh zz>Mk38C_8DD8ced11Ld&4hsP1m4o0k-vUZipczFCriSUO->}Qq_kaQsROxqs7@&f= z1;hZ2C^di>pb}0A6n3BtjVPLV85Gz+4L>Hw4v;l03ZT}E5{rVM2GayaP@F=`%3F1g(9PmUo{mxr<2~SW) zR{~9Cg0e9@@vb<_sK~6qqsXPe2O7dqQeeYj98y-Wea9}1oD|s z3?>bx6a{7l`Rpt+rW+s;#|5Vuvp`9}@d1bda?6d=j9H*e3@*Bm(&7(DC3fHxBdjn1 z7au!LF+!Vf^^OxjK?^RQl;jjt6_lX~W(qh=!ByIXGvJn=;|!2WL6J>? z3q)}#2!JSXs@!vm5fZ*TPBAK~f&zNR8Ae4dP_GYEC_!9S56V3PAHmb8;L>XW#1bYA zrURgqp}}QGtaB5{XV>$t5u$h6{Z3;{ZTxOuwoB|Ul z*@7FJ3d&|okd~&Z8PgW9Vy${JCUBe6aRta;NHBn|djJ)d0+8gq25c>;O~zoxv;`Ca zAit~t^>8+Tc%bCG2E+h0JwO#alj8=EVIX5bRXnr?*#a{L+#&#V6Ev7MoS7c-f!&62 z+w_Sa*v%C{DN4}M1T+*1Y0_&jp`_>OFFvrFNgQ5KV>2)bp1Jxhrbls=)I1xQWJ4lRI}oMlu5#~i4s&k6SASw?Op z7D%ynfdRDOOiJJrD4%{fJ^jN+cF}rJ2?px?eSsA(8cd+V2-I$a7DkBj3tj|iFtwaw zR8$06&~OS|a%nLAI1NrLj$Er-Cf>32S}DU)41yJ&^N2T-8^Nxu%+3W^HQsGc!B?hCtEJ){u^&G8@;L77<*)awMLb>vb3l1;%S z#}`=iet?w)pp2^uEdoH919ZskDaI`15&)bN!S&=1P{3<2{W--b0JR^I7r{lq3fx5i z2doGXfE5AkW=xPGKnYd^D8q^XRaglC&a{vc0F-`_N`NhA7$YIwWl++C^s$&gxtGz5 z=>)i41Mg=k!n#;HK*0hs2UO`mi-0{?ihv!{Pk&{%W85~K>l?d<_6JC*2pW@NRbWwI zhZe?PKphWAjS31$P!3!%J@y;BxI3gf59$ChgXBRGvjSA9gUdNkDutADEKpA>2m6jr3iSehVMJO zTKxo0(BwK~s0=id*ue?veavB1WCqbwSQSBm(E%Ea1)WvS2pUD?)nJ;zD)1RL00izs zvI;bU7CgdRqb#7-C?|NX4Wt@0jM&2onrU)mF3AElxHXtMIF+~*rf>evzKXG9dfX58 zc&2}h)A#>i_hRgr&h?XBR&XOLsEq31RN@4+;B^_grd#}EujN8mG=2Y1_6Eia(;a@X zOPKEh1qu@3T#Nh#sdmAjw}UU$0Mv+0>2rjCUL-&%3x8d!0Y&h z4Xo}8TpcKE*aWssH(=z@RsmP>8cb^#!RzHfV^yGJ?`VoV{x|*MLv~?;qgGQuZGXt1 z)dWrjCeWBw2Z)9YS1G1X@C-z$WmK5ga%mp5r!#{q{N_;F1 z3ZTLK>uen9&_;F(WSj(4F!`}_xT?VC8^EOqE5stOPr!>q!4^&5&dy;V-nF$=+))H- z_!3A;1O@Lub`C7#=Pn!^s^Xt|!6)-UnlyV5S{gVw%&g%ygQl3!?Y)4M`kA1q{|dr@ zj~pBt;+@l)#2t;H4!Xmp#0H&@FyQ2{fi?ubAVh08IrJqyb+m~)o??LN`Gb%>jLC^^OdR9FCx=Cq+=dl*vIsT$f=77iiB8SbTad z7l(K~Tpm=0907OM9A~g+DToVPU;@>gbJ%gDDUj))(NOj*$1TWX*=t~9*$dbe#5I_1 zuqtwa=qs#>{7}b$Y?{HYD6Amvc!h;EOW^!;ac+(T#w*h+xH%G;KAf3;o0~(Kv19sw zZjQ-3`&k_s3qc7EG;?&HheJ}MgEPy~0MthUk0OHiRB$^QfEGb>3t*@gL{t6b5;q~p^Pi0ujl26W1KLZkB>u_amI8TK8{4j{nO|1aey|K?&sqWW9*oIjgKQx z5o|Jx19<<(1jzXO3mevW9y{nPyfIK=E%fQEn+44f3&6bxI;nHQX71iO0y#K9{d6v$>~ z1(s|j&>poc1%818tdNFX$MnSl9PTb#K!$)Cy&FIbP{VHrgrOjyz?==53kJ2UK|)|h zvO5~&C@^I?-T>cS4r=VN3+$h+C&;14*fBj;kVC-|B*qDvC1-au$cFm@RH<%&xM&B6 z;()sZG@cBe?V7$#ki(Mk!1ND-98z3IKsJJ0b7H!P5Qh@und#<297-AoPBJPPELQ^U zMb1)Uhnvo>z^uTQ4GM~m(5i78P!VsFqK|#W|$(~K2MZGTn)S<5IoeVAY;a~Y zEP*4_g+w@v7%xnB72)t>`f+mlR1uD%Sdfj1T#k&2LJFWA-<;XLphhleEaCzVRPqrj~Iav^9O6z;;K({G7#B!ir0FUC}E_irpte%m4-w~ZWcqMw`gCy)IlCpWaTw6hnHJQEpy4tFHU;Kv&?ZOrEPwpDXL%e=rL9$W(EFiRs|Mr z1wMg;)9a-x-vPmf=Vd z1!sE}2L(O_K~Sl{11S-BWI3c5_fJ=s<a^M)dBgdgp{{@`t_{^9-fEfnn%r8!Z z$_FM#=)3}WrT{Vk1TUEwL3@dX!FfbM-i)aQG)kesXU5b3W*C?=|A3kS9;Rc0jJrXm zH=yo43HBP3!gNM?4sA71+@4|uWqJ8*MP^Vhhsi-fm&HLr2b6HsV3qR~c@9T; zdzKQbz-d-cP2)(XK*2XpEn#-rH9 zh^&qQ*)Aen!3^5rz~l&Z1;}yW#Dwq`izBF)4|N4YJ=FDJA2Xv!IWi)AjOKJ?6Oi49 z;&LWrZ=eJj%(pyD-1Q1bVTQ%EC>FCig11OPf(#`rP+ZP}stm~+D1K)GDXWLYHUp|_ zarux5If&3a1&&aNGfRmX$_FQ11r`N(Z-7C8dHO>h4sjoNUw|9bvsnl4*?@Ot&tS|FI0G6$ z1NSdMli}blCwLU^0DG1r@){<`9evaJ)Hoy^&mwokpktei0v|xd!UA^C-Z$(fayv?c zHjZ#Rewd!2#^J1emK8c~2I?;2H)i@ZH4b^Eqc5g^SL4vrSq`%w5_gPoJgEVE`Gu0ngM!mJlc~3!DRwr}l6vv4EPI z8cZG2->Gv*ae=F49tAdm^V5YiIAXaF{+?c`!C@@;0bH4b!UVkfLEy~vy&4>PjEvLY zXmIG)L%Nz*;1L2ES%${|E2w_w$WjEw^9_&(HJC22E3qgT3an%WEiq}}0FM(e=`#Fa z2Px8IzQL|&09gaz$RMB(-WK54y|qi+@gReMff5^d5RSz`zz8&h0kWzdWEUG~Bm*?S zpdfC>GyycZW@ygb!2zo7Kr<{HSppYWVLLCO`w!NR%H1{fAi<8MZQ|e#vI4WT61y4G3b54> z#~%Vlg~-8KLk?RT63aS>!86Ljwa=rA?N?g2x%Qiut#O$|_C(2y6J|G}e6;9;8$ z9H2ud4WPk$0km_8Nt1a4hoS+v(}U0l3O4X)4-2>Bze}y+jt3Y(>-a(Eyn<^?&{PJa z0-pkhz*f*kYS7TQqX1|K@e6ou2WXoBXtRQXFq7jO4)7#3XuASvjmr~`>1VY$3_k6K{cbY2|}8R*c<8%A)a4K$Wysl(v_9Y6WPsKf(R+o{80$$FB-jEP}-qPC#$ z^jkU{;)V~-GJ=jD$YEruS7vY&$W~%j0j-o~RA3Sa2cM&*09qrU#0sKVl-LAbPFK?9 zaOPai#K;WNaA10#E{7Cj*z`_a4mmL%Q2U3~Q3BMbWpxzEQeabH6xcU?uP%qU+7AZM z@@OUnW(CmtQ3Xav1`vYKH*D6UbI#Q(q{hiOX@|?Uh&zWmI6YW;6iB4TQxFS~?HfF2V-c(%;I+$OH{hCKb?bG6qMU zEYS7}9t|cAK@Q0FEYR*aea3njB}UNU2n@OmHXsp4jx2%0pbb0>Rtz?vp&$lLW(|Qw z;7ubIN}x&w6o?EOOa>tHOay+zPLkkdP+)Lmuwt+U_0d2(&J`HB6B%I<%c#Nt+I)^_ zg&j9Y+!nML9(1Au#41ONEYRr$0{@w$;D$2jGT4C~XaRB{Xul-LlIi;mIb0N9FoAc$ zDKNT%){iML2^c6bflJsTu&bJEnI#3Bj|jxt$}U)I1E6ElF9!h(%aP+)M>Kwef0J{$qOsec!X5~C2< zNnjU&uAFyd7T7)go)L$V-j+7_I$Q<~CJ_b3EJv0s#~qlW99fQg+NSFnb0{+InI2%w zk;Zsz`gUUuYw5*oN{s%Xm5`9~g8{S_jY$Di;CWByHQ|`Vb&;EqACw|Ca86%s!Xc^5 z1u9%P6a_#Oiy|k8Vo>BzVANoeQQ`$nnJV&4e{RAd=g9-gLZF>}pl$-A29tmyH>f%S zVFl2BL=H$LrywA$$gjYq%fO(><_H>*;sR}R5>((8c*3a2?pUwDHQmpYL!E<5LBN%l zRe@uAttp4TE*G5C&V@Z}059o9PHpl;rZoI4tJh}{w3Y?&t%##{Q% z)09I=A4v-nNQ*ur1Ee-}<7H9c(Pv}=>G{uG=m|b2hkv@38HWlZ*K~g~4q1L41!2%B z4xBK#YBLVGdJY8v(7H{yH?ly>(ODFEK${U66uBUImu{b;2jJHIF!IX+`$3fWTnA$ghPQNTZuz~4YU!-TUv?3kxL*EbfnN4PEd8otH22g zkQJOt9I)v(P-bA&U^>8|z>#IfbO3ZPsN)Mz1EC(I@($SeCmf&(oK>Ik4Tlm3sDx*A zyugtqu!B*79keHvL4gC*JmcV20GSUn8Ptk#WB?WZtRR!%7Jyuqt;oj12s*Y@gXska zw<4PY%s_6iiJ-$=7$U711r%5vKY-i`02ThA<3MT!4zVbL4-H|^XEae_;$;HWL=p;& z0*6_k#Xh(~Q(zQ0!r}5~>K}DfLwi2{*)L`OKVpRYQr+`cn zP-6B4rA`o=Ly1L!&7Z{qygG^jw6&he@l59=agg`G)^dP{`plRFKzpGU)?i`~WMKgHdt{VY>Uo(Jz>94q6qvzFE(JiA@hE`KRP*KqwHrYDwltVP z8XXzkSR5QLFepM!hErg51-0iC7_)tgSn3s6K;3rMZ17rt1`Q?_B^J;qe3k-qkv{`y z6jQ*FK@oJu69dR)3>r)v-1T4wJI?t$4dD|OGbSET-vM-xR+c|_(3~0KVT4yenn5FI zAa|j72owjP!D3YZD8gqbKz$lV1<>wg7Vct3W-)N7!vkt$ftyDPpu{Nfe!8+1M;7Dm z>3volM+AN_GBMXPf_4W(TFBG6HV7)mFoE&_=;S8_#u|YmpixW(NGbp|qZl-pK*``2 z8#Eb!#XzkJ28e3VMru%b4oMH(3XDz+!QkpxCJWTuoZh@aP>Ja`+w|od1P$vI7(hj= z21pO6^9O2dC@{gcUNZ>nm*5U$Vypw5sRP>954J^#Nr5p8+>!yO4INOVYA7*hudP*L zih`y|b7pWm$&5+I5xj8q?cOc?i0zi-VU&Uj+_cWaJ9#^cj7Z8+3KcEfhGK)eg;Mx30!*oI>x^S7);q4#>@cMV;b`bdd z6K;DBRmOAE4edEh8Fx+ppf4gmz0RIPnsLSSS@s-L881xx$D+Unsm-Q`IdEt(`cH3k z;4ox5&^CRG1BU_Q#pzESIC^9t)zKc%^beC6XzvQMBj{i&&>3!*ruRB>91#1nrUSHF z5>zNLa4Rw@usHH$34}~fcH(dXZCG6H#1X|fcRG_ZheiE$Mn*PJmKMlXVpU-P)ia=e zLADYbC}iCuwBf!$LY+-GA1Z_5VdSWp%P4d-w}iXu=iLV?|v#X$kQUz$gO z1(c&fZEaA3VB%3=1tnPqNPEE%)GJ^PS76CfVg~m`vOyV8;0g<slepn}@~L|HMIfGAJ~=5V}lY&JNbgX02u;0UO|D~TN+d_a42wr3K39HnKALyD}c_`0yPmq?F&Uv`wO)E zirtYhTajIX6VwLc0<8uI9aF6cTHFgdUk}uN2OrGmSP!nGx%{QU@dzn2U;)kK06H+w zMv2|=9Js^A4obls8cY_7>oDmdG;LSb^FadTmCIL`OFP^R*;9- zKon@dC^Kj|pav5|y%LiGyEiB~K=dgMtPW7|fs(CqPE9Dlla$g61F? zxWQGtH6x1xBWRtj0BA2V$mPs%aRyM51e*pf+1Nm`pt=uc7n=ev6G$2qsGvg=rt7$J zSTLTSp6beB&T@!Z;QaOlt{feVj0d)Bx^rX+GWKns62Xzf#CTvjV>E{*tYk z-gHj_?;`|vsyMP7zaaAkvK;?(PuGa$@MLVAUKGn=%-A}8SuBS&W9#%su^euUZPPX5 zICL1BriaCGC@{87F9%Ug(`UqSSWC6DE3txmP@o1ig93QahnHJ{QJ`b`+c*wM#?I;N z@f->^gzcXM-Si0BWW*@Y!4BToqsZ*|W%cyrcn%B3uIY2)Ih+{Vrr(d}@L}wpu9Lu_ z&)7OWCV@kPv3YuH0*4D@+w@Zj9Bz!Q(*+YbKR)GKLY92^Aa}vjv)_FH7b~Vf;6pJB4F5W7G8IDI7|S zozqXHaCpddu`4iXGS6UA5(1q*qsXElv|JIKVHh2m1$w3%q;g0xc1-t9<*;UKo8F$v zktY0)O@R?)J~L>Z6S7rmS{jGGAXpr9wvh%Cha#inht<;^(l``BC!{8)ad*PFCuVY(F`k`1Ba_31@xb(}nH<@S2d6t`anv!sn0_FO!<+HO zbe?REYs`%sI;J1wk};l^!?9-iksOW=rjwJV`{iavD&~vDSh6a!^@etlF2rmx8`?VBoOe}==2*Qhj@IZC0A`?$E#L$21J3yvHL3q>F zfO(PJj#DA52#B7m3qa=i@PtE@ZGt!?3?lglVnirJ?l*)N0^uEls0@bi)v z?T{#Qfbg29gRQlPs5}5M&kiCt5#l{t2ygkMPVst0CLSAz(lZdH))2|(5G$-8y!#M2 zONh$75S|5ucMrld=XTr!VVQ9|?uR(sl-rR-k=gMd#4HntS$`lrW3X;%$88WzMqsYv zONgW)x8v4})AI^Ar0Op&Zv~|fJ#I%JI;6u=4o;}zWfYUuK_XZV?S729inH!GH_~EgUHR836@jk zt_K_V^B0(_0+D>b9;{RuqVfM8u$&S^Zq2tQkkyJ1pPx7hmQ#T6&VK@1FAveT5~5NL zqHpU}us&ICM>a)f#|JyXHpp;0)`Pgqmw`1(L&E4UBn+gu9k*TsYm$VBAKVPKOafxW zzaLmgPMK_rhs{38hAt@;Gk zD8TL5-wVo~Jp2&x6+gjN^Fes+5XbX!J8~;BJ2veHdxZxgck~I^pWF~f&WAXJ3nDjl zI>?k%9!^N$-QEIL$^kKERwqc3hn?H;bURp_4HAskUxJNig{Yb~0qj5)ZpSA-!Tx84 z_`jzKEY1Ycv%INw`UML`x#{f19JY+Frn?q%=rW#}UR=y!CV7GdG??z7#0u`Kg2&m} zG?;7z?oB^b%%R5kYWmA!4n4**(gr&00E;U))S33YoIa<5LrMtAb)c1uj=Nt@KT*LEiPSR`neJQ3 zp~m=hdPyb6F`>7hrZAJhI|%ijMc~8qg8LlG+w-e9oERA=Oy5+^ae?E&lZl|y&n8Xp zs^QS$I0)h~2~3*4r-oyf;$aYvQD72iNp7|hgCkQmXe32}!4a-(dM!r_h4DKy1)1ZAC^NTW(0B4&Z`DCkw+b7vI5g|fldwskdDA+4iylM ztaJL&W)5vGkdq)TOM z3xM1T4L%{T6q1W2rbl&h@POQr(aGV-2(oK)7l%EF_UY!3nJ&=HVFi-)>E>W$5}F8# zJYEJV1#l`*U=f%&J-(Mi%nU3p&8^4^8WRES5&)gu#tLG97JGo^Q50A~EjTs}CLYj; zmICN@?x)jN_i{8aCQjGs<0xYMvVDFZhYBN8qr~>3{TzLaOxyoW51q)N#&~sl%|s3b z{--R8pyNovqpd6g&!(@Q$YH^Fb^4Qu94d@&rgKi>FlD?t-F^~>ipVz>B_@#7phG-C zb4H-X6&Mv51wKqa1QGrLQKUQttSE8{hk?Xf7Dv!ZQ3Xa&CSg)w6nM|#$doPc zVfsRdqU%#QbcDXMfM#rVfaczyM-xn+xQ;_=y8cuSS;jZheW!Am!n~>g8kYdMYvNR} zyG~8z&|~~Q{pVB;RiPhXW1cXBQZS_14l+h|y6-d&VaBV|6Q_ZdPM8K)I)xQo=@W?3 z9}uPL)8R^Yu%Roho(?v(e>#VT#!nW|%#Ne78?U1RGidje0?4ZnZ*5>l*ZF5UhaltC z>3lOd3>kk-cbLH;!T4r+t=EEGya{C)L%K?EUw53s&Baz*&UDXZvgQ)xE*;E*&SDc>RVP&eao)M z?zpQPEC;T0*&X{Pw}Mo%g6dXw#}-h1%*w+8YCo_$&Y25V$;|BtGV^T{n8yUF?%5qr zfSLlJ1(=Q?GdGD&1sMYx20fw%4%q?)CV{Kd1LtxW$^2qbV0OHt21;ejj#nVk8K9A9 zHi3WB=g;M^;e5-Y#0g5m&!#__%VEg(4s`4V2RvCT&*Ly+d^0@^LUqmqN9z809EME) zS*CxQ$Dza6FkOB=hXUi9=??QbOhHA;#C069%-jNRrca*_R(*CpSoO3892SfX(=8Wp z1cOxdE#R*rq>2DTt$TK!g=UK!d$@pfv z+9I$^A{T*`^e^HtVf-=u$Rdt-#^&iNi#co=8>c5N1}mAmm?Mqx!}LFkIjp4KvVbnX zV0N6L0>1bQbl4my=YleMz!I=YZA&+;(?ynY2*NmEuedJ-tF2wi zVaWJn`ue3D$*Rqu2ml588b#2(1uqn`1e!sm(G5j#U~4d)Q51MH-Fz8XW9~Ar#`(*T zHBOKRX*?qb)wo9fP+weC0JqT zN)8RipVRABau|d1&PuS{Q;3}ODzKc(DzIF|DzMz@RbYJ&S8&7mvw4_u19 zkVY#tz`^MOhDgn6B9X zQT+_A`T@9-W7c3gB7v#edp+3f#`R!}*R4mf_!&e}W&_OP1L9DNSBPU8)wls{)bo$TFZ`sJ9Bh&@*Qx8mW3rO)Nh_uEg4jn15 z^b=92SvN#6ZSLI!Htg^wm|=Ths@I4LyqV6p87ytSnZro=2dErl)?j)fq6BXQfCfaF zAdM7e4W^js8z*uoO<%W}LxAz>^!=N`&K24MHo{{IhqA2w?Nds+QOkB3@T?p#~3OwB9y6a%qUhmjPh zUUzH|f%@}-Fs48MKvWxTgQ=b)3{^b^i|V=Cz-C{DtKK05RlPu#VAUntVP;;cO~?E%ZJh43CjcxHRSayffBOc=YTFWk$a$oOXZ;k_J5j6bKV?c>ms1{KYYQ+S~v z*uslkB1p2^#1)E){K9rp9WDMrn4X5 zuw?u&-SGfN664kBOAc`8F!oHpcmP}@zCHlfr+5%tn)@8&u#xNqFH2m(1(}X!cH9BF z8b*Odpl|xZgB;?FJ=1p{qY3Rv0U=2)voz z1yQpXLVbWx%EvkE7~f7$I?iFvbmYnQ*~d9F7}+MXDlqaePrq=SW8(CvlN{j?0Va@u z`Sf=uIo2~yo<8ps$7{yP)4NV{gfewJ-Tv@2M?53rld$1$I2D(iIl z3mjV0_0Mx8^Gsn?U~y!$V)((x!!$kr9Eb1p*XKFZ8K+JczQ8e&amw_i7dTci{+J$c zk;BpMpal0tMn;x;CI`osH`75=EK1Cv`A*PMAJB;e5HU~C9JJ#U2*(?=VhwalRL7g? z=Pz>DF;1V(cZs8q>CW@*^Dc3SGqTMAd5UrRg-aaf)6>6mC{Gu?!ZDX|&h*V!IFgx8 zJfFVjK8MzHr>h*(8K+Lab(JG-`pv5xg4;c>aX2z^wX-TP@vw0_zIZWx%5@F{#)aFD zUgywcWSlqs{SA(-jMJva+~Me&u78Weg>4?l8s_QuuXCK4?s}WUPZTV`1lnOY19S%h zXw`{8$MhAqIW|M|-DaFO-Qq5XAyd!G>DhNV92i@-uer~=h6M6?)1H%YjRKf$=pdj#fdd3rugG?7*OxJ$OVaK>&d)8A9RVK#y+b2Bd=mxoX z!gCJy?a41WEEyT+ZJ+y!qYD&9b6;_|PtSkDVahb+#q`<7IdrC9dc*OSaqjd3Z#iBu z&fUKH9S0*LW{`lSyXs%#A}CWa!i^2 z?-xe`<1CO{LYQ7W-M;lVhX^Cv3|0kZ9>(bxKXYhJ7x=>=I-Tz?$2rCs+wcAbS^ReT zn|~bF7!#)-{?FmW7_*g)^D`5uy_EN#Rdu=oGbd>DWqTeo=T1h(chfakIaL|oP4{Ev zTp@)#4yD8TGsSZN_)gr?Yb^F}|C= zi=Fc}WN3$JI^#zUk?HF>IE@(JPJhI~`4i->yPTYQjPIuNaB=D}zMXE(#hC*h)>32! zk3K1~D)532DxAKXi_<~}JYu8C#GoVyS*0xB8~_?ZWKw_To_ zGn5fN^tQc*hqHoFU@_>v9fxetT1X8A27&X_S@<|r8NW`~;^Wj~d_Fyrk5h|%9%R$N z^e#S5UB>s*ckpp4;TuC`2aTcr1nFNgU4x&~h;i5SXnsyN#c zU0HxLfN|OM5&=#ZrX|a#?-JmYWm>X)`%MAPnT(8^rxy!xE-+jSDxW?uWPv*B;6v#J z&V%c5CIGVv(NfhJTr6hZe) zA+4JMZ74tvqkeO|8;n?+V`UVkB5s;^k ziEzdby3cXj9;d&6yw~- zwu)6jR$%q?Tyf5R##Ph*igPM6u9>bV!5PcHh7}Z2Gnf>)xD{jsR&Vc>;7kTxQ1wxg zQ$%tNXek-HfI1HgwBS~DUoEnUarpL>0O3Q#vWe`vYO%Jm;PGHGWkP$e;iBbd zku;})AXvWuI1U?F!TL8#bLuF41WhL2U;!`i}9it4VCfi0P zFxxF@xXL#1+XD*3Y^x`r&*wh1a!hMni+ExI3?MSf^GRS-B5v3gmK;U ziwc~+j3=hcD}s%%Qsi`JTsOT*k<*s(!1MzU!P|nnkkcqwtZG9H*d0m56Y z#F@r^5NzZDsFB-sl{quPcb&~p;nZbZKmC{rr#)x`wkl^8)gs6bCpJ`4m_|OMDfW1**31SLLi`Vq8DnT7z>L8P`w$rO7#ual`hR zTAcDAuC)fI`t%3doQ;edwkPRuMu5b2>vCE!uAlxzm(z-I!*qQ;&Pv7&(^u+omN0IZ zE~n3#$+%&9hd!q*j8FFr7d^+9Hh*Lu7kOX%KXq_AbXq_B`Bj~vFY$MJ<#>Lb38ga%kb$psGYs{%H z3OY2$+&5{v>B%{V9Ea_TU? zpT5PCa~|XN>A_ZAO^eaxBZ4$pgo2{5Y8|*<-8`%P2KBK^|=|#?*`HcIw zKXT^OU}W0QI$dvzybI&;>4C1Cxs3a#?|0>NWIQ&V(Ty{kasTvOH_m#-{oCKVfy%G_ z)0sRt&oiEwe#wI~iT@a@5~BiZHt3x5Y=MKU(;x1X*W)zE0qvn<7C1h=%9GQ9asTw) zo}7w|`={UaAJyRswJF0WI_aEoo%{ZOJ;rG`%oNK)4=s zlO!txBNHP-1}0sj`BF6&M{s*Dd{ILKSwL22#x|U{H@LuD~Sl5q9Z0FT@1L zuM?(;J2D9vC^CT75;B5Tcrugc#F-#VIS@`{f!-a3?nV}{)8TG}IT0d^;zWoLvJ+WA z*J6S$BvoQEV{(CbUx8U*Ba zIFuPItN`-603s+Mq8QGE2%|U?B82QrW@u#B!-Mi8Gt9A|z*PWM>0l@2Kw`fH68klf z*sp-ZzK0o80oZAdOF=GXL%5g;EUduj_<RcR| zO6oynj1q&R28af=HNk6AWuV>z9hxEm^1lXC11mU^KvzI1m@{)gTyhVTGzAd8W&{gE z;%NmdEZsmv9p8ZzBSk7$xL#a=1u4mc#l#&yfs`_1n2Ve_pem6v2O~6izJoN2Av8la zBcp^ZLj3F={y0P6`<=?m_Zvh8C`in(_{jxr%w&w)Hj*ZGf5nN z#s{M#^d?$H&|Nl6j;kk56W3*6uwnq6dczO7XUB2%#OXf*IG6Ekz1k%1$m+=G$RKca z`l>)qHO4*DF9vc7i-Rw9+qbPt+))(X_;%cKZ2Ip&&V`H@r_T-Iln{Q<4cgby0QIzj z0-M0^=_i6XWf}iWe-^|k$GB%YYcQui56CD5cE<_ePPs!crwHSo>7l`#nsR?RpxX|3 znLtNr3H(9uK~~KP=2Tz@X?DCgb^768PGvzP1qxh_f&zc0e-Gx=WZW}dF@#e`$O&>v zEocaZ)fK$AdU|{ar=l#_2rkeio+#U{9TgN<1b$DS8^Wp00aG&lLI|e<a_l9!HnSd36 z?T0Ah1>anlp$N_Y3ZNtXG?-G9z_E3hKP1#Z>NXpp7A1!~x_gVs)fLxcg8gcUd;+jl^L25L+~R|LV# zf`-|_`_py8IaL(Es@NT`FlGt-hr11QJt8Qw1O)y}F9=78NSGHv?wLM6oYR+Q#?cmW zN65JvSEv67=X6GhunAn9?jFHupp1wH&`uNqq_BZz*_{)o&x+s-G zA~Xy1;Km?k#JlKQjgf0%L@?(ZA3r| z6^Ml68jyNMM1(+uK_Ob71uD)^ti`383v}D~N6?fB=t4=TosRI62w-M_b_KCJf`VB{ z;136McNq)xGDvifGADzRuL1*-E1)rX2IOX4gqtD4pk@EaPKJm&{sbwOfGY+iT4qRY zbDTJ7`t&HycBX%<(-opQYeDqB}^6M;XU!U#5u*9F~~=@HV5ASpyqr8@VPk2dF8}0@+Ef z3|@5Y_yu(MgPP+Vkj+;>>>nVa&XHB%$n+gCoPpA7UQHBt)NpKCIbGbb2gKe0A}Snt z1&&NtiRDyeoHpGpmNSO&#Pr3noaT%tw%?BB+``B>eforWP8Y_;?N{SDcYu4W{fV5S zj3=fqP2@Zyd6H3q7gRrR@G>ayf@)Sq1zueSK7muyyOKB+7^|kQPU4JaJTaX;8Em9| zGG{Fdbp&GM?BzDUJA$qYQ($srE^&PFYNB`+_;M{4M;4G81xC;Ud(f1x0;2+h z!1U=y@;IF#aqI;GIDFtn;Ws*<;T`MQ>d%A8hr)>S)?lw@Vl_d<{FOxAt~c3rqq$fXoEi z@8!7l3|u*A9ijrG<7v=|pUeUv1E3%i-RK@WS2jKLOrA7 zuJ3T?vN$+`HiR;Qmaahj`|&Wkf7=ksq5eJdtr_M_76(UGn9+=m{S9!JvN$+`3IouF z90f+lgPmN8BxeaCWcF@sQU(P#OiBnW|adO96+hal|AJ4cWp z{u=2jNCyvQc?rHymIqHACJQPrSwS6sB{uMR3MUxgJ`vbA-LaL^z#kME3M}A`gF7#S zl;b=`MJC62i#o&=*c>_C6xbZC-HJfs42n#SAhq0z44|d25Kl9Kt}$f=b)Pd7K!bRH z)=WRp%Bjip;LG&at(+>5w$DS5^TjZokGl%~4$?uAhq2!mZLI;i?^lCK1WOo!f?NVb z$Y7Clgf;>gL#N+s;{^|4C;(ena4h3FE`$8pVD~9IwpmY>;r~P~x6`r;}4sm_vhU z1tTvLNY4UBC3cp21@`G2U7X6&;D9?KqQIfRp~ukDRF^)tHE?YOovVyk&glt5!*V4}Go}+FAZIRNR1$IJ zWvX{%P~>rBP*hQXY)b~OHBnRn_5OH3%T5%v71$j)z${(R$u!KMn<7;}JA~O4IJ0yZ z7#tZqSR53z6*xh@V9rt!0(If^6ofz*N$JD93W_oXW(8ev;$%<~0wqosC1C+q1$`j} zVF5Qq3(y5r9H8}EItmuc3n8}zEAVA08NjUo9de+cGksDwrwWITf)FSd=uF?&%_&pQ zp`Z!U3H6!+59oYm9y6vRA__bTB5u4a+@M}hmLezk>@$#)q_Pw^K$n&&a4WD0xGHey zG8~a&aZum@rTYa^3ha(xuY*GAfD~v&zalfJ76NM#XahC#xj@^dIk*)#6fDh|>JNYt z5rY}i9!3QYC(y-pT;@z$Kw?`MK_{*VYA`)uR$_K+{n;X}z$^{Qcu$xeITV~TI zxq&uI3n)Mw1+jq{Y6Fu7(*w|PI!qc&cUVAuVn}*a03DGAKIe>6p&oRSF+Gpm4{QavYFDd-SckXoc*;smMZHu#3Y-IcOAdzy(+)-f4^RgDzz9AS1RN$wOHU^LbL33bm^-n68SU}4UDKm?RKM6wj51l&Q# z&9H%TCg^fK4Wm8GPq!@!`#=c>TtTI9+CIul$(fe*ATz+HjQk--ln z2Fjd}vQZOUnq(<~785G)f#$5hbpbCZtQf5r>JNx1a6z-ICTK_#l;J^VRe{zlDljW> zD)2cnx=AZ?a)XM7Y(*aMc_|9)h2X=n!KpJ#K~sSfti@A_U0OlJv4OG3iUAyARt%t8 z3X~Q>w+Cl~E^Pq?oCebpM(`0pOBm}FKr@}}(x3tml+t-Xr6uUFOHdi8z?r28&M^nX zvUC|3AgyXX1vXF#&Zod_1{#)SR?q@*nH4m^TmeugS^!*FIWi~;DKj`u;02%Ur@#i9 zkEnrARS>EI6#qXMvXq21m=qKRKz@)>6ai5Zic%noN0AFeaVYXB2x~GiC|ZDcB906o zN&s|xB`1r60-NIpPS9F+P;(AcL~;J%VqgHJzb}lSOJ>;=IIS4ob1Sep_OWL{6gxJ6 zZ%+p~qTZUZj}yeOX6#{CU~}wPHv?4HnlqnZ1&Nw5fp*Y4USQ2q(sX2S+`$MsT%Qfp zG+4l?zy@AgBVf)ngHwS`!NMGLj1n7YMnZwjaRMi(NuaLC4r;l8&K1#MDo_F+s8*uH z3vU%DF+;o4Y>vx0vlKvQOt-Qru<0_afOw42ilGy9atWI*!*WhgtZI{T{*H8 z*%d&#K+EYstB1KAXM?;c$gNP%1`3*PP_!^RE&y2u${O~CO6*n)tvm{B3hY)4UF@JE z{FOif_X`%%uz+rZs%eLM6=a$+IP|`7D}hg~`~fCMg}1vA+QjH07U__ z8PgFS1vc=Oelw;6NHMkp>#-d<0gqf%fJ;;o%ijU~`MQF=t|cj7P9JJ^-Jo2WkX?2DTK~ z9B=Tzj$dU4&A+laUVsaLLwgIz8i#BJkcIUiYaBp#2Qz_KE{dFvjEcMpV0Cvu>R#}G zZj0oEI;4dc?2tV$hrB>`NCPiuY!AsHKj8L49r6Jt0LnaUj?89E^>aX>0Xhf4jA;f^ zpiKY;7PA>s4~XV8W9k4Yg9RF>(ZJ@|!IP!L3<nosMhnTkpY92`43LZ12 zJ#3ClioBp)$ZN%LgAJ4hEI>&VoVP)WEI`Jxf><_SWA&^U_8=8=TR=qwbG;eU8W01N zE;j+B@fuL6hXnz!VaoZ*c|_`Wq}OVU@}k?a+Foz z2IbcYGobmESAo}27Ls386nH_S4h_@L^DDPIZ#^GqNg{&+w}KEP!-9$;c1LiI1?gkV zQsQ;zW#r-K2IWB&kn2EKFAGR3@H&2&K1m#0lgWd#D+46e^n&s-yA{Jhkhj>a7!E;c zP=x@>&4-bSL{;v3P=?#V2`U>km^N@KvV*+6g%gwnHJH|LDhesEIck7xg@=g-=-5kk z1zrVq1#W32ZqPYF+zLXVvlQ8M84hwP@j5bQJIWV2vV*n^u{j>$1l{bx4o$xgI9++c zXTkD13TJ^-)ie2n6Uh^ZGDj|fo2;Oc5LC(NGrr*DV_{%oVq^hDGn)p}6HYUx26pfb zD{S13%!=GR{E&-dK>a38P-UUO?Kqt=n~#N!m4lC$+fh%En}>(naXzTDHIcygZ z;N(`|1GT={z^3amtm0H+7svolfU;>Y$tbFTf>%Nja`y_e0+-u#k6E02^?cxH)XwH( zW@KPwfRxnGCJ~<^56HjJii8=oBm!JDa)7EuP#X}G@V~HTDXKGpuHs;ZR4b5L1>BsN zFmXDp4FJmZdnEyF*vAft)S^Y7hy5SOVah zM+nr|6asZzK-G>SuL7tlQe;=)Q(y*NR>=S&Sily6j}>QgWVT{B!>Yihz-z{If|VQ6 z1ofBZWmeEsP*-49fChw{w4yS&X{f|G-F6nIB)$M*R^SA+a5)wDK*v8ZDDo4JHPNb66Y{*c}}}sh1bzCth%;Kv{v;@d0z8BXb$3e+Fu^ zJ2EQpmK4>SF)@G@fEyE_9_PzV$gpjZGkP)@vuH&8$)sDc_03}#GkSQOY` z-O(p3pdC`6#mpAwOdmiTHeH4qfecWff;PY@f|_a02*PBA|mzL4kP#bYm);2GbQ*MNm|L-G2wP6BR>}5mJob zVdYljf~5*@6Bryl%w|j`pa=x@6JLPhi`$Ip35xIAgc;m7n3d7R>qQPv%xQAt@+Mp=K|gRJ9{;^yH6xgOM-XE0;BfRvCxCt`pWZ!;)a zm@{1gS;>(FD$Q#IAbAxu_@Y=3D!`Fb6EDd3pz~`OK&6lZBm;wX%Yue2KufU{nLx{Z z7!*O9yxF12g&Ue&c=03`Rzz|ES@D4rT!+*%{eV^~UpPV004jpOB?-mJ1$2Tp;dB6M zU)*4YRBKmQ!A@ej15OZNmuP^l)C1RfD3YK%LqNwqGb@0T0Vr@m$KHWLAJkDi1Bz!* z3C03V11F$q05l>1lH)OBx&w-kJ1pS21xO-T3`ztjt9A&@b|WPM9&QCGS6*f&2L%yF zwrt00P#1wqK?Ky~m~tC3L!$(0azH13nITP%4Y#I(x(M~mpu!GZFer$?`v@WmQjjJG zFEeOh5!6QjX@j&lKqvmOIf6>GDW6eFG*CguV8+zJiYU<{*}^g^p%5p+x~Y^@x6BN1LM!EylA1FIg~)~0C@ zk2fFIvt}v5D?>;*1P-mom)pc0F+z*_fmM%QA<{V?))U_`!JQ9ZE+#u4)`Plk;6YKU zCoQ5<7G&Q5czqq%6|~QXHqZ^05nts2_bL}1rO%IB^((+K>_M65fOZ_z^muNp74kZJ?PLV1%U^;Mgr%s zD4r_fD`<5vrHPMKksUnY2ntrRLXYymtIu+zAoRfFap2Vqqzq*|1+B`4Rvh();EW1x z|6=VC;Lf__=3H3P0|#Ec854OKm-3_s4!nAjL+?p1W-o#Cat{`G^`OC5axyMB^e7L! zdf1!>s91qDS!h@4eFP;vcBFh;UpQb%4;*;)@ChMMbxW^O51jPCDX*TCjN7)OUEC2l z^e7L!dNS$^DkVK|%BwE~O}T=m%OH~yv`c#3t6Ie!xsZ|`IPmJRkKWR_)B`6yaLTK{ z%4NLCifdM2V;dnk1VBJ?N^yn1>hy|Ya%NZo%( z?;jd?pldQALr}1xaJnTuaNyO08r0BE252sir~wpklYu(<3um@5QQFiENWnq9ysOIL#9RtBI$us9_TzG z+)3}p%VugR?ULTY8Eu3EuO4)LCQW;|_**OW zY@i^gcc}+XdZ0CZj`b)r^N^YV+#;Sa1!tY%$Os*&qC&o{X9Kl)L0vFVIM6lefm0r6 zK?=^nDY6Gw-aKv>cjU%h>Vc|YNZ{3@j-h~hL5RUASSJn9T%mevg`~MKkn5=2N2|wN zdFFV3JF%fhdEnI#T+(CHVEVyX4<1N^1S|;)_Hb7jlfb*wiAj3kz=PEPpaCe58|a$! zz=d8t)=^O^4X%KDxZrLE&Rzzh{R=MjmMm)oopVFKLD71YL1j8rxZqL`obVNu|df=o79)zpMT7aVNb^q*b_xq{jxDDudMj;HnrdL(i!okpDk$ zf_4-Q$Sh<}{dDA&Dc~dtN|AJ%3aY2V94?tjPXTo6Cq-)!cW$P5JRYt8LC>TI-rZ6^ zU`cO2XabzQo{TyJoN>XeC(83Jc>aU@600t{x|JQy*5x= z59<^z(q1S!mU@UnuYN#EJw%~b58nfhJL&BNHCNCxE|u~vd@cL{O@M<=>;i9`hb#=H z{#4Mtdw8o1$X<{ENqXRv2WtNjUZqTNHv?3@V(n$rgHAZZo%9Y;-or(!aM9}9dJE73 z_<@@MuV+FVkcTt_sWKJxa1ZFrZv1_;`hiP&;8j1M@n^gXp$y+X#B} z73e^C{27-@`L-Us{Cz-@9;l@IQIBh55ZSYki+7QdZ=v-+s3Qw<561WaNP@B+E~2dm zu5iJno&vm~T#qytG!RokNbO&65BL2ux-9#FullLSlJw}gBZx|SA*W6T-2{L$$3pf( zVwQ8p^9r;1@QATMcHi0#4Ob#Gkfh#YA0>1`R0O(*a&|X{+ z21(?AkJiuTV`5-r}E_Sm_b*+GCN*j z&Z<}7bmV{?6UXd$hdE1u(@_8}0Lo$~K=&kYf^R%I1HPOXtdUfG;Dd;+fQ?7CuO2Ld z$3kw1$EPqteO`j@^9k_l$e>>TfzRt_pkDs~wwEKT9_%mB379{?BB(BTg7EqasMlc{ zNze!OIu3pHcr1i^eGAy@kf^lG0>vhiKj`pL#~CbH3jB^UKu29WN`OvHgB+L%y3iLn z4jnsKK#__Fbp=RdHn4Cj@ayX`>|q2QngvQ#I~dKF=75uP3ul%huL85<5|%8`y%nHT z2Eq#b(-$1!6tCx0-~w;q%@SD420Go&is2870w?G^b7sd2;1j_?hej)K39LhwX66Q^ z)Pszmb)ztKNald6Gc4lFpxw+M^SK>${%|ocC@`}*u3*Vhun1%*FoQg-0U~@H>x)5$ z;cGCRU@0szV>-bClGJ44P_kIAz^}=qqhz@pq=bF?`JXFg@-Vr}%V(W1ONQ{F+P>P&GDCHA2%Pk8v7u@@q0FfMupn zKE|o8Acbbb0Tu;L(Bbw5Ai_l8-Sk_>IAyrm3)d=GfLx-$GoA4`rx+vmbcy4f3XDS2 zEst|*nMf5v-FJWm6zWHr6}cce=_n|=`E?nNFe%VgVMfGiPKTao0ki$TZz-Lr=dZi5Olb^ zV*|(}79K8cM=o4O@YHiVRzpp9)B-z?o7+)bk)4MNZn(5J*l5Q+6E-|xD0D62W#e|_ zQe@}h;C8G+)ymH8D6GiN!^Z6>q{z<0%Izqq$j-yU?Z~gl&ch5oxQ>U3+mRa*Xb?|v z*cXBVN0EKH-APVOMRrH|LMw(T9FTB64!SXcUzgz+=x|R)kgeR)Hy-B{nLg(vr+f%E z$Y_uZGq)qFA~(or(5aiCq5_ma9c8kVK!N7S>d)ff$fU>(im8sJYM^*1akMEcQ{)Df z<=l?^g;orcITV;3yV$a(1qvxnS2)GVF(Llq%01@MIrpkvWMZd=an_^Nrj zxZ?DK*ToH|e~@5gnZDo@r)@o_Bb%E7r=x;f5if`1y2k0^pzPzQ<;KgwW5x{;U}tiG zBolD`1v=B1mDAMJl#>BeN^v?WWb?6bg1HKuj)EY=G_xIHANE3NA-wcaTZ$g}ep|%#QzVGk}hJWp-o+-E09W?Hm~d*0X^($v7Tha8u%x zHe+guQ($&%oZcZ0zL-VPJC8Q#f(?04mI7Uh=JH6z>Z)>n9ju`2g*|%ZoJZk=2>tU@VoPRC@?$rffCOjc>@%f9Sg66Ro|9S5ysVH)Ra;5_4emt;i*#)+NZiA}_9|Q#pW>8fHN)X_507}9vS&oVjh0=jm+#vlMJTA$1{bvtkwtF4pYC{tQ#czGim#OTheimUR$ zUH7OW`CqQkk;R=Cbf`8sSkY@ROhc@}RkR`(k1~=eka|!N=9IoBXpIMoE&*sI+t$=E zz2F+BD7pvaVY;>;hcryr8kis``@pQ0$FN#ff!UD{YSCY4natP*DiXd!dGOk|K1-2{ zM;5~bP(=(*Yk%Lhi|aEmSR<0a*LO&%PY7zuTbLlS!=y2cl~jNx;R)~C!7UV~dQhN% z1G@v}H;{-3)Z7M`AhNlV80Lz@%q7{m)0u8?iq>C&ItSDNgygZaFpEL10lV)gvdCT- zrySBF6Haho zYZSS7gt#5q6uBIaz_Z+wqmbq%jy$&ol;?O6)h71p|KJNq_3w2Poaa(+aw#QYe@5>Bq&uz@rNa zGf0NiQDAm_aS~!RxQtc<)hJvF%-B6^dj;eUc7!`P9T(k#ReW5aiiAtrk=KzyfeXEL z0CSD#^ar;%rR>n1q{HpF`W2|*3zB$s8r?zcxEz#x8{{AsBnK&QIWl2{#C?z|W+YWe z&IZ?igq?liHaOy5-{w?}hE_t1?z|d~+y1qR!)iDsPDf}R$IIdPaa#+lMF6YNlz2d$ zaSo6l!9~En&StbCVB7SAk2ysc*G+G@!zl;qd^vu&4DPR-V9s*f&^%pS-~}V79sMB~ zlrwZ0J_ds-S@g(~F=PifVjNGNZxRPL%NX22Z52lbM-~N6l&FDR_wnV$boslS`f4DT zA*U2IZbwE1t`f(y4Qz$3yb3&^Bf}IprpP zbX&VPq#fn5RZU^xXuGCq3`oE~1><5UDS=kIe$TY|d9(4t5dg5o;9`zfU_Bcs2SJhz8=_AKZXGV+%u?cV zd;|&`A!yiu@(CBXzX;A*3XmHGp`#6;OC?Jjmn@(D@gb)qq_GKY2=akWyNA}yOFlNC z<@PxrA;SjXHXp3QpYn0K_aja%M(*ilk2n<+k;0iDJpeZdW+`${-~NbGPIMz14=*$X z*MJUcT*nVe5w9L`O51`$0h%nip*19EbORJj42+D74B$EyTpodLx<+l1oCKFg*#|qD z!TAz7Cqixe2C8CzTt}^mIUx2Za5^ewD{(qP3 zun>}D7_1q;geovQe!B{`kQ0`tSV6-aU>~uturRQIEckL6QZgWypl66FK_`iuO%Hj( zDM@M}+VK)ph>A|%`~;j!&OHH_3?H6wN;7jSuutcE$|)&~h)s|amw+xEnr`)!(@ve! zilKuIl)@ncb}Lwwz*pdKIr4z+nPpbsvSRoWs=z*d{!>nCM$YLr&p3^y^FHGgU}T>z z_l#2(BIFjp=_p?ay5o#rm!W_c)W8A_cY%hJo2hGp04HJnW#`5}6%A<_na9r?K2Y zL&%`v^FPt%OrVS?0qQqSxx)aPzn6?A0}v*U(a3|a61VFV50Z(-zR z1Wg5KGHr=L3Yaq(0doW%4B%-x1!l)RV3Fw^FF5(ULH3FkgQ`5_&P%cUIk7VlNmG*nx(=3yZ%{0Nr4wC2fFbIbkUP8!(m2V1_eGyI^)x2 zn8FC+9AyUGAa z*QgSRZeq`ZW@?b27-&EpI%cWB4AR-isle&TAfTbhtRM*9M#QWjIQ`&DPKkOY*rnA> z3WE9!JD9B*uP`fs*+-bI8Lxp1pTU#mcx7g{IP@}9u;e~wYsMQO$ul#%#X<9f%oBJ( z*F=MEms4QUU|PT;(8Z<%Depm3ZUTQ}LCut2V|o&vgplf!WyPnII+<|fVQid@p7(-*wrREXgN-#Wa4Cku2X zGITDN8FcOF2A(V>VenmlP*)2mFgwbFF6;sgT!1DKAajJw3wS^mJUhx}fs61tpu0`M zSFR{>PnUVkDOIloT7)6c4H|+0-2uX+z-!I$l9@-E8+4=T1kjizYY8X~bAxUmu@xRk zZUvCl_1pqIAiG%{6u?%$X66B{5>ViFJaM8)+>sT0Efz26)*o)iNe3Im9l0SQk|1Y0 zuI~V?5JDDN-U?cQfGqOz59r7=WRca|Tg9RGh4a=!jQ%$bv}Yfph*3dMmthVgXsk@q zomU)m?+}Zk3W#D*RCnZ1 z?VwRQ(6kV%BB$eq=U^TqXs(FUvHs#t5Er!UfB|yzHf#$L=&oG_(ET;$OlL$u$%R9S zACwwE89*eNRUTSS%Cv|*ZU1I1$M_DAEttDRbyfR-<{*w@Da}EaAY!L0^h67 z;W$Gw3w*aay8?f`f-*|K2-Jz`_&8PEkq6qu;RRI>po>9~$8bTay6;Ryy5<0+icJCa ztQU}~DIl}pJu%QUBIt5l&~@KtOlu@TchfRhGm_%=H88h3&Hx$B4Rayi(Zipg99uWNpd`UNm^@2r--L;;@f!RTU2Xs51FsQ!{ zs-404Q=lJIAtT=p&A`n7Ht7wEA|FH#BUlHdhE{-I@(o&C!3jDgT;H7+eDS*((-lx5 z0J=yTMDv+3odMCH#UniR3LK!DK@~t(C7` zDi?0>fXF*M0{v{D4WPoH7JxuM8>q%ZcQKO#C_AlS2Du87uk^v|9$3A385Ec_rmua^ zDa$B0{q%cIgL)+Ez#%6E_U{)^G0CLC^npc@2Xr+bsF>n`+*Hg23dbj`paI=1Go~l3 zAnpTJ@Ky6!pv!_86nGqYK-Xh3gRaS)(U^a-u6&#rXt~QiFtG&e(I6#iM0->27 zKxn2n5SsZ1hz4c!dUIybRnm?-B(oG49dDdy6L%C6a8%%M`~j*tK*bFxY7R&$@$oS+ zurh+mj0a*M-$CjY5MRNHVGZa4bp|u06;hy_rpdHJ(wu1lNbH4FmLexJ=oWhm(52=J zq_ULw1ZFXTViJ5QDI@3*Hf9jlMv2Su$oFP(#BGcmpphk*Y7Nj8ri=<8`woCS57MF| zaGO<$51a*Dd6{_FK{Lsqd%oXwwZO`3P-h7w^!P%XxFeqc=ni^bPz`%P1mv6pVp;W$ z1_Ij|L4Ld;qQu9`p}^tzK?)>yK?K}1WCqtfjwj$e4$uYbp!>-mNGWhSuDLx`+))== z9)K(Z-MY<%T)MgPGJzcZKq^aM2csjSA|DS2h;IP0V}VpwJv1~7z!$rNs(ZNiOpv|D z4AFK#EX#2tD3UA%Ca^*M&I?*!pupkS19tZVDbQWCI~f(21$Kb_HAPB^kC#n>9aM&k zWr4!2M+!tvkOG-s4+}p=9yV@}!$3CtI^HJkXoh41cumh8a1!ZR-3AI=M3|eCH7J0*e?Tfrsh$TK z01BW81}&H3&|p$g;&g183a=f(<(oj30!*m@L@9?OJg7tjCc;9)m6wr+6_OG-9p@iu z6L(|+SFxbTVOHRDJP%47P$6DMZctey0d)-2B@*B}+(F^6YgL=Lqdp=WKsUCcn+-}* zXl8?ic$q-q4NGN?n#hTa4Jnb;!%`WC;|r-QB~Zv=PitI`H$iDl4Joa0fu`H=r!_Wi z1(1;k#Ilq?tuQ9gt<9W{Oxa4DpvdQQ{9pf{xsaDtfd^z1dLV+51HMGXj4M&W(i9U9 zGpPOmN0j3$P+;mJ0u!`~i^DN<1uw`=5G6+-eLxP!C!qU|9pT&`yr39*!;_`JD4+&P zb`5->Bmk;EP^&#rZUqhnzJrdSJHfxq5(kGZ(+6Hqc=IA%O0i^|7 zMd~>;m?nT#O~IlHsUjBv)qad1gxgzK)VLnF&MGZ#=MO{Y*MLkCbMSVvGaHm1X zkwMYGkwH<#kwFo3^(+7Mi0_;-(jf}Wjt?2b>MEFQ-jGp0xU;FP!IG-H~< z2wGjD!Q`OCYsNH%5me2CY8+_xw1*4J(sF}2eQ9%SWPPl5gNA_`J&yi5wrjyo7ZeSL#01!VcDjNmu{UH_}Z2W|r?@F{SD z;z3jw)Cgl!5CBCG8)#sU2Q(%QZtO5?FzsPfQcyGm`ECcJlA@x(be~_GlD=Dx%@%ij z)jD0=Q4?B>K{KD@vFlA32MaiYm80Z5kY|}Sm<&Mvoqmy#OKkdyU!1D-(%?N?%pmWc zVO3yOkOf_-tiY@wXU22@#FsZ?+5@5$z-zdf6%;{hxIyCw&_u`yPlOv-vlKu>uAoH7 z4o!rPGiG*+JDPxor$B>3VEfq>xE#SvW=F;>$LTr0IR$t*LFtkcoGul3rU(Aw6v5-) zLm>b1BbVKWorI9gXS^}bF&6pN| zXgM>c86aBTjA;spRxo4g0nv(POdX(m)iC3?gPkh=H6`TV=OF(Ike-~UulNt~?-!6i zWXzb}fM{7WrWYVu&Wz~+h?X~Fx&xvW%$Tl#Xhk!o3)ua8fja&*A>`jnApeq)o~J(G z0+&{MI3U?~3y79AW7+_s<;<8?fM|I$rX?U+!Hj7Rh*mUXngP1w9y5ApfEGz+DRGfr zTG=9(R-j5nAKZoob-f)AFbL>F66>k9>Ee#o0tQk7M&Nn|T=elOaDs|nYf!0s2Gre= zF=ILcqGipP4uEJmGo~FNTHcIl3y4-Q120tsmAWfH%?V6@tl-3-Oxd|XHHm=&W~nQR z><>K!C0&LVMkTK48<@DHBf-^2Yx{I@M{{^>qrmLQk)^;TPz3fM$W#sxK~7e+Vur-! z6i_o<#*C>4M9Z2nb%1C&Go}U*EpNv32O0)nK(r$0a$~GT(+9G{pdKjd*zA=Al{ z?x68+C0&LNMkRJf&MeTPQby4D2eYFt*LZyyGT)W!dhTh728a%go1jxyv?Jg8dywcPacERe9h0}4YKGo~vb zTGou|0*IC~V>$t%<;|FmfM^9Xrad59(Tr&a7uK-d!9{NRLJM0Bc-Vrn3nXy45P=J7 z2}*#H7dUWbAb~4^HE@4`0`~v|q0sd!ga)J|6+<_T4HCLbKwAK0%$VkYXjwC+86aBD zjA;UhmN#SS0nrL(Of4W<(Tu49wE7V<_cn0j4_(kI6HuECGxs8gt^ywdqAGh?~|qUFt)u7GF-Go~{jTG5Q@1oq%KK_EDA7iK8If!x$ZcC#P@1L%@N9Wy2! z1vUjfGbRlMHU$GSCKUxX1r0MM1qC(*6*DFo1vUj;GbRZIHU%LwCJ_ZT1wAt+0R=V% zelsQ>1vUkJGbRoNHU&e_1PdEzc{76oo8$Cr99+V(;9_$!sN^@tUh<1gm*IqjSPQ5~ zlQCoZ1FEKE&6s|GXgM>c4yuS#vTx;##nI{|0p4*rJ(Hy zX;;Gsd_Y2wwkKE!yxdpFkx>!UdeBpV_q84{Vf3|LFewQ^I)1qOS{h8#{kgadK)tOA zpph#XGo}s@Eo;Wq0;1*2nEo&+Fe}KLG5rA13T8|nK(wM6(;Fr%y{$J)ID1==vq}|& zu=lo}Fe%9>3V{mr2TV$`ih7{wXpq+-%}}t{LFE-l2+~pm3xPw!z>!hW6x6?mga&9+ zDQLSNc&i(t=Q%-{MM;BDa7>@V%?0jy?f~s*lQCo30HS5hnAU)3IWwjuAX?sxX#t2< zFk_klq7}`Urm$cMj43RH0z(577~riMC|%DU7A0{-@K(1D79|Nq4bWCqkk27)Hn7iK zc|pOie)L2k|2Gp08nTG5Q@1van0K=L{_q}R<2?R7)b0UyZgn7!@? zEJ~t^I-qoLheb(Dkq)ddo8aH_LJ~Z9XDg^f z21@9l4jG6Bb;v+8s6z&#K^-y>4eF3FV~OJf%!J}t1msaxjNyeH%u14qDj<(;VOEk> z1dT;FGAQypGAe?`mh>SW1x;)9VCL*8OyD_931qKZ!1`xr5tt+>7;xy1;I_#Vla6JoB%mE?@x1gb;rXt*+DIdtJ zoPD9ABxt@+P?uo=BeWUCUm6f{N(TH^qoi(A4f z(9fnI3>v{)0Tx&T5&(rVhoi6=(-}Si1rEo~ZLQ*FOea90asm=6mf(7?W!-dfM*~tq z<>3A4>jb%^>v=&Ieqd4LRN!!YAd%&Gpl=3faR+Q3?*nKF5@brRK{Cs+<@-dCELZ?C z;m&+P0u)7kGsHES7(i2aHzdGQc+4+A;(xwP1c{q7|BwKU1yA8o;&NmxQ{)42Ch#aR zE7Ws2vX*2yDrAG_E5RieWV(`B0W@z3S{K3WD3PVa4idEl&0E8G5GjEyC2o+El>)Z{ zk0X=^k>bcwVgpH8E3hf>I6`?KDIU-aBZC6Ff~7f=C4&ODf)z-VO~D#O@qtE|`M^V? zip&Z;V3+YQa&s&2Ix>RSq&V(i0Sz>BOcUmk=HXD_a%9XlW17OFz%gB2m`j!$tTkJM zi9wNjy1y`&gaUZ__m2c<9Fi5}?H>~0fo?t)2S;v2PRE1O+l9H5_&6OOt!n`7A7SKn zT+%;%yD*n&J!EnL)UAazCLe&JSqwFr9e0A3aZGJ)6IWmYtsiHSc4T*CQ(!__qzr3~ ze*+mHh-!cWs{+=1Q{TRRI%rlEHRFIbq+;n9&BUgb(edT?7I6gzX$1yHRs{yEEdaxNUKzjMin4W-WZZoC_pgF%kSk2&Y z1kX*vP5L9H!~>d))n)iE<;u$fT2l2-%8{|qm6t`C!O2$pKa=N&qpnw5*wuZqGJX<5l4YFXrlq|$9q(Jo}2W+_@*r!)OKIAiFx&WfN&6tuv)0?0*e+=f#2SC2QgTvPcq_W_C zz60_zivlxftQfqA>>kJ+;3-S+)D?8O3^#bG49E0?VqB8-;DQO+=deB@sNBU}T(1BH zf+jQ&poOmlXiAU8is6ok0tcw?a0EnyECclrI6y081g5Yl@jwC-ysD8yL7dNwsYgj~UY)2?dVn1>#&9^_<|K;{|2kEF~_`)CGs*8PG&AWZ@b(3Ecosu!0g2 zXzIN~5|p4UoEU->SOunn)6^MBa7sXg$~j4125wNp%_0D_Qx;nkEsz97Q9V)|F@u-P z%>X%Z3BmFKt03*Dx_wrDhSJD2kE1L33Cfjz7SGhY@xkK!*PTdlkGa1{QLVa0AVv zg8c%CK~Yfj)q~^j56B;&t^-dNXmz13!#`O3aX4N8Yr*RM8z5~U?=x93ya9QU&y48- zh~_q9x&xv)G?^|)nln8Cu_4}n3vwaM`*$R>>e0Qgz~R^cUI&5I#tu;S1FcWuGh>d#1RR+Zc&2}l;!@`VEhFM_WXx9LnXV|!rOLzMc#AJf!AxK}n*zu5AZacmNe%@b zw3+J*p!UfHNc#j*46FuK53n@=(8>sZF@UHS1mH8*rrZjknQO*7eCCW_Kr`1pY@jsy zg)d8!5qxw2lVb~5|>2`2V-=^uAaL&O^)2F~W|29qEFUut= z%K;kA71U)|$SClI6}BVr)&7ITdDZuQRyKDL>IOp-M>EGa- z6}zV^DZ-R}+&$e-5oYv)J<}`UoO64oFHz)Dfuy{Dd!~y!>Oe+>pj9epwS@)~XeBXZ z){{e@@rIZZ52(iqsY?`iIJrUP97q(h+~a~|mJ+8x2x#rD1`}wtsRq*#5rJH2m7~N7 z(#z?{;SOFt!(hgAL_~q9UW17PB*OxVU{D=p#`FQY4i&Usio~^?A7E=aL8l|2baPl0 z*c}&x)_01-5(=vVy8@d+J<1AGS6*fwR#3TqKqN~*0W=}Z0cuu3R{JP%3V11S3Mha) zy+TS6++1A?khPJs~6at;W_ z8M`bFpzQ>pjYu4z1@oZDg~ly2B5rq}$8A0Fi;Q>Rj9eCs$YsF{4^RyXUg`#FvVoH@ zC_?LDF?s?Tqeq}IdH`FDUH}C;w24}X7Nej_jnsA1cO>gcjZqXQV2e=#5!xdK&ZJBZ zkch0ul24Ii5}Xtq`_|78SL6h>*}(05%>3{I8hTHlq4xk3df)^EHh>#yf&!%Vsif@4 z0op#K%*&YL*abFQfgdz1pst{yzz-e}SJ7bN0gr}*7aoK94U7s>3gET%0(U{{b0POB zfZCk!Rbt>3#cZIaHhNvV15}pm;6WN8*|ui7xT7tsEPza0kzUubfm&qTAeXZtt&iq5 zV>$v_56x!AbO2=W0iG;H21u`mQH5c;gE|)%q}croa)c@6jsTTFr0uMzCuM7eBcq}w zC{(!|8MBnQK>c{ox@-kda}d%Sh1L*`E&QP6eoWAl*fji#**RLMo2QQ6fPyjE_X5yQ38sV3LK6X_(AQG1N?~I8iyv+4t{gy z6Z{Gs3TkFdcR;kN8Pfw0ZE4Q*1VmeyGhG4M`i4JCLCNs|Waklw;|bv`1t!NHwk*w1 zCI)lxwwD87p%ymqYC^Ec4zS1{R=9`)iy6}zVFeBaCQYU@dSUC zKq|CkQ1Whi;7t}XjptgJf`Q`(}H%VmrX7c{&;*M6Rp$2NNfPC`@YR?alJwG7!kQ+T`LH680 z^AKneILM+F5l9+s5CQdEM8MHQu7{Q$m@e*UkLn?IXu$PA?dbs7(?OX%PeAqMQO0aVX3(%6NOuDZi2Q@leF3CfBqs|~w+KjgJ#=FV zXfT$=Q3f;^E2zQrhFOshWX=m_MP??@{vhxeGGvh>Xn#6rBo?}qT)_yuj0QAU02=Yo zU}6wh$D+WY$$UUe$-=3jp`qb}d~*P}3BN-GR0c9BSS(jyQD7B#$Ev`gU(dKlM2UyR zL4iSm2efw)6x13_J48UuW$==Ib_GTSE(K13H{kOBf*5#P5Cdo}FbfY0cSU2;*Ls~I&ja7{JIC3OF=G48M!?aI2;#9XQ?pob2~B$gfbu& zn?tx-j7;^Q7KjXp&`@A-l*tk}%m^CmVQ|y{F}W2O90jrj4sWkB;HqV0TtEGfA(y1) zHVJM~1_cHMMg=BECZ|9D|NrNAk`S0F!F`#Lk*VI1QIW~vKGB#HlxGfxaHpTS`)5Ny%`@s9)i~WY~a1=;3JlqxEsg$fCgNXp*JGCJ>^)>S&Rr09s$m;&`HSlDNRv>Hkf+ zbc7zjH(GcousS+q3w)byYsMwc_i}TG#Rjktc2r&-_yhej!suF z=bFa!pLO~UbFK@*OW8mx7?>Ryvp}2sL0g%YPM>YT<7RG49^} z#ga>nkuiC?v^Cc{{tNG>fj6QugCg+6yX`luxmZDx_iVWI87EEWv*n7#P*Y{g#mvaq zKfTV5%M@h&@!w2x(=Xd``7<_5SGMQc%Gfadrae~{WAbzt2d*Q=e^^-^8MwLSV7bZO zv7vvGxZ{kTN#c$=jvM+Xi3=Q);N}KNGdS{O3Al4-PH(7Zm1lIF9_`50B?3-23Xao2 zje2Rv->X51YWhz{E(gY@=~hl$P8^_o=*TFreR_)%mwWxsbKp(G+d-R^c{!vU866qH znfM_{oI?OZ{8$I*3Uy5JxsBj`br|Zez5uPd$5g*{e-mgQUOk3}PdC9koiW54E@KyO z1v!)r(}Erx;*U->fGmcZUytzd^WV+lpm0GCiGOFYhtM_f)jyaPpPmU?zKALQc|GV( zO*HX(1t!PSe?Yfeqe&<*IqqNHDDKFKDZURBbi$b8)Bd!AX0D(ful2GE;a3vW^vM z9W%lij~_IEjh*iA#-&=n^hYzoFeXGuF8|dm?#K+)jU*1W1Y$XocxPWT*i>+mLJ~&_ z3?%XS|G?^@nF2}TJ?MrrSWF>_ql6NY_}+g=X_iR}RQxkKLTcxophy&f`hgMTH;DMz zkIkSNWRM?p3we>GR#We3UNq%@9{)bG+C$Lmbo~VsU)O zkfp??z~U&7<@n&+L~(%^(|J9(WCE!>P(a{PDI9Liq5=RL* zByp5*KoUnuT}a}`L0N)Jz!T)#LS7_^1Gm7ZDqx7CBs(Pa@O0zn$>mUw;%rb5Dlmhy z0*bSd#8I4$B#z>2Mk%N%a5sPgm;rPy1A`-*J7|fW0)r#BJ1^sOUN0^#)G$Rh6uEpu z5=V0c)H3Mt65Bx=;o+He_c2H=0jFmMn7f{Vw!4Cg1#Sfv#}Ct|d2#6kd|lsx$SDk< zh=ruG`yg>xX^kX4aSC`VE+pI;q@XRy8!*+})3;l4D6&stW@4{rteakM%ptbjz?+Mc zk#Wa#D<7^h-$`uT0-!qCA`7Bb;5I8nKnF=6n~|wrnZZ#2dg+BDOO_Ig0B9>AN0tH$ zIHI79j=w%!>lmL;U*pRa5)E!FVVxRhL|+r|c=`-+M>%LGj{&?U0Me*d;BZudbW)f> zeH73QC<^QX)22uJaRo9?o4(eM%a^TZ;&gEVpK1PFwTx4y3kGnBPoL_~B@Y#zzRRC0 z3?d%J^x(_%%m6NB$Oy}PkewKfGIW>WT300kYUN9yOi@4vAsr9ipDxhKDZ&^!Es)C` zWTj;wmny`{Js>O9(c6Jkvr-<^TI6tiz?h}Nz+D9Hj(}Xr;>egKFoRu*X?o!=Ci&_7 zL0sXC6Q`#KaV0WtpT04a%iRH^`Oc#tpumsnIRzfa4|k`53T4Pr8Sp(z+>Q;*Spqwz z2LyA8gWB^v0z0PX26NdmGEZL}%%#dWdHTg*E@fC${0ipMXPh$KKAKB(x_tD-}Qs*JOy8-{YpF;1Nx z5XvRacw~A;D3^xfh0bPiMLtl`&!))hIJd7&T#=7kf!lEgGw2uwP62SJ`Pic@5K_Pz zWD0x=yvV_bGteT#xDptdr|$~m(q)`H{Y4m8GUK%AKH*%|j9;gp2qB8K+F262avSN@x!wUD=#8iW!W*`db)N@xs@J?p18MskHR zZl8WVlFNgs=l^uYC@v9A)No;RoC`V^h6(Bzln{uEf+QP8fgRJUqqscena!9kFe!k- z`T$dw8Pgdi1#ZVPOj!!tjw_h51SU^^6ov3SZ#0)7BsGCO-xCe<{AZBob)fdar{SrV zbfBK^SifB-hD(f*ar$)USgt=z9p9%r#&Ov&t@=K_K8`DZ>BINw7vs3Z8MCIpjN?)O zak=BU9GNElnC=(PrNDIN`}Bf%E+wWdKc-KK=Q3cr_G9|7c&;GJA3r9FJ1T*lfL6qVwmS=?E3r5-7P2@fFzPa_19t)$bs5$&^Mbn0vwltwOyII$y7zN>cLG-c z)1IHx?w23`pvj6&M^B z{hGcuk!!95cG)AprY9wF8R3w9_G|l^BraV>rjFm!Zzpr5GOhYO-6@4DoaxN(>9bR~ zYM9>ro-UcnrNA`d&vfflE`6p=f2QZ8a&>E5`2%+x3&?SxPA#)8LnosWhrmv7{R#5$ zw?EV6)40SKcTP7;<5H0RhS0>!4f4e{W<}7NaR!03>4j-rL5#bmA4%h~b)4}RZa5QI z-E?N~><=Vh860;Z%R4eCf;Qzd2&6eN1c7e>oAGzLQ#zM5)1AN5>(jXunEw5pzA&9j zLFmxB>7ZbCWCowA$Kbf&-}KArT7XapeU)ptiUFaHvLxyR|?aKf725(x!jmu{oB4GldFbN?%=K# zaYaUug`gw_Y6&qrN@nvhF)=W5JAR$+l+C3gb>ed~^h8=lX+=g*lZgp*4i3M-oaqhO zTy~H#A17H*wJ)%Q6}%h`w1I)y(IiWOSpaENM-2O@&h*e6E+=--;pmR1`=`&#;ZlSc z8OR1HIi?GWa*OCf*kIFn85Gb;5%8IX#9G&%%Vo!Od(HIoxm;>)8@{xOD>Cx1b31;0 z4rZ}&J3e^`X0dWR{`lPll4ap`>|D_RVljhGc2aWVW#o3exg4yDk=t?mgz46KTslx! zW4Lq~a(PFROJ(!9WSEzJY@U9QOU8Kmg*Bp_ljZ-jO|Q%6QmXIx-zu)i#3KnB(qnc! z`L!9ulK>4>F*~;HXb17cA#!U@H-UI!5Z=a3Eg+sKXb_Lt@#vHW5Kjc6@5f89DZ&um z!WnHKIU&%%AhY9)DPVnq+>V@z%#QQwXM(u`5Mw4y0Q2}Eyd}#TK^pnE9T#XJ`M;EbiubGQxqu5SQVKaL048Q zGC>A2nIS`zOrQ&Wm=u{EK^MC!GJys&SrnNa!2_0{Q%)S26`37DcSk}p4#*VHb$*b{ zGj;Ox9|c@;Y#YBefd*M0_KC?%w|CpSWb!BI)z#dOAE zE@9~>pi6Pjo@^0UU<56&W{`Gdfh}jAu3yZR%XDw;^m)Zx5%p^(w1|U}A(JALrq5`pBerXry5dftTCdWya+r@eKx$7N466X)J zi}Ub7Bp$787w6%HuY?czM#kO({1(~qsv z#X;9af!MSAn#DoU24dfs*dh)}V<7g$l?~#cC&UTng0OJ0Sy_0 zCw*iTm_Z}etO`s56WBrLrr0Pkfy`E5vSyT-&Qif8&NyMZOa+&^!2f9-;tGtQHJpqJ zjM4%VrUzGWS?H5!|MXoITsBNwrcVD+!6m2nXVN6`EJX$d7DuKM$1_tv92RB=1qR4O zngSDO@e_FAA(H~5!1U=Zm0a4K&1~RFvjf7@D=N9tn10-x{-Bbpu>Qb|Nuc^coZImc zgCdjTm-S$-7`Nj!5O>2ZFjth@aW^QNG&D>GDTXHe7oAf;JYjCf8KBvnmL4!yh}%&> zk;(DMIWSL<+wsU%FiU{j5oE+42#+6D>uMAUeG0HOpYsVgLyol z@}J4^!ecOxo7+(uWc(8_kBi$;O_9lQ%?B`#6KX}nRFJzkxE(bWnH=9Vf_dx^XKk1a z=CN@*YA7-}{+a0l=CVSp=vWQrv2Z*7fv}h%Ie*I&`3iyO69vRSR2uGIVk;w=#X{gwoDF`tssMr@IF-fS{nW+eM zFtI5Y5Mts`b#EYI_234#7*z1cMTA08sMv=~2r&_;*on&sF=43Kf-49yA*k37Br!oO zVglUt3M`=6uM1ZZn)#s$S6oAg@j=BJt|P>Fp<*|X#CV`$8*U)faYMyAZX(3Epkfc| zkpwxRf;(;@6mmetCfr7du|vgPAc?U-#SYv-sAGkS%>a!aK%$n61-b|Y&4mz;b(Y_G0@r=>&EkXda>=aaj$`>jyI=+L6%R?0&fC{+sf-?6H z22ekJ$+YP+>bPv#K$ZxUPQP8prNngQ()9mzToR}@F)En@~0x3k;#Hhdm zJ_m}?amlpl>l?W2Y_43ICJsK+nHMCtfH6xE?020k$2*s%!AeaQN0ThaC&+x8EXOyO zra!Fbas|0hqk&77X$~>&aj1ja1KH&6}Cpm^(G%yN8!EN}F_Jcu zqdh2TqvZi?$q>{VdVrMRSrr%^?|}FkObnp*2Acw-;}sAew0aL5C@UC28R86*m<)>o zqvH{f0C>}(Ir9QW1$G4%#|FkMfzs*nEnJh>)-0U_Y7i?<5_Fy1@RNNyb1RoqeaCl@ zAn4M;15HyvjSN|C$0hr~EE#Uc8<)T=X>P|BQ2hitx!G|6sBU5gH5flYSQ6ZhcR+O# z==@yAom2}+>R}v>X11H)IMDD8?2Cx+wlg3#men?0#rRSgBpen zph^#P53%DPh!eo4f7=&=njAaYW{ZOsLV}kEDS(~LRN{C6E(%IrELlpR&B}}d>!z=7 z<8l$n0PjarVga?=7(fJzz`N<}?Of$dE$!1A+POq67J?d*td4U)t;V0?+~S}KZbnB| z(4BhXjvS8LpHCMT_$kiK4-vO_WO39J_$AJLV*2_HE-9unozqWuaLKYA0bT3IJN;b; zmzWNul?m&6GlNdL<^U0B`-l~oL3a3ca0T-22kUkO86xm=`kD?dS(w30U!PBZ)xjkt zgU`_E3Y}aMLTDq()X8PWm^J-mCzm|qpXo0GC~XqT3(zaLr)i>-aQP+|dHmKu};1m^{6$pUZ~pEt?`M_(o#x>3l*gV$*eQv2$&I z)6eysMe?6Gw*-R%gCPTl6LT|YEE=*bMBwT4H&eKlvm9YlWSzcFOIDGUU4cp9$n?Ea zxlGxPvVnG1PUlNflA10wjVp)o==Az&T>Xqkr}IzeYGFJ&eadvMSb^`L^#$PODT4+R zi@^8kj5D~T86QrUox$bEw4!x-!VIoSjHjl5p21biczSx_OfF@{Gt;NeXdm63|2dT59B|BJgkex0zfHj8CVV&*IW#^q-zMi_4Dj()0zhxC)p*G)|f>Jex~{ z@$z(=*<419->2u#=8|N5IK6W=m$dX1c;|!>vZ@JGnlNNJ3J83kzJE5?a=k;KMGc&e zcN!;&3oK<+V9{sf0d-GV6j;D3SU@M6us8~2DX=)QWC{3BpE8H5Q-3BCBO`Q{i50ZD zl&Q{%K>;*8Ck0A-42p~jtf14DITTny9V(XTYxOv!#Rb5rREg2?7(+H6I}-~FBMS>N z1NZcYdK@BroS>CMjE**-%W8SqCY=*W<&;ujbmVvA1r>iXObU#=915(a zOgucC+~C&!2WB1)2&)0qlLw1E01Y~TSr=G%SRt|tSa?_f@VfYvYbfCzys#|91s7JyGB!@nT)-8{m^}UP0xm1YNz?x=;L2faoSwaq zYdZQen(2azxV#vXr^hVfGGUxFec~dnQVb=ci@EX{lc%>X<~qZ50aSlHV8~Kom~Jpr zP;`315-xtmr`sErfJP>7Zf{x2b(xXz=Jtr?TpK_%=Sr^Ui~{GtLxeIcpj8&_3d^+7`HP;-b?_ATn6O~Lr^ua_W%k7?PxF$0(?w)>k9oGp6r8)ildai|xySEo^ z;BsVSygyxW3zzita~rvSGd`MrY7>_n;{%8g%Vw^>ERWc@_e?*#iA#F=rj1-O%WbxB zF^W85HazWp6WCgys^I{2(BlY;`Iz?|uE6>>^)b3sEip!@`0Gxy;! zJx6T@!~biEcx zxds!95;LdeObiN4P6}-;icFx~oUI7jK+Tv9uHwKW>>QBp zJ!rW;cm%+b1C+j<7$QO9pmm@e3JgvR3QV=;%nbaX(u5<+vEd1lmwv$fH+|oBE_22m z)4y%!a$tST#Qm6Ydf_G^nd#v>xVAG++s?lelz6zN2kzoBWBT%Vdgm@KMK17iFGfd3 zf&J5~;)O#QIj3KU7xs|x0~JXEN{pbTbj%8j){I7=<7Rak%miL?OgBjou3>t`F?~~l zu&w}?ITHhDXBY!G>wn;!{ysrCfaw?8bjL(t14h5;MTx>`(^u`{`Y*AURe{Cv21AzP zf+z6vBUl_~JehuQHcd`(HMYtENm3 z+`}b3ed!)9b;hOB&+g&UfoPfm(BH*j-TS$;m>Srp zZ{N?Q#`tOaz5QG&O0DdObCJOtJ2*fahnO4{K#j=b3<3@8(^U>|xq-Ch9N;QbYGQZ% z&rs-in<1NzgM|S!bHT(2ZuD?~G%$nIvmE47W&AQ->mZj?Jyf|+HXjQ!0|V${3`R#0 zfp(asyr4s3SV6Zfu<&vyFo6#JWpw<>An=t#fk~fHM~Rsid176R?lgAQ>iF+P}HdWcI+wufC2w9Zz64V3B~B?Vx7Mn^$`p6NRd zaRrP1XH#HNWCbS?0noNXMn`Ue_UQ_Txnx8yF)FY+GM8k5>Mn4#p(V z>FtNPbmaEDMP8lyb}F>12pThE6zG_K@i3Q*asxX!@)X$>m>j|3dhp3a(D3eiP#6h- zg5kq-iz8gBjPIt$9pTavX<%1i(q+(4Vgnb+Iv@oPrq4OTr3#Am!$-L67`vu39p$oD z>|$4702Mq5pmYwp;|sKw98?9^fMSnHVE6Q-qg-{2UDF>P0qp5A^YYAiP^r917R*X&4*Ph^tVQiYtb&@L|lwzt+ za_KWRO<#SIOOo;R^rI)aJQ$m%^PS>~U~HP6eu_(%v2FU)Q(Sh8Z>C>4#pT7=G+q8Q zmjmO!=?SN~JQ%yCuRP6_&e%0w@C;YH&`lQT2q~x}WL97jxHG-!43`dL)AaRcxHPn( z=?uKv9yC`CSy;@-01j3KW=GHjvw{L>{c6*6rn6io(yi=J^FRfY0*f_VsX){8z_XC( zI?E*&^#+_0A$J0R^9R^SCeZX3qrhEoVsb(3ih@d>0FOzC2|zUapvf~jYB@3r{Fwg# zESI=Y$9lL^!L6&F_0u)ZaXB--ot|@!OM&s{^xkt^`a&n(Oci&$@e*{yf#Z)iQ^f_2 zO+R;zOM+#a1b4=CK|dx@CV}|rjOV#p7-vjxJI|%U_-Xp;^IV!t4IiiLGmDFg!ET0O z=3s(U+DZ(L?>nY5Uf_~q+`e7r0+$FA+YZph-v6hYUE(rhoH#xA64!j==d6yhg^oO+ z@fl7?=2Bn3~#RVF4*&hA3fD zU~ueMKfUTQm$ww+j28xJGo}y)P6bBjp8M(dFT=JvH}y;hEvkboLV?fjgX$tss~CB) z1ys^;_sJRJj$8t0IvhE&1m;1mXn`rjwH^YzqF=#L6s3OxUTXqc?34JMOKkeuD_s0c z4V=^WUEwlhYUG^$@d}r;>5^k@p!G7K8wWs16x2_DwY3Yhh88RY%0-|{4 z{fUt3`UaB%r(?r|={ncAIZn7YJ@y)xw7{Rc&>@o!(A_8<_qKOj z7xr`VeZ~uFf zYZD{m_URjLb9pm$PMiMsHkX^$3np-roELP!nF6N*D`;MO-If;c$etC$YBsPKOPS-k zEz@)FaH-TU11;Bpui@cQU{v4}_z0b|;!$99Tmw4UiV+rlAbA!P`Hjy}uN~raTmd>r z+VKEemJ%aqI+{^n2P5RxLr}9sfdh2J5eH<;Bd6mTR@N-XKONIW?{e8Qed(AUc9+YF zv1R(iyIgLJt90bGY&{fmkexpm^l~8v+~K zVs!k{F@3{5E)mIga1eryt^_%1W9Rg5_qkLgAg1v$F*_)5I)aY}cih05CD1k9=mA$K zTR9atLD%@PI4FRf+Q25z#tGWp!0gV;qQI%ZsmZ*7)tq?(n*xhK`}B(s zxFi_6roVc?6~_2^y5mDG8OF}(aS*EdA(txSqv;DDaye!^W>MgDVlZbu!3wHd83npI zLDwH~fGRZ(ZpY1xilF`vXo+4nw<5FSx4YBC6<8IxvXnqGOm}y+gRYO#04+aZkOKAM z9A9s57k3nfocG7#;J6W_pNZS?*WKw}kGPB&H&3s9#HGf16Et@{J@Bfy==8mhxHRfN zo@*6XWP!}ru{!qsYyt7uK~o~Ej=MfIgLrHZ-ew4o6~dda9ITH8!s~?am_c(Vtd3JJ zG=TJhH+`@=E;|KQ$q14A(+;u$d~*YfBA3GSl*e4kjN7MoJm&J(SP4qD@~~vdpa5Q< zh+6z8Fgu=@HvRu&E~y}tqC>?d3@8ao*k zSU|~}ky`18-{D@MZeur?7QbShZp-*&}N~rTH^1 zJ&5}rfwugx6LR0DlhY?XgShYRGno7Cfa(EsuTjT+iO(UHt$7Z!>?p`G_*oT@rJ)K8 z#MU@?*Do5p;0lvQtt)SUGB&)jT=;@Z6|!57^vd!UDE>Lo!WY!dL|;FLD<1JzmQgRc zj2Nd(?|sQ7DGpAm8`vfV>Iq^dBT`4yKFWA}8oS6r&XJ6WI$7r^HmTwux)m@>WY z6_;Z0KBS9Wm;|=5DliI6VNwtfU>nj(+p6Pt=xuh9Gr#qe#6=oI@m^t0yJ=X`u{^^Dv zARDnVK5)rRFIp?;&Ho$JnP*U7RbX>uEED)W{mfcH4IYG`!0&161SO}pec;-}_;kAE zM=njqr_+-^axG`-_%xm86PKoBFQ)>N;{m2DB~VwQj}z1v(Ph}eEYLsQ?-SP|#!1sZ ze&VuVoHSkQGnX~vr0Hp&x$?OCI6(ts2f!;r?|Y|*@c=K#5*7ilC9G=|nAd_vEd(ZTf>*eKq!m~N`lj1`F@(4Ty&1fhvfyZ~vnD+2Gf!6r#;mvYn z0ZB=Kj&K5v)S5Bv;B}HxU~=36k(&Ph8gxt3bUaKg%Bq8@Hz>CPCV9YX|Mx`oIcO%B0J1hFyt8 z0HnZC0JKM#71Ujyz%DRl`j@|4`nr9b;OiR|L91{XvlSU2%~i1N0+TsF!xT)87ud7F z-PiW%0spwPl_qm4fQIE*6c_}ifKEzqVysn!Hglo+rqBJyRRcNz<<}a)Yv|5EGd4W8!w^p9(&AhRG46oWw0)0ZX3o) z(~mQA-)EdOeK`wQ@EL?sW#x8YoV-1al{=G#aoY3?oZQ`vG1FtXxMdipZ?ELyP5{mP z+~VfG!#HF5b{=jA_nF{!E|Z%g3uqAuv*QisECpVH83<8n&_-g2D3V(6MdKh*W=BxT zIcvHdFZUtF8Pgg0xMdk?iZLfeICe|In#IZaW7)*m>$Q^J&|$t^bh>pHH@>T z=L&GoVw(kO1Pf2E6XKSit|Q1D1`!Z|2rL)m4r81({huIr72~Ywl|tM>jI*Yn5#sh? zoHboim>aZ{!Cn~b&KP0t1jYl?_X=}MiGZ>i=q4@41>h2vNr6@1!1UL`+%iHSnF*j3 z(jPzr6ADZM)2B;{aQ8viw4zPLF*GUfaZ7V_yqYfVs4Vb%x{nyQHRF=$9b(*a(xCfy zKsT4M@G>eeg9anG9T`EF9Ww|lo_}3)xmOGH?s5p6)Nn9mEFl&h+Jy+(&u0F)4sACsk2k5jZ)$Qi@wv zbO~hTpAsVC1|jaNrPzusGo3hdZ;wF7vsn23#7TF7(Y+n zEzPZ@x(?*t^`K!`CQxT?52%n50L@VC0U0H*kqPWxCK+xu+apX047v;!pbkA_HXjEo zBNr1FGZz;Fx4;UJA*(>dY7ns&WE{vj2N<&ic7WD93ap%-D#NYI)G=rJ6dCSP#&6TP zWVtmNzfCuhtR^i?Z zqTSWFpD{{oFpZaD;W=LH`L@-WfXvB6V z9+_^V$8F8{c6x;#wz+lW#0Czk>!#uZo{ zpFoNh(9qFzD--S_#^&j3O}LANdl?m2^%?gtf*lM#m7saLu_^Z^`9?-)0I@hIu!Fo- z0X}!S0&;Xg^L7?9ZUsj9U$9`ru4=loIkzR_@9DMX+~=K6e3~W>S~MXc@P|u*(Gi8q ztjnOl;(#U!nt)=kW)uNisl+7EI=#<=Tc5Fc`aTQpB*w<+ik956jLqBaEx7|38GlWm zXa(XuzYb)-(+(>pz-)zmTT#qEcr2w^*4aF(kAYmmI2L)Eg1&mpaXF!f- z68OUf7MF*M9|4JT!^CAAnF~P)38Dwt5>N^TnFA3M(_jMo9z6MmATfJD&0W^l7%-`iu{zAG77wW_&pPlP&jT#xL93?6@r$nNHl9e!!kvOzI@~;Fkm? zW?s-Os-WtF2XuIIlEA6yAM8Q7WV@gP_d#aH>gkuAxtB71SiQZB z?+@pe+Ab8ry^oRc`}T{W+;2hj{&4O}CWI*pIozT$Zy1#rKy!l(3OoWxCNe1S3Ot?O z9K}78@yYap7;dHM_R-+nwIPLj8RL`f1u@)AjEqmFJLYrSZr>2gT?FEMEa0}<9vjbH z3*tEDbIVPCkjbsMT`G~A70ue|e#zWe?8{2VVIRl|Q>VX4<<5oKIXw-@PL~XXo!cK| za;u?Qr-EM=?=BrPK*bp zH`j8zvbHli&iFe0Y%RCEzywfb%xJ|hhf#rn)p5qx?SE>ytr;12Pq(P&ZezT^eSbZ- zFeBrG?Ux(4hpTDgBRGJf4&*UmkGnW^LQbb)T}^(Ip;PZw8Y1+D#B0AaClJFbDS zSh*elTms9oa67)43uZBcS)aSPow(aURTZ-alY_w8=?*>IqKx0BhxKqPGk%+1)x+(~ z*fo7$4|fb>`*i7E?oh^a(+hjKDiOG ztr$N|Up9%`l5yYk2a~u%8GELiP3A6Q?3uoDGIuIt`*i*(+!BmGrfW>$wq)#@o-~C! zhH>BY{ZqIN5pDY7J!ll6MxTFm- z^~LlD#M{6PIz{{q7l{18l_k(KJ!Bf#fNRsZPk_vs&Yi`0Xgb#n?m&?l4`zykW=Jbc znOFqggLf7vOfNK2keJ>+gPWJ}>-4EJxLp~KPQN{a+nDj#bpDy#N*qgPfi9>LsF`j# zlUqY-&6*kF0a@CA$&|spgnl))2nB4TeBbJ18rBxnEsGQL3;X)ncRF@a}NtK z7uB=WG1e$EI8KnuR$>7yTLLvim9i8VKuZCX1QkF#a`sLan8kgu{*6qQVz>f};{%y2 z#Rvr!#{)81imnPQjvb;|in$6bj$3526rB`U9N&n5?x1CH+#-{u=%By?I+jt^KLF#0(6jKyf952XZ zDW-z-b7m>pgVqTPXDOyBusD7Z%2G@REo&9dQp}J61)WfqVkXD{_AEs&P>^$EDF!(% zX`QjXY7Tb~%XHL^8=CopXAfUkF$Z5rJ0L16D zV)!ATz@orr#`Hu8H1}b~^gu{~#gW&F;RA@iA)N(Yb;07eK?ZcI-+wO9`i?u&O02x^ zm=wTk;ciGPv70gdkN`Dk&6p-gGJ$vZ&SB)O2Q7#O9c<6yI01AlGbpMgvXnRk?y!Rl zSs|&!%KM%PwEb(9BrgM#1E^)*zyw+Uen2t{bU3WQeX!C4Af+F`N)Jhb6@VQqqQK&4 zX~i%>5JG4As>L%jlM4f_L;EPB5kAf2Va=%}K=CU6Ao z#4n&A0r^IQ>4UTqn`501ixOx{1fvy0i!3OB9YHp-7n(6O$bw>1Hj5QhmS0}PtrWUJ zR>5CE5WIMKgKU<-b6zFLmQ+ya_<<$Z1@6HFU3uR!@w^B7WrhqaavlhQ-1$Qy%h6uo z1+M~&Ci9HxUW>U^c`ryQuqX(EN9Q*1P2b4Kqh8Oez~abe#n2(Az@orw#`Fi|95yQk zQ1SqkK9I!n10>36#jpXSpVy4(i!>zBG=P#6s~OV=5dQ!l$bL3~P28a6JO}ucBtYJV z`Wl@0B;dXV84pTBtlW+tR?iUU23;x2HQg{tLDWQ%mB~TDP+%&L0vCAegqj;@-p>)_ zCr;3DVGK%a0-#DrgXw{gB6z#t2chX@OSsoDzMQVQlv_pmfkc*qsREY*s{)(A4R9)X zA^|c&gXzKal%?F|j1Q*YS;}qAcw@T6GHx}-C)4ehaofkewB+|go^AfBA+2WgM7T;OMU5U+Nsp*%ObE_u3 z2923vQvgAZi8J>z7u5z0S9iTZ{3@bjy|8 zru8p*6&yg8^FY1sfUw*FYVZyjgyk|QmdhwO@Vo$f{{krfH9$9hvpeeKfKuQEsVoI4 zfmh%Zc!5u;3^c9^OU!SX6v~z>vh%!Rn*MerHxJVaNlgRxF9auoQT8R}};DOQ~i{k-FXr5x_0pESWpvwR&qd;XNizB3nSRt7O zEvrDqA@4JARNRt=lvN<-!pbU8>0)WcfL2!3gAT}HafFst>^#qyKb3~4YHuoS{6r8VZq`EDqkQ)Sqmss zz~(gYXK^WkmP@H9unHWRzIrvcPd&IYfJX+nO5n6&02f`H(5ivgiUC|^LVc$IiVTo1 zc_F?7S)~M8m<93$C@f*ou?19yz6N;!6iIN8E3m`Mt_?EN%hqtKFnti5F1VdruAV`W z15`5$f+Cj5!|5IA(|HJBP?1>W=WJO$@EP*}1mKr9AT zte}CDD~zCkcpwDIhTwy@J_y1xqCVpkNhNmBb}o>T36h}7`hXy)=_UvYn9p30b0gS5 zRDlI_ zgHMB~0=SI)0ZIx?kfZ<-e*&tUVMzp3yR$ex056^grTHFaQ1Bmtx)YS8lpuDpXfPd+ ztOr^A1nl=8U@a4*K@s~wFbmp}_#ps^H(iEb0j7W=x>W;K*ymZ~^2%UMq$J zpiBWy(a;RSwpM|~l<9*YXbR1od4>!$+i#Es89qZMOW*^qBIx!zArrjWJ>yeaY#)D!{N9txu1I?#-13ZDXt z0+$)n48G|LpYte8zqOuQx&8t;wX;ID^@3|y$2p+l78HpW1eJK;34RVAC`K26e930T z@B&n@ae}Y60oU>mK*0|7wGuC=xKm(pl(k}50pcX;TEU6j^!h zf?^L8!W{yjR)W9+(1Irx#~Xs6m~IgOU8wvGR6ekpF*ShAUu(_`ZWXg=Fx@Z_bgT!p zQSS&!n=!S3tbHH|v9<$j?GJ%0fqroMeIf|;v18Bl(;K zR2@iJ3d&HRlmjnA^&lAsRE9#6B`DXkIfA-~j&rU~7Z>=>%j5vcG&^LK*g$2LCi4ba z#WG0C5~f82RPu8}Yr&R!s7g>QG{}My%@0|qN>IJYD)56>i49V{fSNq@W=wlPvCnSC zv;#z!nKOghaNtx6ZT~?ESWr0%E)k)@(8908=E~d7$gRMp$jbAaiCaNLgNcEqe!BK% zZgoLWKfzJgieUn%BGj{DSTQ|$Gq)~sSA`8)`RhQsDB!RGbxqiymAx)nn1RGWshmZZ zVTB|#+(0e^mz|&{rvf{caO>cQgI4nkXGU_V>%!S z4Yvc5pxI*dkOS4Upo#@tOM!wGWGXvIJ2?A15CYwPaTeTb_ydiTdQi&)Y$zv4-49vE zJ)lT#<_1Oa7bFLKkcL$Hpb~Bes6+!r3y204CeREHs$pR55>R~)Nu4cFt3Z{BBBYJO zslYDq6CCN&dAD-g1%P{e3}#F(K*0^F)4KlR4RpXoJk+09ig*@qhXv}~>1Vca%d-Clw}T%{|FDhQ zzaHGLWP_$@Hk9Tr2Q1z(!668 z_ycLnu!2J7hpfP3CP(=~N2Y8(W=3J~HU$<1?zIZ6;8i2$%nj2oZs*pie;|^jAn2$p zupNA+5-7p_5K-a;l_`!Nz}?CZBCvZXSU|%sO3a{941|~hizd?p5p(7TLg023vt#qr znc|M9%L*MEWU~a`a=}U$X2;#2Ro~zhvD05V%W}cMpIQ!U<{6(dy!? zpdRq!>D{}y_0qr%G*H}v3UiPHzzr@XCV~H8tDlG{aq!+}0-a{B!Sp~x3AFj(K9>>) zB=Eozpqah9?1~&b_d)fi;|_2``Zj1Kf-5gGw*spIx4`4+^1HbWjKGaRaBmP=0kJq9 z;LC#AbcIiegZB;-D8erADKbIzHSXq?ss8}3PDQf7m5SpZ(7F<6LWCwm4hoXt%4wL% z5Y%QwBtsTZI-LH{Sx(pimi{1}RVwL820rD?mIcSWvZq(!*_VP&G(H z4pjr?DJBPKpyeIm7O&?983XRYfMOR^mO(>KUSK;om;3-lEvPw0UiLi!3O8x^Vn5KT zV8;p4@azlfAz=$QkXOO&6>vd_mTy7f2JWI@4L5CQxXCDiHrla*?#&V~0j)d%hr}Ei z&>hDb3SiER>GO|rONcQw$b#+wW^tS#3*L+lD)>8Or$1QC?>2q*K5pK6a1RG9e3X#G z2b3$w3!lfJ@R36ep96yM@ByEe#Vn~I6 z`lp~n`N5g|HWMgIvk5$A0_}oSU_;as;ITk9N6o1$d6_~)qSHtxF1KcY02f&>uNaR2|k~_d69kTGM1XOJ_$eJ^Q1}i`V9}0qwCmB#H zA#h$JrxMasV0JuzVFu`gYRFO;P^3WH28is>?ASPcdZC(th(G#*pO)z}!FLgY3q$at z8E~S8R8i0(0@TU_i=rm=1u{w;)Ag6}i7SEvltqJSjtr!-ngMFlFgewOHjy%c#@jYb zSG3?$t=}P=1sOn!u(0O^^{R&{AKF3CVD<47k{zzTptJxDlumFP zmffkI0LH31%wL{5O%>PPV4AEdhh>H(s*YeDrRcq|iZ z{YaqvzX{r@3~G#Emj6Tq8%iZ`9UP@6kXw3}z(PA@Kt%~O@WBW28~}^JLmx7!1n$1D zSusoib+bV2Xb{b)!Q`-p(ToW^TFj!!{DKcMlmHrWJOUb`hIDa2$#;V^Xxfj(5!6VB zj43qofy&Ao(>+db+iQWlU__0wP2YHe+om4u3|2Gn93NV99yCbIufXD{Z^ZyAtw5s; z;1NT8=tv!G}P)-Flfj_(o;5Oq5Nm$3s4LmH%zE*(^+9kUoIbCoozwGoqCqZo(a0nx+1Mu`V zXp$SX65Rl*L_xs_DjP65a-aovEacRo3L4CgO*1f?&^NHBbPZSw8Z=J=YSe=3dyJIc zAv;}gJHMpjV^FHnU}}N(1kkOYpGD@tjyyuvB9)eZgfDgHY z2Os#e1X%v^@|=T@^0G`{dzzb_>jC(rj5Umktf07(t3M4IXoQ6Q0kj4TzFssZu3oeP zr{h9UxF2AE7BS#N^Z*vVupTlvaXb*p5>ny>?GWVzZJT4!XWSv9#5rB?5x1BaxX=3l z@)T&$NP!bNAqScm01X;}#yJE*6B8y1Y>rGNSxTV!UhtR>Xy~6ofg5>T`-cE% zJQZC09gtMw2Inis8)yvC>inzY{_lcmI^z@fnE$Xcev<851YS45V8sCHODXV}F@dHoKtA~c znYyTFm;jp7V9;Q)0C^%yi7nfVsRJqm^_Lk_3rK(k)Il<1>JbHvk_jmCD6lxzgU9_@ z6a>teet^tlv|_je>e>r{mxF>whCwYz&=>{ChZ6)rYyH6ONd;EWby{{4BMabqR~ocYT+k7=cnQ=f z`~vFwf+Rsh6`)W77o{MRKS(RE3bcZ~-U6*B9ZxY@F@T3ZSu~g$WFeD1ps3p*YYZxT zK*!Z6@F+m?dK*M5KRDDtCbK%$E3heWOM?t=;1_7;o346+Tb^lw1Sst*c!R1eR?yT8 zpBd8{&~yr9{D;+y3G69RD+bVvgrlex!wyg*gUyQJ0!S5~8PgFE%?chLhD^Rp-*|yr zp?-!GC?z9LE8CpOR#2`r8~1VN+RYyus8j?ADMja>oCc4T%3t?Xt2 zYgxboDnM?4=1YC zKuU@kpjl^d`T`f66A*Q%;}7X9@R%l+&glnfU2vE%JN|n+6ZzI$a1(ifG)ALOkcn4V zLmE1m39SkzfajS$fNTMk)XdP5dIo5An_p59Ji4aAG(`~7Pn;l#Ru%q$^b;H8(5k`? zIap{w`iUUd+~W!dx+({|dKNJ!rHPWEyyR04ro>0KPyA#0M38 z&}0c}Awm}g7r;*P4&CKhyj=mSQEhMmg+o~6)2Z-ZfP64Yq}O`AIkK+7E1?4y7c z!;k3`zHm#{gK{SWc)}5yS{on(_Mi?XC}D!12rGK@;-eN!<;ypj9)Di~{{&*Kd$PTJ|=b@iw=O9R7?7nkAL+fVctF?tnTJ zG`R(8!GPCzV$H*B3Xm89t;Jvvm;ko@!Svm?2VvM<10`)paRjPoP{WQ9>UNZnV=kP2 z>khX;1Vj^ZxX6HKTtG&Mg6H)W*aRkmi~lE}Wgno~H1KdTC_+K&;X%u4K`TccK^#X! zI3?ZXR^bBWHi*LM6Yg>=L_wCWybw`hb!BmId9UupmEeEynHbB;OfLfIsWU>S%^T8SgLZAi^D5bFr zbby@9Ca_@o?R(rd^&rnc!U5Dt1}(9JhJ+9}BtYw5o(Q?}ZfAmwU_1~4`_oarP>I`7 z%w2)ok=-4skdiY3T6B1{vha8kE@t zrcB>>pWC1wJWF5zs&7Hght#*A><@t@$`fT+$>z6X--hP<^p&nwZioKC%F0Q!RyLE z%U7WuMO2xf4iVVhd{zu6Kx0h|W=sdby$ds@Js_IXjA;i*96V(Vnw|h1l?oec0uIRRrJXsWp5^e4`80vKaK;Dwl&V?q3ou^@0-(O_!fhctj2 z_|Y1`JEj|E@T>YA;74l!pWsJr0D~NaXaHYCX#j(x61-#-GBtf{`kqJJ(x6TTc*)&| z+uSVE^^^J8rYBtGXP-WyiC?Im4ZO^a1(eD_%izGxA<)7YaB~R0`hpL#k{+}=yaBYL zo)xm99@K~e_e4N(3#!0CYZf6D2dDwX=E&f9`D%l>BaZ-NCBPI=OZz-13$ti2O#n@$ zc`>a3HJd@Jp+HLk4nVtX;0g;g6%S4u2LvJGC7>=DWU&YMBnB4H^c_1iQ#}xXbfi{* zQbq%~_p<^q7y|13D6lv#kU{B4&5$u?2GzIV@<`B83OOY~%OTL#AJ9G-A-G1+?i+AN z>IFg!G%)i(2sGZC4o5eocP2G@2OH&`Drwjh%QK|nSjh3hy;6VfFRe_v_NK_Y4 z64eDz`QQjymjSBQAS-cpNM{L51y@K1V37(PMdlWG173S^0<@jwJQGtrQ@sNyd+IVA zkpz`fpt1`z0%pc^0u<#Nq(QACc7bW2<{?Pl@q%=g5+}Ire1!|tHUKXVVR1Ym4H`h> z6lei27Xz)Z3Swt-ZkVWCQC{aQ$6zr8E9gf4@ykjsO1u9 z8PIe-@YF4+S?{-G{8a(9bEyRK(f=NzL25ngqG|gQFB?rpW94FF%_7#-$ zc7=&sfn9-HU=wI)4m5S(xIzRJ^9&kHZy1$8jfH8Ty_zfGLuZBndW2gVG9Ul`JUZg9g*UgOs557kK;;Je~&XAc4}3KI0Y{C06j# zC2$eJp#WaDxIso>1|O`kz{sc4^AXJ&@}W<=$nKba)vY zouJ)cERLWVJ9dF9T#yFv0X}H2p399FT;D(j09YJBh0Z?kpz#Ax;a7hNTt3|a7ke5^ zHzXC=6c`0&f(klU-ix3(1vOznwHj#S7ieq=w2U8AK0XmKV}dLj1J4J67M-y;g4#+f zpap8+f=!?CiG&g>sO8P#2pY>~biBa;nnuuIdLSV%3tTeS|ADGNRLLwFOg|(X`2=Re zTg#W3c)-<&BV;uTV!VyT5we;EG$hBw09w$&0;=bJfF|NVtw2UAh9i(BICxzqctZwg zA?_Tw(dn0%5dLLUU{GLlYgP}Kq&qvIBs$EUywS{DUz^$*!B zf%$xjtWZ}%2JaXhn~~H{k6+IxI{oe&Zc9(}t_QdS4Q|Uo8^oZT4(}2}I|QIbm?BxA zaNi&!0NP^!8Yzl@%k4o0;}$|YtRLQT`$IZLpiQWtxe_+WP9x-Qf+MKe51)sH^xi?O zd08d!Ob56l+`z8{8F4OjdgD^ zxa~qAVZ;jRAb}fVu#OGXy!s!s0}0aNGPjE;z%0x7I_jy;eqpz$9T&FFs0W_)wPE=qU zmB7^(I01q7!00oAMw%f?WI!tt*acR?odOcJ0rd*N?Rzn3*ODEw_XiY08&JELkX9kc zyFHL?BGaFI$gXBRAlOeN64bzK0aVw{QCyqcF zgAG*4gGMGbKvAv1{N$r469KhsHc;(YFR@6Co%7ABbc* zG6)=J2Ms%KnEvw;DmaX4#ZMwL?8gS5l5rj!XyveA*robn# z7A&`bA0o%9z?lV}%*7M8) zwQL9DxT0EIG0&ut5Xkf-J-gPSE*_ zpqw%Tl;<2zz?XA^7bh#QfLagG1)eO99bh$xC7+;n1M`M@S#xGkCIXe$ikzUpaC|Xg zhPWc90=FygOeO_34W<@0@E%yumPycAn*wJ*(FaON;1xwr1V9I+u{eS|dK#d8TWkV{ z!7Z#m0-%A+sf>y|JhQm8X39huxgR)JR_C~+!qIO=2x z?BW2my1lFGy!8un9b41}!9Z1g%G4QxJ5# z+}$Sb$OtKmo=7P1@Pf2Cg4>6Bpd-@P%n%1HcLg`n)`64T14*zdo?{?~gNNZjgPT7j zAiE@CLpH3_U;N;fMIDA?1?|B=90ma%gah4PprODHo?r(J;(<1xX)yVK3L6b34@J-- z3`j{0TDHlkz$UPsPk~#3UEl;WsILhsO7$5V7?P?_>fi(O|m6sKlhfG`-~~ zw@E!@O&qB!wv53Y5$GHb`Rlcq9sODs%@lVOMDB)gE3ji6=sgvr3T1&msCY$R0}Wll z4&Rvr9d-eg3XnvCvVyT=`u<t5l9e}_t*qL!y1rI{V^t+gYiBACgxSOQm7J`Ee_h8Z_F5B%Lv}1 z$fC&{0NQxQGYPB+bYNPQz$~yLP38=9W|*P`kRnIWyu?J1LT+eqU06Ls98{RdPxpVt z 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

-y>z$ZkQ`VryKFEBuIqVD5H*@e6Fg}~E!pUb+ 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 z z8<3{VNa#0WEpeHli(Xj3B`2)w$PVrg33P*t+To3B2AaVvgC15VzV0W~n zQy_d^&?xR`NvA;gxKTvBUV~{4Cka_Xo5}%E4@wT8WPz3%W=&}jchn{$AV3o~pfL&1 zNF%602Aa46H>^;L2WaWQHT~o!5lf~U9H7RS)b#sDM7Tj+i*Mkj`yCD?&`msMh&JEVm6h5hQyE#{(vsXQD6gI zHu@db)B){5Vt3_*EPX}KT%Z+C*m9RFl@k??G_|k(Ym2y}EE$OkYrTWNhyjg+AkT&> zvhy(2gOkt!Nl^a_8a9xX^=#lZlbk43GHBHpv!fQ4pn>;-NbLlrDS(&ogR=)@2|v6_ zetEH3+)<14pkV_qsb>cD;~GGlyFsUffmGh0sbxqx zjV%zlK?ewBf_lQB+lu$YPWc9RZb8lfEz||y3;`Y|R$$bqX9BI%ogvCpkACL+3Gpn) zHz%iq_UW2~7KnrI1O#9DcR<|nAar#END+=J5yc%3Fo5P;SRGGDf+nF(h@-4EKOhcn zZ`FfG6v3MdL2=3la^wp>(C{GWK5Kz)R>%q6AHbbs$USnPi-8mv6*vV>!}HY*F(r1; zQaZ;MqM*|YA)~FJ{sCyvTgyg+ULGyf|F-=ex5PS|h6J%xE3hAtR1$O8?Jm9T|;3M}z?u2d1S|bg<@R(JD zX^jx%;zsbo_7y^)g`%K~8x>eV%UF(pN1;K3&`O}Ke4w>zpuuKdN6;0c;KE2WOW-Fg zIeX1@FHEoxcuoKe8Uso_BODppj*8z2W$lK>>6_C*;EBC1Uv9 z?+zYX(_mU6q{Ia2r-5(Ma>xet$c3^%Gk;9rTm&9G0_`c(U~&Kr-)JzoDDer*;sWpb z64*Vxyg)*^UKrGO`oO0Mx?-BC1k{@Y^?kBHdqEgLQh)dqIKVwG@V&R(j?5(rT##9K z1!2%tM4*vSCh&2QzrYi8kT3_20BJBm!<<`z8#E%S$OPKchLmY|nG{?hjs%aILTVva zP38?!N|15-h6aabMKcBPQfNhX1@q;KOyE&5SWG~tKvzuf+a)5V$iCL;|9|FYCxy0_ z7SJG{1*iuNO46XQG0?T>;FIG$mx6A+0BsJFRAK_R_ds*KjE-NyWBCUp;dd=O5rE2r zq88*p&^>ela7WG%n%?(b#DdQp6dlm@;|Ih+R>)c?azgh_FvIIdMh&JIg0&*(oL|v; zNa+n)jMu>rTB64cITs2(zmM8+0Ijk^TkuZOa(A?b(#eZi0eE+Tm`M688w(9 z2znCb9Ow`7%>keTvA`GQDKI+fDzMZG9Do!fpjBSXkP-s2O%GHwfwqssueAghV6gSC zkP-s4o$7-Sv`hk({0+ickO3M_M+SifV3R>xAY4H!fD!2kyr>wGT;twYH+I{588Psk8-TEvKs*oWo(4kBB>-iO7H8LpS5*xR$ zVM*BXeY6UBL2rw=qr8BDA`@t{0Vr!C7M8+K1qUBNTn}AY3bGtr3^PDCy0L?58X7F) zH$z#*?^F+3A^8iw z1ZR@tcDw~jZYsniH;mL)Pv7K*k=p7ZoBU@8LDs(`hB~;gBsWITTo|Ns);)QN9f>xa1jaQItR1a#?gNOAFgL08H(YXlfEM7+N_EJbAmB9?O zNQf2IMF8!;0v*f`-hagjT~Yy>9s_Ug-1nXptlTxcGH78BcKB?K-mn`odS1Cz;`Y|+z%==Kb)8@ z4mt1%x@Qx7fC@N=ACOdJ0{a?sDSRx(qx_? zG<`$6h=d?$^d7X`2(~g5#i`&W9^lM>K@2o30P>X*rvj*JdjvGseF3_r6vL@kB$T*7 zDO`i;f`lRyxU+Z+9-^QqWin#|uVR6&!2qu}VstzMawaGQbU}knU>~yTGlI62g8~fH zdxKxbgwk~0&@Li2z5bYpRxr2(0Nnv{Kok^hPe6;@*ff|PfET%eFL!5iWE6PB1Dae1 zbsU$7L7U|#BthGQ8Nee_pmP&Ib6=o)+!ckUD_j(jn=W-+gr{CITTvELpC}5#cOc1v zx+gpeA_|gON}{l3`%Lbj79nW9T>-S#Zvl8^@D?d0CP?!X)Qb zffFofkF?};{u3gGqTmwD+?@G>1T@8f8qm{2Pl%{_3MepTIo1>ksDL&+=`$`6Qepy? z)!<#tO6;JH9ftzD0%+?;O(A5qM}b{Iz!A&=MKrr3PnHt58PkL5M^1<+I)Tbe4W=WK zN)oQ%eGTG{42lBaSy(xFeylZrb(5!1lDsYa0zVSQZ!RwpPq42#Kn|dgNY>zbYdn09?;=M zptCeUBc7mRVZs}`pi=zCiMaeps-WqP%v|{>{t#u zMH+M!BeR17lLB9sl7tQegA%)|0+%ajwI-8;0%%dke}+PL1$IXUKaiLLFK9baiIN29 zKoy28(6S{4(8f3L$j}TSxMwA@6uCf&i5tAa+?|&}0d#&e`*fevB1-k3lk-65^Lr|> zODl*wHZT@}4t55Qjex6TaB6d8%r;{Juf1XgB?9otEk`6lXYMJmgAVsrVuD$grN{+# zjRI2^cqSQ?_jMTz&HVgeO+3T)s$qrfCcUr!vY7jz~kzXIqS zMFvL(1z`;)o_ayhIlEZRJRlA#I-zyF890+c>UzY8Drl|H1&J(2{2OoZo!D%q0NWM_ znpOa%9B`^i4!ZUjba}NPtcV2OV?5!LP&(T265cZD=+SHZ;p^1{(VTcW1z(!=jJ{ zz@T~?Jb8jVJPQg+#PBRyL{0yARzxxgC66+L&M)Kz75iKY;N<`yw;d1#t+3_=?Sp_! zu!6HbNFO_>z-HzKZDz~@9R&e8dQnkiddxWyt$G8{@@mk^xA!bcOyH9xK&cj#@(h%~ zi;ql{I0aU6L8=~Ih6O_4f)u?t1bx-zhzG?+9%UeZC?TgJ-(uB<`lLj2)TfG$ILZ$kc;cGVBU0 zjyq;f7Z>;oA2kLqdIdKx7C@R8preIAW5=Ka=RjE%ycQKyOfp+Bzz#jzAO)^YKAOf?W{}A}U5j z0eAsC0jLL>0F;O^7g4TNCjK11yFglt*rXb;ydl0vAgA{`2{=q#b z@c0HdWRD574h6R=Fs`)bWPnTxL98j|Z`^LvX*6i@SDCf*Eu~s}+L+xJjW1*&an? z+d&Sw?SQrEP!B(%dn+6ylmiN z+y>n5R$y{ubLVvet=|E)c0q@x^FYdFNO=sYu6W`1nzQONf~x`+a95nk5neq_4|pIV zQV*^Xc!;SHTzQ!wHlSMzS``eb1{6RCCbEDICx#?Fgeb&?pe`J^ZUAlT(r26_q{PF{ z3%U=29a0>=e;}g9G=Uwmv^4&p2)ix|w7)oo9bDN#7mDhD*1gPN2UUAYpzi7f&^_r# zd8XSu6p`_Q^a^KygkYD-FJK3)meB_3`oRX;(F5B5&LZ%h#gQpXfyMDMgTQs@?zbOo zAeCAml^dcI^zrEdL5`Uz{)^Z@i02JfagFyu!5`K=^q}7$Y?>_@dG3Ta|h(c z9Zitw6Iem+U;;1P04=GJvsnrrkDr2K16b({kW$CVU>hc|DlviW00$*2cpVj}BH8sw zMBN^A85^VH3D6iQY^m51OyfXz&p}7#7a%)s#dL+oB9f9bgt8p3g3cOdg3J@K2sH3Q zCZhg-5)rcluL*Ft$>KMqHPOz!qngCogI(`IOSr4@nv>pwVNI}a|!Sx+z*iTXkav(U^A&}V- zP`?T4641R=@a3j(F>tO?U<9ov1r_i}b~AD_flskRoO12T;s9Fd!luD=1bi@oBQvD% z0`071bo|7iz#^~-93pQ-mB3jDv=ahcAF_gWR)Xq8M>cLnP&hI`?m7Wo5DMOKcmcGz z3^bPxU4{p`^_lO!X+3E;)l2SgP?$AE(8 z3mokfSOm_3qjw4Ds8g_l1)w8@z+<TRK9>` z<017aW*lyjQUcww%8E}vD4Ni+39^;-ZlD#U;Ddx1&6uF;J|TJ#DFC{T6ImZNZQ!J) z09u3!iRR7VXl4bMMVibE=FAtwAn5@VdEkudSl^9&nFuKMAeO8VQeuQ3a2 zP>UHB&fugB3ukcg4eOCGfqNw2XjFjI29P2eULAl-7)U9NNJ@&(GL`|_gN0Owj257* z0a?d^h$Zli7HEMD6@wc%-TR%0T>S?YP-7W%eh7;rqd*I<0(c(h0}H6Ft_n&Apl|^# zk@~^|N}BqNp!syrS|7(h3|0)_W(un&6KD|wXg(9PxCv4&3c+qNx*`Exas#p$+Bm)- z0b2>r#C%|S?|Tu;EER-ZkU3R>CYo3XvCjsyPz`d{1ALzo6Lgs(xVMhBywwb}x(M?; zbkM$ToU0UJYpKC&l%RWV;m5<*L#B*QENm5bB)-QEcNKV`4Cf*_*kUkHh_gYG7W(q? z>0-$eLiNg!?FXRIeB|Zjpi4nPH7d9Wb_6fmgxd^RwMm^d=Jg85qlS&M8^j%nU$KdB z5qNbXY}Xg)7-7)rM1(Xb>cHElffW20pCK@dRj!x)qwuUVyV1=;#VZ&>erEK@ZTSx}bg^ zsN*Wj>-djBpbe_{!F2miBAROOiRZrzkXjj3u7dIvXvUoZl!I9{nP-4{gJRLpIztka z#UcG+1$NL}Eohb-bpy*^ER7L@-AyZj8%REbyIRdr9q#BGU?0kXLg4~7wIPmraJ3h} zYGpxcPavr^5NL;nzzMJd8IXblNDB1f3J!o3NQ0)I_U_! zEU>;k=;lyq@RZ>K7Eml`FwJ2Bw@p?+j0X=PfVPxE1`yU@Xw+a@!2&uz&v64(19;jV zyztl6Q4DsJ4h!-C3&=hVrVT8h!{WdvSwOa7J%HR_#HhgpTIvAGdEg^6rbCa<%CiRF zbtd{%M4pS?5qkav`*gdnpao%|rszM4BDHFhIAn9CEpaU9f6Tp!IK5f1ONr5F? zK?hiY1jvL2Bn1|51r1;Y;vfY-m_acKvBDanpq^Ee`3Ez|5n><}ACOeoKvb}5GJgOo z0Nq{V_yS3R6On;YKU~EQunInq5gVW?KnhMW zz*TGjs{l=vJFY-d!3kHe0;~YM0D1wE0uH!>1z-h`vrCxk5i!CJS1|*u0(`j81SBKa z;0h*y6@aeFbL>D;zzSE;0am~P@<#)b0v5P}2CxElZcsz;2NS{(OmG!Hm_Vt54P?Xz zBn6Cc1s}i)z|(OrkQ5+->IGN<%XHD7B4%R30-ew#{QxWs?quAUF7;EySPv$111!S? zS#kwhIK7_-wz3?wqzJm=Xs$!L^IyFVI3{a9>IQw4NM1zRU$)D#)O~1u8|s?b{pRVwM>)b^$9O zZZLu(fe|zc&0)<5?r$8B&Qf8RzTlULGt&yr>3h6IrKkNC>0?|yz5lm}BIBCr8-I(~ zFfN?_?zc$3?muZ}mU@;t##&_t#|GwXB~}$sI4Xb^>@k3+N*MldF@S_5vJ}{-cl{BO zm3#(T6!?H43ls(tO5g>GGD;i*Q+TIebmkYH{_>BAh!dw1Ly!_9=z8tKB3?!X1`VbH zMP>yC$2Sb1O_K})Q+c76?eeliBv}-g6c_}iA%v$F{u42)zrX~No&q}9hQVIo!HzxZFo72zt7CWNb?cY`}J zAh}8uOosSum>2ZfG68k!sxD=1$UJ& zva9MLfraiY+^z!EDrCD#2;Eh)>*3A40L|r~rKU_-0`uVR2er`fg=#&>THJXS-04Db^8=6uh&xHhB>b4}e87|?FrT*` zR^;$g640PV23gVnzn-~}mk-Tx0t?{52Rd#7U+{qf183-g8a9MnRqqHcgRw*{FS@H1 z!d(R#10vg1pvDwrl@%x**6T7bSTT?nsXS;d1a;q;vIG{v-3i)=MZleS%0Ez}4&hKo z#%v0l%8lKrixKG$R5=lFEAHY4)Vw4V)7T>#l>WHT94D{@9)h5QbIEoUs7Xu6Rk+h1 zC%UVa!d(TLlOo$yoZ#z-bs5eufyQU+6*!;`2R2Cc4Bm$PhA9h?BX|`Vc|dJzkVB^uJ;-!+&@uX~8cd)J zp~R@m0N!J)zz9on4?(${ncQ5$h8B*{T(SbVt@koa%s>+4fu$o z35*J?3S4$fJ)pTCHYua$MryWTPpB4F+^H1 zykT-Yz@WhC#Mq(4RjI(~WZzclgrboK!!*g*mzAnQ1t6gm_+6&OKR zRWtH1f^rb3o_xbJy-841+o%T=FQDEIv_ZCk5hR-cn&xpl18%!+V9XNe;{|mJ9xy5~ z^0G|7FDM%7JCPT%G8DW_;sm22q}>df{ZL?pT)R-L#AwEJ0(_?^tK$c7E0sfFC8%;{ z)nxtvzMe^w`3IvCmjc)HMj=sQO)i0j;!3;%GsP7+6}UjPHF(&WLtv9Qc*mpyr#bTi zPzvFizE?<8rhYpstV&~s92<22B*|jNv}W!41TJ0^t`FIwpYmFJ4U-cf2rbySBJ!3?u&+WTW5Anm$cJ zR4)u&5PX~zXqJ=3Q6Ni&f%^?3BTKz9gQG#V5}OL>Y!2{BA9hI7i9vx4R2=gtuz?P& z<4|BzVAN+|wPs+QUa?(FrXJjg2RDwUFoG^WR)F+)*c=5w=XI{Sy6S2bN+X^Dl1VwC zjd*qiHi4ax49X0;a+?jbU|k1vudNxA2FPYd1_fqE{z6AicWDLIEHfq*1vXH0DJZZh zaGEj6)I&Q!pyLE&ApIZE4Z{XmDhvvY+}GHdIO>_|lo=c^FlH+;t1y7}>w!**<2GlO zP+(TzHfOd_V0LuKR$^5Et+7*LaXbL&I)bi)1|=%cb|*$q2T+j%G+tJq$O_sw1-hwC zg9$W1R?n=#B%;LTIQ48B=xXp3(B?!I&>mH0M+?xZ6E=ZQj7lu9oWiKVRG`3`t;hy4 zD@PH0bQH5A2k0bn@MbY)4JHmnb_EX5-8@;K)x12QJ*sS=m4Z++7!(*anFV3OwLbrYA5eFoW;XWd>g*2D)@W ziA#Y^U^5rU{t1kVoFKY~QIQ2iPhnI9%>yv&GcI8Sl`V|*pjaqTU6$fVN_st0>wXR$_Bx5J&`VoL>Xlr^gKP9)mga z21bwvr!Xpl;sw-KWp>=an5D#qsH?ajp;}+a%M4Ol01h@bfnB^1agZ?B8D~IVW(Ac) z5N90$@tMq+4uEKOGp0SD+gc%AXlBPfjG!c>#OSycBnsL60GY#8V0Y(bhNd25=Yfv- z#^=65UM6Jc?S?xKbchUt855<>vw$QbMl8|b$fyWD{{s}}pv#h(6u1;X8{b!f1|POg z=av(d^y4sNQcz$9)%Pk2%#IqM1%99l1(+QrKxvW{G=jkFr~o>vQ6)=Y3zq`3KBI{e zs5t>$k;e#LbFKlpt5BE0V0w|9s0Ifp^-5$3?3(^TUqr3`0wbt|S;fS}3dx8LSxPJ_ zpn)S$&qj&UoS6euAWUIYWMguGmK`jP9H5aLCIx2DkOX|q6nHp>15$1%u_~}Tf)6@E zNQ3ePxPg}g8eV{Ai+Tog@B%81EaWLU7HGaOP+$R7DjEtb3QT59CJHPHT;NP$p}^v3 zkmdM$e;fFOBLxNp77Zo~Go}&<%f^hU0KzgcW6A+%Zt#U{-~|#apkh)*fklB06t>g9 zxGD-baF{WPKnp66=M-2RML-D+ba)_(qeHd|g8~z`0D}T}fu91i<19vjgA&~GPyvC( zoYMoY3X4wHRuENZ+Q2ov-;gtU`g#S?i2A3X?Z@CE9HQG%#Ifmhi?~3q1k^Z38OIlY zAp&z*8970Pyh1i40zk7|Ea2J(wBw!=T+e`5T#ld`2E^ia1l27d7LOw%=p1TD(FY?H zm{=9qvy?cd7j6~P1|8-M_8Mdqo+V3Q2d@H)E`tCslLCuABL|4hAv@AR`yAOE*~%Ob zfcB?L@o=F^%YqfNmBH1^fCYFE0uTcl8a^--ItrCJegGL$FU7+NS~bKb@PY~C9?;3< z%pf5a1vV=NDIQS6*RkOP=nDCU4b1MK-5v~%j8+Vw^vq(#02YR$+4Y63DUup$g*aRAN7LuEiWJuzmP)ibex77N48ksFjysbP^ph%R+Qs5V8oxV#&bPi+N^l(+tT*mh4M^!~n3r}U{R^R|N zt{6b|JhK9eK-=`iYNFkY?c4R$MI#xRzOYO`|BA_W`f&}>y`m@XOce*6`rr#XSQB)_ zgaVVm$?5lAGl?^vnjW~6NuIH4`$bLB`Am$vrx)so-eugq-CtMqF(c#d?Z*0|=Rq{H zq3BUY)y2Q2i#xJHx4QF!a~;Y+Jzc<9RFr8C@AS1Ngk+|h zCMwD?uAiP{EZV{NYWizqQE8?J-P7gkq~)3R@=kZCllEcknJyqBrYCo%bCNiyMZ*Fr zWSIr_@+z=^%2m+hE~`M@^us2iszRt+@EIKE->p;baz+Db0$9hF(1xA4l(;J`4HB3KdD#|Z$fRo#ckr9;p1>nsf1tx)m z)8CqknlUy{S1}V+V%#|0-Aptdz0(F0d0;}T>2GE{; zc7c7opi&c5B?{DSPc|3TWn?@)eWHbEG~@B@Z!JKWHCt4wSl2L(6pOHt2otHs@%TWL{bHk;}z$b8O`aL^Q1;(oB|LsI0 znfCKeUvP&>k&{J{6|~Y{VE^S_`41ryq3?4QD*CUDi?b zA`|2O=@Z>W<)`zxfaJILxQH4vGVY&#z*Te#~>)z*jV# zrv=pg*aMn65jZyeu`f7!*!)E01rM@A&%aj!EmdQ7TtD5+Pt=pYVGK0b#n|4gogpqTXZr2{QANh})9(g| zsxbBQPq%kbP@S$3D5}o*czQsfsG8tsUQh#>7j!hJOqK$Nz~|}hfugdE?bDYAidG1{ z2A%f>TC2+kI;-W3gh2ar{UFgY#`fvUf<(=^CNL^+fj4UWo&G#XRFCoBbg^JjQ^sH0 zeS$>=7#aUfj|~yE7QWA=1U(7~v;%`lfmh(}^wlAv{)}^`{|*tAWSli!G*mQ+v1fWk zsA!}1e@0Lbklk^EWR?P-f~Y_{BU8NsyDq~UNk{Na%VO=pP^HR3tM3#us#pF1|7c-vStB`8Pf_D1rAX7?_gHq6?n|#C|~Hv z4m#)s)Gy%`0I665Qo$?G!RW*o#0xqh9JW~8VLWT|&AXf;1LgWT`Qwq4LqQEKubLI`O0zr_12WSeWUyT;E zU}_PZ&L1Nx4GT2TLRN5~O}B~>wPO4|y);HtkEu~``qCItr6@?qv4KJk+||Gm(K(iA?-|#Gak$o2T%FFxiVc`;2aky zcW>ZOVgVgu%Hp_fx?r5BjL2nBK0Sb>!*Rxn>5g%t!eU6ej(~NsD1dZj#fd62{+`|! zCo0Rd;lcE^aiZD+3m(iA2d`Frz^=gVxZ=U|7jdF8j6Ks?<3;U3&UK3yjRnz5<3%mR zp~+D|f!%QdCp>HpP5%-v>cIGWx@m%FG-KEFi3y@MOs#^`&nJj#*27|N0T(EGML;bG zZdkH);|28-z~Q?QlK%M>K*^XJoQ(H?ytjudONk3q5^PA^XsRpp(}q6j)Y-~m^bEbR^*iZqPX~90G@?C#8aO<-%0a7{))- z|D}qWfa1#}O;i&U)$wVf@*uh)O>_yj$ld6PvoroT-WErA8WjqfwW9nCR=VE;6Prdt`H z8f3aarl=Itf5z!LnWA$T?@m9N2@6O^4yd~(Oz+PUmEa@n48B6qHt`KySpxT=LlmG) z3M%QD1@2C7%N8|f+%$b(wx|S{i^t3WPzq~Wznj{LwTa6j7z5f$P@KrTr%A~U(|_l z$@H##Q4Pk;(>LdfPJyHi$3U<K}!}KDUz>HvI>A%P>) zKNO0J!`fB6MWQPD55zzv93MBRp|1cMrao~K)N3NVQ3-K~5xnR|On*}(s>=9yx=^vGIpezNUd5u)1`y|Qx$|-; zu<0^zfC@wg@T>xc8B4&Y2+XF)?7mbbBm_6b4M(0=)I zx?riO7#~rg+hz#TjwPe9E3$z6$N~x)a2x1>V3q=h0>41}bcHg}XvQDYYsy4b7#~kx zSSBhi2(IVe2!YCaa2~ik{bZS_6)fyI%SBZ{9?~xtRkwrq6&&PzpdkMs1PbzIXpr+k z+B+YFKoJFw63{7Ypf0*dmIAZDrs-44MO_&mPrp?zswLSDZI^5i1gS>kz|YfVD@3In z+Mv=az|x%H#be-n46WUiI33x+mp`(BPA}t7-~rblGX!82-1PDaQBB6*(-&5VYBPSD zezrnXf$`h)cNLN2InDZxq-N(TVZKkfM6!n#S4ZizWM3F;*%~2vtiAMq4-QW^f zF`chURD<#Cbn_}v2gXIyE2=~dShh1VIZRh<5mlXju}W0NwS}R-?0xka6WrzXUt-%zb z2y*=&aHp3`fmvYB^i4IQ?u^H#|EdvP!nl3<{8~{DuTzs|h&!@F-3%^9*c=})peF2@ zKWB)8PVk0TV+w4JFBmY25yLuBF*&er!CSi79G9?VLBc?Z1>{>6fgRIR>qNV3?sF;e zz{~=bo6G`t*+J*iaw_mZ{l}%i0xj~HL5srK9AAL?lM1W?$EIu7i|R0LnjTRv>XmU^ z2s(xXDzA~li4|lHGkCB^ff-btLAJr6D+327Gg5G}gYQj zAnME1B|JT{K~$e{)AY^;(F=^*r$;r4y4BC!G6Q_y8q7m13T%!Om{9|8BS;MoY9P-* zQ?nPOMi^Di0yH%jKx#Nq)J&Ie5@qH4$pp6^RG=eb0z8b4H73%UM7Nn97lKw*ETC$Z z6_UunMGrXeIM4!*Ljj~@dSJ7tFyr0nsm-GDu#%>$SyX{>+Vs`U;5Ljxi>O=FO^{=y zQ5@@d0nI~SKx(9*YQXC+G4l+TRCJ(4bfP7^>|}8O?Vm?-J3NDc5*8>%89@_kcbGwC z1t=SIwTfP5d^|m_O|*$|`}Buxq7JcrTW5$n%0L~$%b>ukz~*>>1vwUZ9noWvS3wl1 zZO7}l3S@>H)C^?LOs{K)G~2iZc1)k$E^5knfBMCCQ4#sO>>$^%gAyP(DY9{ciV9ef zb7DG6hiE?I_UWMDR6}r9q)qFAY}U1QpN%J5XZnNiW!9sXmCsW__Yt86Qu7(WP9@6l|Mr(=RH`xOsX+zo-J^@9CBOqNa?Srmyc8m11n4eyU$oj`7X(m;It zqUulsmLM4rF+o%rWPa@g(KyD()9*~cXf(1-6jgC-2X){M@PaBtP=`;0sexCCMS(-$ ztpI2|=m;-p2?D$01F!;6Z4PR;9^e(Y$)Uim$^3vRws36(pgW9OWKDi40c7Bwh{nmMF{E?aDB?|_&@}?AVF?&BRlZUG*MGUR0nb?@G9_t90*zi18D?I zH<~UwoAL4VbJIm788=UVFGs~|ulOpxTj3+W9W5d}phs8^`KA@FMY`cNR^hFBITcN`HD*vkYPq9$3LuDO3aS( z0-#1DlY_$at#d@}#D8?p1kc-|XAR_NQlAU^axIGoiAz!YQG+x zFS?7V7ZMF(DA54PJ)8n}r>|Nds>$8)ahkYe&&O%v0+XiSTOg{=cxF1=LQxy8Ik!Ql z+bJ*$oSp8oP_%%tdHUXkqSB00r{7#CDlO3oTFt?z$=txG2wDCQ_;RoT{n zoZmb>Z;7ZXa)|vp6_%DzZCHnf`i-sFu#Nl}+M`96U_ij{J)3j@KYO zMs7zAMRvzC^Bct#IY8|b&>C=oncE$giaIbd&YRw}Otg@3`}8l%M7_|a*O(m-ZJ!>n zTvWssb!Ls(@%r`|;*R3bOwJ2hG6Y)Ig`^5v|6gDLji)VK4yjm~1$Io|w_LP^@$Piz z6`~c4kEichA)3f|dAi(6QB}JuTna3XPZ%IMh*{tg7buHsFr}C=GVq9UE3i0zU;t$Y zP+6(K1RDQg0qqn4ogn4NB5-MX<4RGn`fFT@pf!RF){NjON=L>*D+VSWVQvKm$DZ|& zB|nS|JVGFT2ZApMGMyt!fl1&trz3NrBj|(+7FIUUSUeMG5J6x8tdk(*&f)-CatJQ5 z6__9c%%E$y__#s4*mYpyHy{I6JmBd+R&cLV0KB3BwEV|WAj^?e;L>!bRib)~ccvGv z61CSsavdMYH430JpukT0$qZT-VBvTHv;shZ!Leig^gF9WrPzOhCNOVuP3PBB7N0J% zT2#j2DkuO!>rX+eSy#b(XOz{3wx%3#I71S%y3AY$Ob872*; z7B)wnEP*?qkb)|3WDvN;3DO1{d;uM<0M_QnC~#}K|5{N|U5F$%vYC#|P%T^_QAU_S zECRQtPh2Z18V%9Hfg;HU)dD);3tVXUhpyiCIv=;_UVl4 zMBN!DO!r(Ts>wKQdht3@W$~39Am=l2Gay;WB(QS&+I6BD((Q~243O(9Z5+8ky-m=n zIt7qf6Q_SzCn_a&1-zcDga@=@2sDQbmYX(RVZEphWBYX9^`gd%kEb`T7Zqb%FntC{ zaKZGW>qWI0+oykAFKWTqK3!{rsHtF|1UDZf^>a8jFbVWaOfT3VYR!0e`kD=*_DntN zr@!4G3ThZ0JSU(&{euJ}%k+8+VbMixBGP zMo}wKP{L4T;o$+D75IfQ3+%>;(>*qccFWBXM9pVlH5-^9YNk#9xJgvT;5H~*Gixxt zVFD#fa9koKAuf=qHyA*RsX!$zlfdoiwwpy|8DCA0-YgoxczgPq&7zWw6Q&>AEIOHe zF2uU&30p+v8IMhG*di**ICuKAEuzM<+c?10B6#AG8NB<8$&o<-reS}ZvedM#qVkNl zrz>m~6=R$`-F&O4JjA??_0wawifXWfyy@7petOSVQC0C{?9f%TpdO$j*w>Cs0&}LH z*eV*vcze41Hc>IgIn&LyiK?rB!vLfiw6K+t0kklM8LERp04&+FetP3JQ5oc%1I|$$ z>!+{ZCYs22d%ECuQAMVX_0!9A#nhFMLWdcYs*w0h5dQT2x?+;kr)>w%0`u+=ZD8Cr z?SX*A^qSiOYSYi`5ap1Y1{!-~)?jL2F=JZ8qQDH^b&yIj-r?g&^iO%R;E@{WKbi2vq}Kp5lQ>AAZ^ ztwF*KcLl6K^q#u{M)e;SPKV59ftJ<0fOB{xK+fgJa%@w{;FAkNTfGpnu=kSO@ zZw&}SCL=(+GX;P7uhZj_- zfbu)2YMKVR9)LxIX%CYb(+egA7SP^HB~}F%N6?00Q0L~}be4mnDvWogYaSGhXS_GP z^Ps3J z4~aSmJmN%TdQg2o{qZ4DYsP!ioraM10XFhkst5874(x644wRUxCr;QKO|9j|~(T!kzp2GH;+gTRjIs>ekQ8GlU= zKQ4NZv3uNfb0e|B2bl#%htbeXfF=8PTFL(Yn}F@0D) z{mxlYXU4tL70!v8G0vPGeoj zN^rMJ!Imm-V4S{iy`0(f36nSlS=kjh1RhWKzAS3Svz-yN7iIyY5*x43^!)3hlG7XR zh)Rn$?nRw$W(76s1$IooaT(l&{CQc_UVH~gjW#sBf_7y=)%af#m1Mj!J@X2+12e=O`Jqa|-4IqsP?rNSEXnM65TpiW*-&8n^o`d5*)I6$crKA#~38VO+qZ&+Z^V1f?=XbB)i4fpgt*F+_!cU%{h zHrcUf2KerHa5_i$7UmKKR!2}j6&!YmS(fY9!NJCRLv%gko#}gTh?;>00&a<_OqaMR zDzEwoWTrgScc6@{!0IT0F+^4HS{6E;!v?xV0jot5Zh|d3c2jgIEP0!!1z}$sG^}b8~|h7DK)7c#J_{`*hjcqV_(E_RSCnaSgC~lZzX) zfRV+Kz0i@>jh96MbZRZ5z6&*%rIj!f z68Jm_4ba{}jw}UsfuGaU?uu$MLd;^CbYS|$yP_hDJElLo3(i>V_eAZ*KkuJ`GUNlZ zA@&|vP2D|F`=}!zHTpPQ&B6^Sl0Ye%71E0ZCu&eT6xJ|d5S0v_EvU!}YB~sHDKI#KMjxkw4qj0J?N4Im76SKW z6qp?K9bfF5AucdU0wJX9IDJ2wkdb5C90eGT>8Fc9ZlLCVo zQ-}f+xUysv0L!v~&iP|7V~S8<0=XNc7i20kNSH~3Ny3aNMuExk4rok6;PZ6jN1{rM zpQndC64hm#Ih{L8Ms514N1~F9pQj&rB-+ZjeY)3UQ5Rvf`kT}7-S+7VAB&30f>Smp zsB_2;b_2VkLKY$?UVbdvCpSw_i4&Z#L1U$$5%m9{&5Yo+5F7$`m)AcLWn?@sz2T{- zfzW=?4j0hw9Z*dLY8@V&e(0&F4dc`8|DTHHF*2RFGd=&g=nBx9V@}YTV-8*h1y0bK zV`%zSq zarSickD^sV4U9?*5D$WSVhW4`E!z)&6lG>+{51Xe7f~aAa80G;xUqMpxTBiDiA7)&Xgn3vYyz+H zViuS`{liz$5KzVF_Dxh?|1uY-X{NyB_?7{*Z-S8lI_3c%S^}->2Za(SMB5ps2cD3T zo9c1MLFg5tuuj>4&H> zNUiw~Q5D9E(_?;!YJs>NKSVu2^ktCnvgtp5h$?}&GCxI47!OYm{3*IXkC1_Dj@?v3+{sFVQXRx7k6K=1ea%QjnPL@*BKn zx!|{GF5~U#_kN4IGImZ^`6KGWcwlxRlAG|%t$MJ7#+VI znm*w#coaB(m$DdWB^{%{j_K9Al&1>8bF--9<=&Z~+&n$=pQxH-C!-YTKnj6P>{1G# z(J0tJ+UDsi{)wtH-kE;kpQszt6p88kG8OWe4Fn)Aacwy~L);N*E*sq?(?RlL(BcfT zj25&?5z#(iblm-Ns(=`1$RFLUQ?HBZGcK6U&M3B;ar^YmjA9c2d7#ERsqlyF305hgObztev{ysZpjRGT_&@bCQ~Qh^eN0@j*Qc%Ut<lh5 zapCmOtYS@)i@&yr3rs~StXUlwwzi22Or74xCZ@*tVER@zF$aMO6K9A!ayWK?C^>*%6zgGZoUYF$*2lPg`aUi( z56gLdGttMQ1(vgbO9@bu&~YnB9=2Ep-2Y*6+`yD2uw%MCw-|VxC#ZIc;T9`oygU6I zx0s>tg5~g;IVQ(Bj9HFvt|JL7Va#&;f-JCxG0X7}k^pGhMZk>d3+S$+8Ox{p@Q67w zJ-I%;pGVA!=|9)>(>!9jjJ?x;@`$N0PMa>rD`v*HczP(WmelbPeX`tTz3~}(_ zIcNi_gCldHv?3D^GpHb$0XpuO2{d8{I($yx_Vn5OVg};iRw}4cVRi)FO#~Wk;>Z%X zGyM_2Sd;)b1L-*~I0|!&kARptV&n(w(3SwXptMS&eMsLu=PI%o#&&B%ITF-!4&kQ)ymHTzjW#mbK9 z=Y=80vkL5({#qDpysU`WQvG)zw==6o+V#2cEHUhX)&jM~E zfHqJm!8`RA#lbFOmJs{OxM%uL39$(xD?saIr9sEagC_z&12-$C&y^G_WLzNc=g88Hj)c1F;=j|LNmz~t!*WW-b%JEtF$5%XheV4QyOg1E?Z zEm<)O#@^}4vSJ#Hebakn#Wb1jte(DIR!o)Y%IfL&WX0SxUaW>x+Dr@zERGLWLvI$S zP+$QM7lWF(ERHr=0#~N{$cY6BH8MhnBS1?W7!|k#PEX$;C#H-;Tx|MpIWc*mUPe&m zx`R=PmBm2;u1RvbtGt*$-B4a}>p#*;^T<6c`1Xr$18^GhsYEU0O-3lyUv^iArJ?jDMz|QW7g<*}$#9K3$JGGFgjIuyMd1AO9V%iI8QZ6OsfvLHf|^vt zvKX&Vf2%6C5;W-Apf4t?%f!aa!p6o5PWX%hw>TYt{AVt7WG+(#T|>{$?a0E`6ivp9tlIafWVg`&8rx&V=X^Tu01eHiiw^jsz- z27x`(H>iu%GJcw_ry-`m_RFltEJ?oYN<2iGgNCHfxEgF&>zHOG`|h@xXK@Z7`(;p@Ou$tGO5OB&9$n73eZtVFb-$ zGP!}y=W~QP;F6A51LJ||!Mb9k&MmBA+%Y{zPb`xC?8z2!$4xV)pV1RDV{D(!tS@H7 zbA(%oS)dU#u)c1=bVq$LF~OVQ&Bmb3y#fl1jv4|lrf2Aj`7_?0zC&M3k@3#-Tl!*Z zjCZFq8i?sL-kWY{AZ9LjAFf3ZWYYbq(<=?cq_q#hg+V513cO%aWaSY6O|G$MFlB)K z2-@_+=(x0R`hEj3N&Vw+4g3l$jwcwwM-n>rte7tD$SiP*8*3#OxRk zP4_huQ(-(by~s>VgYm`m*=Ayrj6Ku0nu&QazL;h%Cc^k)x~RFBlPKItyr8|~3XEXi zPR}tH3)B1r>b!zn3XP!#)+_}s0VE9|=YXwzZ7wFu_+mPzg;>1mI?!B;D`>+pXdM!G z5Sq~uqzaVVz&_9scrm@#LQID7(DYRnV%m%^reCuV+s(Ls`Xoy+2W_Z+&?)eYh2ZMZ zQ3nzJAg_Wa&p{?m|7$5G&Uk3LsFj!(;==iP&CH}!flAtJ^51JSSE#(5)zlJeO;5r91 zRzXS}LFcM~HXEaqBu79c34;Qo)Mg3DCq1g9a10yl`Z61S{A-{i?l~3geXNzwE_K z7~fCVcMww$+6h0_0}?R;Go~jxh&eJ&p1#;YOogePak}FSIr-^-UB&pPe|He`W85~~ z%~4E~anAGtM=?Lf?bG)=iYYSgnEntX_-T5-^F2k-!3fC3X}hCzW*U^lnG zT5(Y6!3m5W3u4?pozn;GYHc5|t3!RnOvHC{?*h4+YZu7XTsuLo z=2|W=efk0)F>&ts;-CRpE(LCZMbi)Yh?y|%ocr{ly|7c}Eu1@MD?2 z!Cx#`VVj^5lNr+n(CP_BGp045bybX33|l}nsF0X5T{%E3m2vy@&H%6nRtJb_F}|OE zEkI0(asBk40b&};ySW9{iz_f2GfIFCi2~&|4jwLU$0K(eKs!%08MqyfY zdpcvVm@MPs>GHv1Zj3vprv;0dGM<<|Cs@pd=_A|pN5Nthj9t^CL&Q2*4*jq5p8h;U zES#}@x_zkFZrM&oB{nmrC7_-4pwess3y8ad30#vso-Q6HrmJuWe5M?z+0?*PWX6=C zzzSYH#|j>uW)fIDJta)co$=N5HDO}%jGfcZgo#BnE}pItE~dlSIXyI7%$)J!^xkl> z2z}7Ts0*M;$199kN+9|IXi8IHGw7g0&^gwu&=c_%fJPw&?oStq02|>L0XCvCLM(!D z!SsvkRK+A-fwas3pMTf`CP58nMuGd&BE_s2PffRu6q9FsFg-d_%#iWn^j-*WZKRkU zAt;N9+AyRuTdY za0yR85F-}Jcxbv*te6Vp!|C?1V!DjGr{~6sO<>$N{a>t@2IGS1>TzPA?SZ~=V$w>` z4WjIj2ml`sz~&CR^4)O?OO^t=KnLISt~fCRsRb;cCVflAgCZxqbLknd#J!J@P${Ag&EYTWO3sKo!HpJ3YrSq!;+;0Dk9kh zPC=u)hgFH+jA;TZcvl>w0=vLIZY3cF!7v5TxyzvY9zk~1$BRiY?wdX%Ud)2=|MZLT zVyR-F`YGrfa2%nKJfFPe>C}VB9giF-^?4zJ~+U zJ>0?K$PTWLK-+H=m>uV^WGS!-K;&+K{#YP7>dL5Dv< zTFp$*jZUt-Tp-tihHsfQn07D=fZfQ&tsum#z-q?C19rb6sCl!ZZ@O!`m0Rk! z^7Y`P%dE*PAaIf!R0A3)vGB4hFoT)|I-mo%pnV9a&7h+!K;@AJxDNpr1RbrX1Zq$* zJDOxcIzP<%j6Pta7!fTNxO#Alg;|k>hdlvw{3z&t9#F@V3AD7ANt2lYbP8F30yDVM z=UlD?>br7e3G4$8Ag3s?@UlT1m;joS&H(L_QeXkEdd*RQv;{y>@&8>rWD?jhy(3dhrXJxOHgIE_ z8B_-%MK~L(b3pzF&v}9tTRDPbkP{kxD;N>MvjkF$FgmVj=@fV56fl6f5n>6#)zg); z#KbfvGK1p(2*dzJ1tx(5pk&Sl9ti-AF*tH$fum-6VwRX_HfpqJGT&fS0v&6*9A*dT zG$2+5&gI~Ec>oGwPV==F=RXFlK>v=YoO(-1vF{u^OEAo-mp*yrn6^@De{1Q&#cLOf>Ge)bdzi`6~-OYBeTUcr68%Lhe?TrmsNq;5!7{t zh54LpF==7+FlQ3DH2qYzm~0dz9M*s|vVl8{uy6qN{86(fD>SxRn2-|>=!8UYCjy$@ zA*w*;JLZVV3PH?20y3W!V*d1k95H>y9n%-&h{;$Y+yz<@01CJ#D5itj=g6kBfLhm} zV+E#v%@I@L0EY*sz{%EdT{O5TO}VfGqpjD(=W7U;u5IV-_z5a>c|v5qdzeh@=NJ*ygAP>aszD2V7=3 z_AqA&Jcs8>1_gG|ASQSyL_SYUlCgcdWuBOh_)AV``T{4QC9IIezE7vu#F}>;XMPf?wpou=v!GTJko6{HtHgSMf1cH{If&DdOdP0#HXtDFh^`a`% zHx`MBKvp&DO#f6Qrl8irXwD2ONjN~GX5huE-#{0OFoTb11C6GDim?ULEsDWrq!x=Q zFfN$hRxGB<*fV`iv6wAm$MjdlVseb%rgN5vO=RquKD$KBYDBpSpe4_X z^TqrbFHirRFQ&@aHC?hmOoy>+x?6#mI^*W)c?DwCj9aF^DiBj-JUN}GP)v@oZ@PA& zSSbG{LFkcFpp_m1tETrCiUo0f1l=qJTFCOrS0>WHU2plm;B{zskfE>enr3gA`p*Nmzk< zlN)9LsKC7o8fak=FhGcb#wK{dw{=4+FsOc5(RZB#rWRV7z#Qbt3!e93bOhUM0V*{i zTH!+r-~la&7!I0m`o(fFQFDYVLB~S&f&9XOa3wRi^k5M{RRtQtl&uhx zh}r<#)CD?E)$zmpHgK+kIUA>Dm`8Y-L06$DfcosHCUtd8@2?OO&p?QRay6((QDg?K zxB&$nIP)QU6jZsRdK9J!<{*<>kTTF{V{E0EndFw`v&3~77#x`ktr)}lY9hsmLd0>&XAT>+^22!B(&E&*l&XfT%wR3uJm6%EFl@l|>1-`RM zfrLOO5;&fo(|}|E187T*E<=m}%yA3~pvH~@ljB{6EJtR?|I<1^gE`Gyp!OMuA~T5M z0Z-ttIR05PU9MV8P4;p}Ge`~8k)ZjbA_X=_{%i$CX@M2f6RX9fnP#$2ud5a_LJ1}z zNHBqh5YBW?KUpoNEeCT1X!D=~JLotCCQ#0V1&>gTm@+JQtZT%K$q62Ic<`*M5i^T@ zfe4-xxPvDWGk9(>WI3{-2M;4!@YvRhso7u#Pg6bU*iwdU1!if16)aMqHZ+q4lMhI9 zh!SW%ib5W#Rm_n>vdvI^?#s21x{w*mM^;_Xd(hE{**(CTY(95EH*Pn z3S(Aa(q#xj4nhSc$IA>^j=ZSh$DjxfKNcl6aOL@D4LIpRlNICi8TDckjF+cxtQV7I zTrquN3nW>+sTZ?BNmdxSPeU0gyg=gtyRl`xo(3@!Sb!aC5Yr_mzy!^iDnR+HbGm+` zn33LulaQ!2t6jNioJe{#gOpOtd<6N7>EYZ@AC?|8FW|Hw3^< z7|?_js|J&Z853wrqXN4ld!ZEr=w2ZS(CjmK^*p=4j_niL#11hra!wEK6x+ebGo7bP ztcmg2^!_d}X$elyY1izaV}oTt1K;eRqYKmoUUE!7)Fo!mcz8Nfx0o6u=XA|(F%8*g z+#s)k4+jRF9qg#dt;nhXJ>rRTdS16!Vf`OQCf0gJ(E0fSkT7G?U{V128MM_#gGon; z1ysywD6wTLarm;-E3mSHPl%eprN{{?CImn;CQO>l915Urb`UQkShfKq%c8&rn!*LG z|K?U?R%UP%fF4T?I*XhIbmFiAdsaQjfh>@dN?9Bk9T^3lg7&SlfJV+iXYesY&fsGN zFG}+#t3AUv|u_!DIoNNpN(?R$vr(FkPt^Jkl1>D>k38 zYx;*?F@Mm8i#{<$#s|}r`otXgx_bZpRZ478AGQ zDF};^+wsJ*S>m8m&lwb$^cfhe85qFllsg(^3A~ujKS4~Iv3I)m1TjsPCU$|B(<3H` zDKkEpUNb?=jInF_<_Tg-j6Kt@O%QWo`olT>{2@7&=?)Xcq?j7mr>|QfrpWkf`h^u@ z%1j?Prhi=_rYqgR4qN>NN{Sjv9H4p#ybP>uy6s9a8IZ#0m144tZPN`;2?|f|St%yK z*fxFcN-=fDf76ey6!T&1ntouCSUqFcbce}eC9)s`K}LbjwPOOEip~mYU4crOH`6ap z7L#FoFuh^En5x_x4h1HCMj7y74A8}nOrQ!?AxnW#;Olh5DPo`_QXkBRxR!N+n2{*V za0hU~4Z4qjQQ*gPp9Nyx>|N|2(;`57;FP8xSRkgt_;dQx1!B&OUDGueidiy#n0|4p zm?zVJ>tGig|EAl<#4jJ|Rz7X}ZE9F=gFS_}S0U=?ljXz0*KV(f1ro4sb7l^O?Yd z>G!6IMJwV_zyfj(4|r9r5R(QI2k5YJ$SM~{V}YLOEz`yHWIwE)A+E^c_yt6PPh|%k zdB6l3(`6HAntpz|n5j(zJIH1MS6)z|EdsiE;0A*LL{I`WW6K0OCKeR75HSVN$)rq< zDxe^IFx_E>n6gw4yEP*RXcme|gGmL{nsw9x86zn0W_s-mG0?#wboM!7ilPud9AJWY0(8zJs06T`16GkXM=XNz&Gh|qz&72R1GdS1u2?8z*Yvq_ z!8YBSE9M1??|EQe);uwD#-Gy{%@YfPM)x1)=?)8&EYLKabFr8^ zWBc^L#bV0Ztz6cOps4{CGbSI<$SD)}Xmv+1XmU~kZ?*(oZXxht`uxRWs*G*Zk1iIA zk%Yub1uqkPd&C29;%=DkxJ*oBy5ABp9>%um(M!a%L6yJ~G0=+rql?AlL7jLpf!66i zmWatQHcb~_Di+4rH9c=BxU6`$RLqC*-*oF`V%qFKIYD{l2*^0e>21rz>=?VIA6+Kq z&)78mO}nt0efe=@BgD7#~cJS}7(+WFZ$l{p~6-5gAxv1TN{o#eyS~0HjcZ&iA!$z)dcSRLX(FpF9&EUmC13}^n|ry;!@iu zL5EMFqbKa377>%9y1cfo%FB@TU ze6n=9>^d>k`t3}RX5N&7x*|bg4P{_W-}O+SU?nu5-a-EKn$QEOweE} z3#fGiZhnE!H3VJ1;yB^SMA-InX2%W~M**~=K$D3Bd}&d=qX}q)5PXORBdG1jm<_tD zhXGQ;f*Paxj1HhNvt5j!MHadYHsE#PpetPjAPe^)iv_;uX8r){mU~*9eO%*e1h%1#KL6>);Da$rzk5;!znW22Zn(?-teg(^%otpB*V6_}^%bqFa>|M#6yc=~~j zVr*=yc~~78xTk-#7I2#`v`Nf}@z3;)+k{1@H*6APnI5-EjE8AA%XER6+#(>6I>yH7 z|2K&lvH$1hzQn}HGQCDmM1~i%_nT3J=>?wxlfbj-iJQe_7@McpZ5A_POq{-PvzQO# zmg)aCi-j}pnjW@A%&5K{ejN?;$}1*KCeU5)44TXj_!ObjSD<=nM;~`RXxLMO zNkowov^hsc5wi7$O`lN*)MRA>-P^&Tz@)%s#spdk!wE_$;G3~z6xd*QDv5xOWz~Re zti`4QbO;_O>OcctpoWJ6Xi%C}poK?~LlksUjsa*38VC0+Mo4Nl$e!-DUCgf@6awbV z0-#F_diWLDL5H&Ng9cdzK(nt%cXff>3BHL-MS;z+9(2_W8_3l%3Sf7FZt!A3zq(69 zfx&SLKj;`JHb!JJ6~v>F{0ZA>873n(xtuz=Dt#D$;=fd}kD&~`UR@NPY3kP9INhBP*;0N_WLH#F3S*S`RJ@{TbP>um# zV+9L(eG!h+fCHRq!EvTAJ?9;h!}g9nVp`xG zpEuq!B~2IGC*}>>_Q?$zLSW@(P~Zk_Xk=30)&+0-ocDnVbk)rM4@@qMPqshUCw3FG zf79>_lhU-$OrR~FAm;QnpP4{gJ`KMx{bPJG-QX)z#P*cKVqqYq_rEcPZWlNz76;-O zd}Wf`-g``J3uDSI3GR7}Ow5pss{m;?FoMe{(DW^+jAC?rz?UVk5q4%gsCZ=tl~bUa zmI+icF@wC!0jf$sl>(^t28}g1vSbNt;si~~N=(oEtZbzVDyz6_7@430U7)+xpca9; zU!XEU0c@25v%qAY>E{C!#p)SA>7K>u|NsC0`OTR?p~?gbRd8|x1uA&-i3MsC1L)Ey z33JHpkzmVu;JLy8GKK@OkDaLwW}_0Q!Tf+P%TW!H9Y7vr1eZhg;F}eRFNhRCH7V$V zC>8}qNNptn$|2x9p}_>&Q>6gP5jSSc5O)+rPW8+hpd}v~Of0CW9<&B%+A)-54_b%| zy2DBXoa`AvOdW8t2QyV*$)4K@)YJuyDQGa^QL4ZKiAeAzb36**w9BEu0;(=S!5f7V zzAT`vha8Z|XjbG@;BZptSgy#bzyTh$YG`n1=2ir)B4J(Y^#4C|vy(!b0!NDiXA5ZH z4>b3z!oZ!$$W-qrq{!^JY`WShF%^}+mm5IiL(JTce2UDDGy7XXJSJ|(1!r48EJkj} z)n}*Yof1=)dGVq}Tws<2w+MLjRDsEn-|_MraLBYvY+rdwtdEiL(R7P5Vs?y=rk9@) zi)K13INh*bS!DW)Gh#fV8+kxY5+2Z?A878E4YY;n@N~|zVm6Gkr@NgMTg5nM`^U3l z-xwu+y_zl#zWR-+1ayO!0%!n_)$!A->Hp7*NicnWHC^(8n7+&#R8?7^+vXrD-@clj zazV_E>G!MYYc7aM%6vdq$(yCb4m#b=@#CxM4=;$>GQE2>UE!jb1k?Lh)2%LwMKk?) zHGTR;F@2_=ucn{4DCWfU?bURiOJeFw-(O8Py(H$u^ySs`%1dHOOkZD3pL0{T&bJpkkjX zQcBa`UK10RdCvm61eFcc$6?c85^fsgBGV17iwSZ4VgWT}c^nzt zA%Y3l#iSW8Pp`Qymd|)(`kU)waxO;%L6^HJD1z4KNn|N-gEo`ODDenD#3d9(zyq%e zJPI68ArVD>kPZPwQ3cRQu>yy{%6 zC@?9AD)57tvIGLCq59fV_Y`< z!UHjT)@Lk^mlsSIc_^m9wE%pb&lDylzUd1di^)undMIYdxPE)jLop^st~;-%iz^5@ zG6*b~KI4&CD&x}W{~n3WVCr3)~5=Ps9{B`oI=GV4iOHR7_*~)F)z77`IK=dMf73IAeO=Q!!Jfb3D`UKNZuS ze&MMYFXP?m_nwM5G9I6<@J!5)al`ifXJP@2j2osOcrF&Fe06>!I3-WyV`76;mlv3_ zmDp84mn}isxxCXIUx%b+L#5(CXVOkq@D2VJE)0YvjopZHQt zmT}Vb^)JO@7(J%*yb{xb>NWuD1`R3cGRVPoKLF|CG-J90qIst$yaMa4dnIPV_-Oj( zS7Kp|pQdxY7SmvyINkWQm=@!t>2a^coESe(U-(+git*F*I}kb6H()t~H(tsHV>JEO;+$3_}0JNF_xo^M@?E@bG zEyw0HXWjv#8O`dMj(`|^;41k9cqg_3yW;^S(3)z{nOdlgPDaO;)2LS?Fe-pnPNA#9 z)_nk7n8gIHq!~bgafS(8O9z5EN0^}XH2Aavu+RxiwP10GQfLE}9khd9i47D2@Mh}t z2zPNW8*WfPoLvF3!I2%*AO-uA*^CJk0HF5S9+1Cz%$RmCK^vuP3hba;5CpoX&v++h zs&|12)a!;__Ub6^*af|v)g3ZK51*O@l_f`~|9mGV&)7d*^1T@7?683MVq(J6c@#l& zU|fzL__7o@9XYZD{!FiYFQ&n`d-|gHVpWVYrpta1Gh{qE-T#A_3S;B+jhyld)6~U9 zr?31VCeOHj`pFMscZ2#tGmW5@2Bg&hZpK~UVB)K10nPPIfZmnOpuxnW#0u)NEAl9? zf_hkryb7$KcB&$u0xPH~sR%k+p@A_=k$d`wk75Ok6Q?JB5|d#3GQH}Pm@?zn>GM8` zSxHRf0j;0aWR@^za#3Igt&mY*RbUbLGX29RF;&K|)5SiEsf)uD379k4fTR_eK^v66 zO%M4jrd7`hZYhJNm-!sUL8%ooyT{9@zzR;S;A*7<)Zb@^rB)@-6)XzupyQ=DVJQ~0 zS{yVH_~-FNaWf{^UDz$4VJ%iorU!iH%oPgE3WDHN+rg;7?RX8e{#IO|-arwwik(@5 zse=)m)>uJ9dp(Tcv<7CkFoKdAxa|q)Ybt=-?ga|W3T$RfpmoCaW=x=^!yINzDGJP> z^K_KB6j&9QL1zLh2|!!$5lVuf0t>q4kQcn$7}UV6R}wa7jsR7JJ^YHGP~dV@KnevW zXefw)R6s&O0qlED1%6P1Wrk)_u!n^qo@6m&0{dG8;n^eCTEW*Gft-cvQxihowl?r9aYDOu(5PXW{_u;K?DRWd#FQNc?Lh5rP_bG9xq}-=xbP@&DF_I3!@EGd zpao)%jEXGN?Y@dhs>6~9gE^A|G>Ir=349ZVh8MWA%Ir8{dfivCM#dY{zKPi~{+(|3 zO-zjO&-8?Max%=!0=uV|d=r}l$rWPLWxtDgGTxY;{#{I+@#ysa?_#Qq{nNL87Yl&5 zn52J*@iP4ZH=l&3+x`$!WSluY{)d=4s>Tj{>T)#k>2*m$2z3h)zG2@Ks zul|Sy@yy}^AA1Rsm^Izwub3&a!uG#n^C1cir$_t~Tglis{ey$J{B*_tVoLQ37@3&r znL*hdI+g+HwV`xJ!F@!efioQa7*LXTA%Lx*m(ugxx_#CgiX%QEgBY_YS zc03Oi5&-uQ9Yxq3?=5K+7wDb7oKajs`WXvo{sFX>20Z%#sy(KjZ4-B76iAu=h*4a{ z4r%xLQZR##Jz)cN?j0Egnt7nv8g!KiWW++?!*mxWaYdIz&;kqv(3(*N zCV>v{PEyby4tP{U-~(u*D-&p57<5_{c#uJXNuU#5)%2B2;?m+Cpji(c@O}0m%i-4C zW)hdH2b;tWsvseAG@zXcprLARX|UH7m>iiPBbsuK=Rv1`C=1M$fQ}0jF)Vx%w%iuv zL?+Pq0NQ}G9R3mM=?*O728>gu7qW<}G9H^gokbiph5Ug<+?8?WbTd|QdCpl}N*tgv zdH3`7t!XA_r`f~W@tDI}XSIj(s#U0i`#VCi&yc5w~8pDd3584Df%GJuvpfm(?Q;6M_9 zn8^f+ANZJ~z?A8&?BcfU@1dpUNp|sQ#{TK59O6EVQ>Pbki03l)Pk+E6Zq9gOx&)`V z3RA<0?RK2v`i$I%OqdKHW!8l06_Wx`zA?1L)RD7J**SK==cOEJaZTHVvj4 zL^o@OI7o)kis2830vo88@B?(O*$<8^ZqTYBGX*x#K0`$j1vU+3rW8d9knR#iX$3aW zG3VTh0t#&4Q&)Hu%$6(337nYT&MmIScxw7OZt-CL6K^1gFEN8=X%4)ZF2Eyh&3Jmc z507}f60d>?=o)fp2T;e2TTxPh9o+ho0p$Q5MT6-VdBjB{xE0huCq=MI&SB zkYN=iE`dMbPWcT+MRAa;t}rTr@9`6NWXx9NP~dT7ROA7rKMqAc1ujJm(8g0X@ID!K z1wMgi)9rZ0)#^cBeZ!a~@Em-r7#lapoC}PKf}p`?(8fDQMmHr+&}t}N1wjoa1|=>5 zXj=FWP77>~9~iTg_!W2^4>0`UVgPy5AWMN?fmeYGnmE`rm<&LMnmAqttypIS4=jLh z$#G=NQmp4v5LDz~c2MAQWXx9L0x6UV&Xf zT;MI(z3kkeZb1(}Xj+yDbO|bGV4hJy#!(DZg>Zn&Z(arkc5pM&45YS$A9Q;NId>IrdEG6n7L8FaQnt zXfSnfg4>YnAV2qTg4>W_b_*w{4GEgHgSm>$iNU;{=?N&&fnrRF*^KD{C_3uRnC^fC znar4OfcPIkr(`OyIo{v^j|H=7GJoJuGILVsSgr)|A+(0#0Ofgh&=xq*jYWJ)=H|>d zz!$JU!bbsgU&jp&(AcRFJap;{;lX184Ia>*1EhITMzm=Ql+ZCZX9kA|sJ#gaB@5J$ zxiP&FbZ{4*kf{d+6K2q`gL)&N!(zcxJ&d4o?idTyw;%_DoZ7&z#Nx=9WyaLN590pe zQ(ysQ4DbXHXvhw%6`KkLGf;z-4YY2sqaGBA4A3}cHe&+CIjExtE((~;n0|05u!DL? zptYfnKOoZ&9H2Ge9F9{N6(GSc4GMQQZUs)rWGx%0L+JSAT=E!KpaDWL^&}cF-m~(=9?(7QE0#m0~2#6a5NGr$*`~VNoU0?zaK{6n$ zG0!k5$}6xt-rxsiIW|Yos13UY(;ZOjoH0wuNP$O5JWEMaK`Kj0OF=A4Nn2p<^dAD^ ziU#0Ot1C>PK`buE53r0{4?f%+l)@G;W(l0(0Vj|nOj!c2r+W&DYjGU_yJH87636sF zL2)q&4W=zDib4u(j%!#!XJ&(v6X+E7`O{Ymifaq=fwB(20>o8(pyQtBPJbyVZp$Gl ztst+!B5-uNo{+dLBiHmCA#np%E(I2Wfo1>&K$%`}`b!~kIT28?s34i8 z#38VN3p7-DhfRrldV`3#S}^#cEpBj7++b4#&2npi%61O$0H)&-)+{9+Xek3qRvJnI zAWBC`1X|`uDX=T>D1dIV6i^UxWD!`)qa-k$S5#cPUH}w@AcGaS&6qB*DX=NW=wn76xf{V&6$pXNLylvpub0jXkh1aD_H zW7+|dyTX>Gz~Ok5L4jL=OW*@1_y4~U4{3V@bAv4MQ2z$37kM~NHkWKD2baDu`BWEGddbkJoayr4+=z?P-JfM z1*Y>T@d)f@QR15ZOH^EkoeLCDY~0f)D2b~~zaS*e8qEs2J%$UE18?vv@PTrm0xM{> zP`zVALqh`-m}FFtly+oL5Y=U1kOr* zu+=lBZxj>P(BM^&0LQNelY|m0$aykK9MD(>$1CWbE(HmJ)6*Hn#kEZ!Nv4Hei5n~q z8m$90*}FXU|JVc)iY-)>M5`}eqhg1Gufa5d9dtF5E<+EyqA5sz4!aVEBcnGjqa%YNw*rSF zqdPAn=w35W3jtc;K4)-K^p_IiGD70gjvS5*3X;-A3Sy27?nMex)5Rsl zWd1z~{K?>Z+?%AodSF=`7Gd8;gRN zf>f4*cowKJz@kvkuEBJJUx5=8l!{!A44|d~XxK%81Jncp&FCvKDQGHiC~#&ev3i5n zdVuutC@?8n;K*MHvXss70%#N&G;*XMCvbdvh?KaJtRN_q!2Jdm(3&(*vBH!M z^4AT1CD!S$r-(>d@IY!NP-6{}7B!gu@G0PTu?IJW%t3Aik0mj|n?g*OYoO{;Dtj}u%HABcvfr|#6?_OgQOzJw2IFN= z05yRi?JF)wRSv3->&=+J)i1MIJ=Xdcyx|O%v0)2~{xcVX>tWa}VW0*mxVs9P*n*TB zB1(M7s6Qs4#^caAL_^`MCBcpS_t%kYx@okB`%cU1y?!z;7Y%R18htWI732B0XKxM`C1Jt(WGGm&;0k8bn9H(%Aj@;PJs>B6O3cR4OYGps@_cKkP_e6oxyj0jtA!xe;#AVEV%@aD_uj80G?2 zQ2E8mt-vh&D#$bt0c={4~adi>2_-4uyn9DUiQCwVd`VV<=US4o` zgW?tBp6Nmg;;K^MBm;`ZEKtbI0WI@a05#hb`KAXdh>L6RDo6`lX4AP8#YGtxOjl48 zx8(&b7Y1jMHS7YLr%x0XH`Zqd1tpsX(;jg9;{bc1W4*f)w<|A$Bcr0S0^C3y1zm8% zY5EyOaUF2GLm8}-QGr!pA;^)u3``CRst`voS~2VZ#j((I1toD&HdcYlJW3o0osf$J z_rU!FYACTPs0b_td+7kwOM26HD~a>O&E$ed5ZHwrkQNe;5-U@^0;q|>rl4TPbOLOh z8PgFCMct9Hpep@S=>t83Ot}T6&I*Y1!;WBfl3B%9-e>8vW^+Kd~f8>)y;Wm+?H`Uw?rUB;u+zp03uG9I0-qbjb- zev}7v+@!*EgN0)9)5}%G`{f(nOc#d^MKU;AWI6tL4H?*A0^O7K;q`P?HSq+-ztbJL zF;dX|QG2V>Lp&l=*+j5ns6Yl@pQHcijh6!&60I(?U>xCP^u>7O;l z%{V|y3lx|IW==QM5;qo|#iayV-UQk=I*Ut*7dj$esU^Of>laMo*K|8=@ty3aK&ghs zVR}5jyw-FL9dUW&u^LWL&+Q|hygAcpp6LrRWW=T~)e*O2oIm}Ej<~(&8PFUnr!GT{ zBVVB-3+NmkPS6Cc}-gK_EhlLq33jMDHN%;|WA1vH`ffH@1AgQtrci8rV{ zV^QD)m1C?RiUqZX1eIqByb2rwXQuBq5>H@UFkQx2Jd<-R5A<-r=>jI=F4Hd=i<>YW zoz89|-pn-R?ercKaY^g=;Z{U*WoNi_zo&uQ`vYc+qEzdsvwuQJ9 zd| zwkS;hY$*Y?=ys433<{hIOae!z zpRy7USL){iYS~`T^W~7@3a9Y3XQjCYDTiAGVxb z;!%uGrt>Fm=uQF+CILkb&;&VXWgH~AfVNXZ23{FJ zBwcM*8ThGDtgppNF`Y9}j4Nl^Ha^3W_KOh&PzbK$C}{ z!Brbb&|5%rC}@$11$bdMc*1HbXqFk&Ka^Hv0ZqzXnEugST)F=HOUT;Q@5tpBvkK^t zH^?d|c0~Eb2FlE!1uROSH5lMdFg)rY$&mw|99faeFVHGPY>81oA&psq9aMlZgZ7b# zC@_O2xxu@DKr@SulP@(x`o5s>0^OYiONOxWiy2XVAzT6;E14vI)E*9-K;fAgL5qw1E!af)s7wfKr(5=_xLw)9?xsQ1I(&_#J1W3u!n$ zyVNW$FmL)qPw`;Jsnef&ipMebPj~SWSMdMC4ZScH)DH#i@oMDZR$zoJPL*`rzpP1I zV73JJxduii5y*<72S*qnYxr0-m}C@1K zFL56kFpoh1I->EM!A+VQBrl`DCa`6?o42@H{c#=z4h2CorURf(7rQ2N0BDaqE4O2v zBclSQZbg1jpOjUX0koqLG`^$Aq`4Qx*gr=t)k{evbtKr_c{Kt?i67swWu z7G+gncU)is&McgufoyOPO<$NRE;hZ+M_i9f2-J*YP~sJ6n7++NJhFZvmjahA0|Tf_ ztihB44i*m3nj36mTry3!4jnTf`kDNC+CzLgrzZxNtoeH|U&<6i6T> zkPryq{R~(W2z3MD&aW2GonOSK57Glcl#3fue`qk}C~?7;_rCHI*QtkO5hn0-FQgt9 zb~FRUKV;1aTHZjNK*chDijp;$&6vRHmjg0?3Qh`W*~5JK%VzMcIYed;n5(8w^%qyS zo1g;Pamem?KovYY%C5;gK}AUhTwOyHx`NJKX8@g<0zQJ3U4y9rDFA-?i|c_mMJmZ4 z6&J{10XABR#Ze9vB4~+07F=4879uj{%-~Rfg^a9|2WUSjytMdwvsK(tj*J}P$T0n2 zsJQU-4PoLOicDrq3rrL^z;l-@SPKns*5C$>B|%CASv3E{3QDNYA%O``3vy)mTo%pe za!xTQK7X{ai4>nBTm-I2SwJpo;8%h)L|Bwqr%wzN_hV#41WG-QKw*WKqzViQ$cv>w zlU<;~!_gv3K?qcIX9$4Cl$jhrqottXb`2)*tho*HxH5}_0yivwftHrAgJyh}fXeXc zbwT1%ZlL`$>>5lZO5Be1?z~KnptCeU*EjKlhH3agdfgQSiWCJv_LV5{VmFF+dVP?% zR6VBxsKy1E1KOnmiAO@|7(Dq;opcpAQ0zk& zI>0J=VMhT_o<*b+q#B;IJPXUKxJofAlPt&0FI&VN1&GeKFjq~N3Kmz_$6AU>qm*Lc z15{Z-Ns@B_MLNGL~>5xh$(!U{}B_ z%uv$6^6nOKM`e=3M1cc)j)shkGbnI?BD-Pw{6KL_4rx$dgIxiV&Fgv1n7~<$+?=jJ zTpl`$t?4MMz)`Qk1RfM2zUfFH05>0Q5qCUGbkmVn5uUNx$;n2X+zJAqn^ZvcAE*%H zWq=nj44^QFWH6M5f;5(-Bn?taVnBehSQx03M9yQF1eY84HWk1)u20SHkp1WLY%_^ zIgfz$u|WG3cxyvYKsnA~1f9|}VY*JFcns6Dx6`{K#Z?)nPTvqIF2yK3{dA=G6vjEz z6QaZ|45xuMqA-EVEDml3c1Kn#h6{|2^@_X-BG{`n5m2=zE8z&bTa4ZD3S*XnFl1Mn z^m0d8fxhYgqQor%Q4Q5#I>V&M3mUe7%wBJ96!@}~L>2fQ z<+B`F%RmQK^MmI81?F-o2~2N~7B^u78!IsVV6?cO+C(k|4h1I12Yi1(YZ~!6R&u&u zj5w#Lkb?Abfq5WZ?4b3IpiOiFlcwjyh)Xa|n%){C9?3Xk`u!O3aC@*V;1B@^r3R>B z!35W-0jl(M1SWw_AiSZFr2q{B5X}TS=VJc!(pd2@#%a^f#ENG~ECeb0qX26Ef(|SL z%}=xIGd3truZb1+XPh>DPMo-`kO+7_m|cVE4`?-p0=t69^wV+TGRXp<0|FQn#S}Ol zmF9EOGVOQV;Puag=QV_r% znF655lo6L+uE?nXZpMHXXtpSVoXaWjVtQ@7cu+k!I2b_*1k}#bU}{lRWL98@mcqz= zRM7AmtX_w-$hjR2Kp7HV;34cxDQ`z)>+v0DS5tEXfJXgeGMLC2+e}MM)I2;}+D&WCI_Yd|VNf zBn~Jlih$@nii*M@dWRyU*}6qhQEYm3lDH1z?&&L%#FdrA!3$rMz!zVDPVxY)9|EPn zKYR+T;3WeB)88hED+-B#0)YvWXX?jDfxHsdp>0Qa< zn$sg{#Y3k*Ocqz*25p1_twUo~-~$UV@=Xs(5x3;xcVuvPWG*RE;GI4_MO>HZKlk)w zDdJg-yweR+#l;zSPxnj}_hpzF-`u1#b55{TJa>VTzcTcy^5m#j7oSv8?F3!j~y)s8!12WP>C^vw2Um}WWlwKoQ zxd9$bs3Ses_ccMbWRlrKmc^SJrpM=sJ1|b0z93gT$O4>j*+BIyGw6s7CP?7|uD~1k zp(Qb-h+ze-*>q%3sL`0U6Yr03CxU)DY$U$|`fAE5}7G>~KN=4r3i}J+P zSa!20aZW#zCvFWYju;d;r}O56gS{eOTuqo=gXxDNWLYP)*yNlZmoF~K$T=M(&&WA_ ze!jSvA*Zwg7pTPr8jpdMe{7J_n9Y%?1bo&w2e>qbxRrPMvwU$&K5o$JT+oa?4`^lO z^z+%`2IkX16&QGQ9CRy;Ci4kp&TZ+U^WGq>V>`-SL7lq)j`eKwO(q zWcq;uNI~(kK-`RR>U4!d@ujT1j*J3xrk^SlS5p;&4gm49I4E#B*1IV&fwH84Ya!^Y zN$}YXGsIb^%NC1^Pwy=i=bvs}B+l!z>Qk$@50|i;&Re4CDdjERd(}@GFTc2xTcrDDWx> zWh)6dvS&FmgInR?MyJ5s=`%{iO$8;)nAU&-MBI#N1&9`#ey>DarhX!q0vEhB?#QCZ z?f9;vSsb$GhsgmFnvB_eObm=n+>UID+~7b~1hsC!Jdo!>hZ1usFez|@+t%R7a%6C~ zV(52P05zif4>N!kyHDZ*kH#r-D~Q4(QGwlYxc&A?~6*pv`53WEiOwX?pH<)f!CeFt=dAetrxDK0$<2MF@8PluF#OKw+ zi~*1FiGZEtIN>k@IH+Fm2`uCS9asgOw3*=yp0EI?5zwp+Je7dzad0|O0*&k30HqW* z$kaQm->bj{ExNeC!xHeKtDXsb5*)6Y`~)aTfyzh_&0@xM21G-e#1~u?*d0$CVaRga z4w|~S(ZZy+(qG00-q=Z>dEj==dTf$@CUcX8&n|2tt@a+(F zaRKelgiLHRL8h{9xPT|rn82Mpc1KVKbmSJ;J-w_(+(k$nr6a?Ur64i=OpUlXCm*~c zBTy!;HQlUMT!|gDc9&a$4cu{=USBJ&%fhQ5%%?8;`9NiK1HTe_&xZ?K*YZ!ds~4Aw1doMqL(+MJiX#Kam=+Z!ZfPX~ z+QA(s@IDA|Q2$Xz>iBSjdQThc#qGt#K;0fLs6#-wl0`joDK>+>&urW8XnT zJN5$>Zu2Flae;P|g0`oD8ol5KE2x?M;K+3GHgOGAq(kSxyXqViK)V4!N5_DUtYHJ? zLV;(~Q`*GU7!OSEZWC9xz00fwT09Qwbt*6@fcGn~fcmNekUg7BphL<)dyRg8HbH^T zHWqk}xc_bXgm!WH>3r?t9E{Vai?@rb3WHYrE3gP`;ZfkwXY64F_lv=b^4i5k8D~sy zX&1K=n$H7Xf!4s31==U8z%KB7`h|9JS;lkI-?fWJfEM$Bme(+MFoDmN@$ z*CMcEK=-`}JQ9TO`2?Mt0N&9H-o?ZNs!Ei!&6xuf*cG%vrvUMQPPqo1ln1&!9W*PU zZO;4wG{(@u1sa3+z?r4MEwF(ZTBtOF$Z- z7t}y!$Wq``;1-a@Fa|U*_yknsI_5d%D2Pitf)+&|1&2U}k|4NbyupyAH2q1xxX|HbWt(npB7wG;ncE>jiSpwI<##F$Jnf|a}Toi0Z zJtMaQ52zobD67B&>I8uX79A&WWhqL7BAY`|0z|PW%77>pMNtI~MM3BWCIT`5=UCHpi7P6E;45at>Oe30||X|Ca`TRW=!DV z2c0X%r63DB>AL(u7pxKI)8t_VWeL!zIXigIFP9@@iISir zV-aWz5kFdLlx1TFEt{M&eOaHlf)}47qrhKoB_XgPUIuXU6}(k~Pv8%dFgP&5lAwM* zW0t@}aQ6JdsU!qmHw;ZtqV+P!N{}oxTb7#2iMUB0cS~Qp#=8w1g0z{KJZPipwnGJcPc9}De%FL zQ(#vR2M;K8Gbw;ZU<|+qDzG~?FlQ-%u0>Q(P+$>&6rL^2ph^^E>lQ{OM#p+^0inUP zfe|!}1IqmMW=vbaMJcFw1!bn`8k5Dv>p@DCm^7GJz#d{!5OieBHe+G|kHs}GD+(&G zJN{tK0y~l2v4bfKRME3Lb})kmkdU0o4{AM|F}-0?0H>4}AR9k`?xS_I0G(Ov_<{vi zJbz(JiQRW@9T0-)0uKxb|!s)0Pm0XjrjgNa2^ z9mG>n6mn!xlyGEF7dN;;%&x)of=x+EK}dmLK@PMnokt0|=3vO8vI~_M z9cAzpY#6euoJ0L9-2HdyKPhYfu5Ex1X7-FFchOteX^Am54B zgO}=o28cD7ey}O>gI1`pJ2rrh5^(GQ=Qi-xEg45ffd!EAh@FswNpi0?DTOn*{cW>Y zoTHxIu>beiR^F*=MgWv$24t5`-f`$SU=olPG6N^SU3}*&o zgH+7Z9hZp9*7GQcD2OP?2tdyV1)cfMqro(X-;8Mr=*V~;4W=3VpvDeMwi(j|b_Gz8 zJApk*;1~~d!z+c3H`ibyuPSz2A}&|&I0JN0f#ZRbpi|7jlNNK>Ar&GGN-WIq1f9-} zXy|~#Q?A}|0W9e`8aWy&h)XN6DoBH;O~CG3LSy%Vi)&CT3#kf&HpHOro52C8I-!;3 z3U*NA4sxCrcnm@wW8@Ls%9jVXh{4TY@Pb`!c+U#l$pM`ubpn()Iygba9LQ95#|fZA z-yAP6W+`YdS7HJe5**-qms5#5u!xB@B4L zt-lUVMbJ4?jD?Wi>;$+!_!XF-rN%-r?M)Df!dl2I0ZnxOMS*QoZ#!-21fvc9Bcrp z`y5xWXDRVP4<}<#V0WCsnWey|0CGGiZ7c=Xd~?7~XBZq#cU~ecHJyKfI9vS@M$mX7 zyDq~4M$npQ@Px+>MnzW8DRQu3i5IY834Z9X#0$9q>d zYn>F@z!wm)JAPy^W7+~rFFU{m(E`RSN6@{4?2a2aVGZv+gQnPYULvkwu!GZ#=?Exg zE0{4I0J;1G+~v>#=>u@5pBYR}mr-!M0C(z32FDlBaji|@GV{uyaw<1yfJH$JJm@if zuw+7MT`|yDmm-sbk|Teif+F-lKX%6(oREoRCU{kUXV8QusOFr$f4MlD&J9jQCh+N4 z&@;H$9Up+)?RXxPF=2y=PdJr8wbb;0vxJ&eOo-7ZR?sLnZ2S&BMuVh)8Cd~*fDfTy z10#|GM2m23x46Xg1uMkarl;-~7a8z!Sb4Iz$aLS8;(S5^3KChM#pj?oMOM(g<5JUe zSBlH>f|iXdusSM$TJ>tvr>_*3ukT>ZQUWc3RA2=iWG1D+4?1@Yx{!#GTS3T?DN9jE zLBdf5bnZAG=wLQJ1yRs>+oC*-;1(Kal>+(0J;q3V52A-w!M*p|RpNa0k_w190X1H9U~?$ajtiePi95;?Ie!9L4b0-;2%0Veb+=oD_`x%H zhe0QVNrTqkD2Rb#T~tBPkt0h{P(cV3>!38in5`%QiFIfQL*{CEAd5JmAq<+QVsWfj zA}~=!Op6c{rUV*Kbt~B`)yvHb1zx%!O@6o_o6PT5%iv)9;{j z_ZSqoLDTQH+@MvRpiyptr##aqx=V}5pw7c{gXiJFx7dgXJeqF4PF$Id8$3NUJz<@= zlmHj##3Ci|E|vf#A%VNoyVi*-I)G<*KslKMIwtPO0A7X34W8pU4C<_dWZ4~I^E@k< zL5FLD#1AlL3Cy4VdY!nuDD-?29XHVGQ%2CRG>gFg>GJEvL)c-*gIBE=cV=8LecyWV z4926=)i;R8z@@r2fThlD085!~6i*bM0h$hG1>JDT039@ZF}V={cLlLl_@V zKe$=E6nf8`^%ikCRxSk&f%DVjwuoo2aw+f#ESP?Ji+DUE*L3Zz;*vaTVN>C*ye!ib z4~hFspR-k58gwEZJLu%Mi(ACQri*M7S7UrU-FlmNt^g>WII@&@pu^)!raNvEj}czL z4!+-v19WEqj{xM3JN50zc85%#w_Ti16f_b0gcTIXoC-V&pkj$dVD0pS+r{UB4xLNf zAzlTgWvBnzA&$*aZS(}=Ir{6J)BBBpq_mC^u;^Hl^_ANY5M7%;th=Fru*y? zKPCyKsn+wF(f!rtB4$XW7pKGevoyxD*$7 zbQrYce8F`0ed0arkU`ir(|z}e7ftusFV4lddAj@o@sbcmZt!Rsw>0?TFi2+zau_&+ z0_gNgeg$6S5lSw|2qmZy4_ftw7@^$22_B&YHRO+hOs?lg8XMfhsl)*ZLH=#xtkWeA zit}@TrlrAanhg$$H-ggG0r8UQYKOow;^1Ms>9&W&TgHCg|p8}a8NneplLyc6PcST^%0u}(jDM7&iKJh%_4TS0AfC03*XjtktNMNl9! zITV-#mQLSuQhYUN=MQ9!y^^ds^AB!Nz=Q7kVglWJ(ZLUDey}_K;LcLwbOfKf18r|G zKo@Y!fz*R9(8YUNGi*HrXgWbb)|?rXfI%nWE#U#})RzNS#w$RHdI3+C<66+j0qEQv zF3>2_3Lfx+1~7XKj~VEeZZLZZ4|G8T+(qDeVge|OaGNppfK015W9k6$In0<^c%YjQ zK>e&1@D1zWEeov7ppn7p2ak%^PhWRhT#N=^1 z^#xo4$EF*c7guFGJw5EaxF!cU4{-`Co!)+4Tou9Fa$a1WGoa7o9%og197G2WWi!4M;$a@$U2s7sPcL=T853K|Gyt{`9nq z;%arpdqvzW47{561QVpwBC5bD z06rZHb^nx)`T;sjOBN<0cY;Hz~&GoBodmRX=(krGN=AWBAwTj2Nfz^mfY(+ldD zN~TYcmSw582W^qmWv~OE7RsT^V5`LI4mxs&6LkI;FN*?)E`trY3&R3Bw;eoiCSlI} zLJV|L73e$x1y0a9FD1}z8ZX4MAgxj88IQ~goZz7|Nsw9`=Lys!9XH7VJ#O-Vr~-$A zggNsL5Y24HbOc08f-}GgQAb8a(AEhK#{;5SN{o)XUrrTwWJKH}4JtagF%Hvv1UjHn z5~|9Tmzf*1;8BC=gs53P=yrQfQ0SZy1!o*E`-mtgb|0P*k37c;?UD1cYGfYt;la4BH=7ws}m@ai@Wuz%6LTaV;lP|)(Yf)=t8 z_Ol9-pPfncGqRWKam6!|pQl`$A@0ZtjXkiRc?DL%&*5WqYD~-+M~-@AW7z~gGQtBEtRJ4VTzOd#i3U9o(ZkT0D5VMSnTxe9e7J!4Q%~?;{ za*`8^3QNL@HC3}!vUK&z(zG;^)YRERLxNco;?12?4gFntEOG<+3WP0Ptb#aWW7tJR z#l$5frKDwK<>VC%BZZ9KmZ;SU~p&IzA8s6?ROZCNqOTFX&Eg z4t>TaVoIDW4xo8-4o4;{h8tp#b6_5bnK6Mfx+9wv!wFFZupB7EgFOtoc#gwyhbZV0 zG#1d!Ivo0pZ^V>1LFZUGE)WIT!mPld!N>GM3^EwRp~<{Jbo%TE;uiAlkX17bpxfCU zPl#qIpp>5nrW@W87pn)`d;uJ^AX`9ZSN82_5O?GdI4cNRGJOSPSra3ue7GP6_S+4J z-ymn;vns$`bqA&pr1XZE8PgMx|Jcl!9*99BkI_+0fklA>6gZ#-v|yhoC~@*OgNjas zUogF*P|wrM2ww8W13Et+H0j6zZH`EoGcOPYH7`IVF}yhfHBgDw5%mN-E@){C*-yr- zfcKaiq{6r!cWJBuE{7d&PwRl3fCsK;PKZLABODq`&{7pF4k=X~84;)4fN}s6DAr-i zE5SuSiy6}%Xa?9Js=(z~zl9&vC<7-1fo?8EPHqKG$El18oZ!4Ft;p`gpeV`Hzz8b2 zxIjy?&6!V#fm^9;j*OrKzBwGhvF6wSy0`ZLcrE-LF(r0hNW|WNMC=aHEG5t^KX{2f zha-a(!xB)`H85G%Gb{wLK&hHtfx~fuSQa$)LAR2?62KENC3evKDcH}T33E57@h3#V zgF-w_Aon?f(i)cn8|bppM_`9sf#~CD1Vu3@@jMVyVuGHEUk^z-AZmwbmZK5)VCflL zpoIAbtgRlT;fyH6x(0AEg;@s<4yeBcK*}zNDe)+<37i9`Yq0mhx^IYqu9N`hF-8T1 z-xrE0fH#*YGAZzQJ2I6x@?(z3Z;H8sm=X8}EussUp0>Td%;Ozy>hGB))Fz^+>3#RM; z7Z+z=0LlUajnm^Fh?{VLTB-2Tw7vyanlgj7uz*(3fiGoNk}zk!AO^anJqMH^K&`d~ zqM%TO7D(WGsKJdxklAdGqDajK2I$Smk|6asnuoBaQaux>5e&H+8eB%;YBoR%q}Tf! z#2rNi3_y28!P`BopqPOcNMJU+K!P^jKz1;gVJnd8kxL}-rQ4t@;6S+sR3I^PD=>o! zB#1H6ikv((phO3$QJ{H>5n7%wT0u$^aB^^bjZz|Ug2E6~W-2j*7S+{&+t36O7OZCr2UL2hFK7!AoVL~I)X!k>4BIMGh~G`xLN{L z)To+4hm1m80@lr_zzi*-sz3#zD5z-yDWRCaBM0CjYKbUljHC+LplT2YW==JtPIF}R z1$iBG9XF`N2j`LK&Po3Ub&^4A5D@pe+m>`iytPl(=~-K*mFh zb7*FP7fUQqg-@UgK}tbwk2j!P$7Tkqb~zwT3dfg>U~Ct%Qa+ z=tgo54WWx0Zt(a6?Ry2O688 z7555k0+31p>`1VR2h(Mrh)ausyTVA`eFO4E<#fL%;(Es5vdvLY0a3ay5rqT>D19p6 zbZ$L3XhHUZniY7Xpp;vIji?wXh5CvO<}0MALWzM=1rA@3S{zaE3Ns3nxOvNnh=DSq zW1s|NKi(JstH2inWymoggdPK>gq*9(%~J|;E~h5b41RN_6)d1`spATkEJqH|sRE#( zQc!39E%YkhQ_sXzMHhg!D1q;g11DGT;eHUCLw3Hn?(syNxJf8fOaRc zgH{qls<|Dkpe8eP{~_qCu=R`r7X?9k$26IDu!1(=)=v+3E-q@h0U>?>EM5mH&`zLh z--u9l0<5fd`hw@;qV?Ml;upZ;;PUVWLOVQLGB|Ex6lmjxIN=6ZZ8gZM2S{pRRV{<# zW`x=YV6{~swJ(s=o;WdGT%jJ6QyjM-6u$r~24zmi4@ipPxyo@XLhT2z+6s`tKd`FZ zj!^ppthOAawt)>Ew2t)%7w&yAPpu0a$GjNbL%&YWE}5 zt^lho1gYJ?2Dv5-&ENwF#T&qi3qXo@U^Vz4LhTN)+I*1O16b7_La03eR-4BSYA~O` zs`xNM@d>cvT#&&Ru&OOkC zzVV&7h|o1gfh*8J`oRGznxdvpcq=ZIa2+AuzzGtM1nB~;Zbk{{8;k;1q1rpZ$|69@ zK#PY_l-)!qn*df8KAr!axM=Dvg!l}wco;}KXe}>__S*<$3&6@kLCQeuXi=2iK`2`R zRu%$Mwqg3gx8kB=Tmsji4&4Bj3kJ#UfXH#f<#vGOfIA#Q5NH7r=7lgScqD z1YEd*3lzzoAkCm%>hN%NWE8jw)!6}7;sH`JfeT*GDX=;+z?Dn@D{%)YS;2#>L|EV! z)RYxGAdB2UN;cG^s1bpy*#K4p8iaP-fuckdu4D&Ti3`Y>11L(w;7SgFl{kZxV2=EO zhXUm|vcUJdF*q`ShxHh&7}kS&0?c619n;%Cip#@xfj2W|^D#3pGMY`__EB6pOaL+% zwLuJYPUkNcP%Badv^w4d#1a6Hrf`6iuqtp0KyIMoaNG$RV$@*bP~rh8;!)xi_zj*~ z*)QhGYXX{M**9JPlem<+HHf`e40M4on7LC7G_tG2jK>VrIbjDkCP4$nw*?j1d91k|8NsSS%ltueIe1lD zaXT`BRWlX3@`AejSX6U^x=R9J!!4%^eij$52M=3gwcUc-5pww_2WTphkXy~Up~1l9 z&TFc`=EztG;zPp1(ZIck*A&#v7t2xt%^I=@90B#APKafJs(nbGo5gV(XcU(VI*NM+ zG}vbb3i%Ua;Nf7(qc2XqmrqZV`!2Q(bV3s!nTOcB&=1NYNmy%=r{CRi`#4&2Ne zVv0-(j0!vg*~fU4AT4i@37|2kHK6F=GJ}lk!$w^=LDO}hebx&=!`+a6Dx0HxA*3fQ za0fgx1R74{HHVDN(D>xh*z{C7Zj^LI(xScEwjjNV=QSg>0 z1_kh$o(`a{6zJSR&_o_6;Nku74p2Z(0GZ>cufXBhA(|y{7aYn{Fbr^<0aB&_npI$$ z0PW#}E6^FDpu)=@RHQr*0he!%C+gu%cbJo&h#8FK);=!Zx>$Vqk}CmjH*!4^nIPz(eq2D#{f zh#Auv6c?QUx#$AO7)MC_1pd9Enu|1%q#sr?kg3Q%{uB8VJ zUUg3g&C}J}g5qZbD8wAK6j%iAffL>qlt2Y5*#S}liRKN+VY&kxrZ(WgGDuxD0jv^w zfifsZK!>)bpcrZc$qw~Q6GY6I=0M__E!&J~1}LHzfQ)d|RN!!&0gvb<7}_0IfRsVp zv;f&nE5L5DMsm{!VMv~Ucd4On`cf~9oFl9uj$-;CY{v9Q7@Q+OZu%jtz~R^cvdmFK zfy42KFf2Q?ptuR7+pz~#hP&TpzC7drppm1ezWEWTl9y|OY zqy(CJVNd{{1`AT6!SqE4+=Tf9R*If1>h&2LP`nG$VUYL!K+K#2b|GlQxkES$)ShH<6oi((3sC$6G8Lq6j<6Zi8mP%DKy*F4%v%Do zU<1fNM;XwChr+Os*@9t`;|`EA1;ll*mOUt5g}7{okRmU1 zHV8873L2XPt=|Qm%>)~rWM&jV9-fq8W);{yja@>1`r<$0nS!9X97iQbp|+GO+n#$0TQn8M8^P44OdVC7o=2!>4G4*6uN1d%hEX+5+exFKl9 z^h6Mn(;f(dnnED`j?W?E{|^LVS?vv~c97#ffK;NF5g!CW*~|na-vE|JL^I6sEg;9& zgNlD}846b00aEMup8=Hl8w8cuKt%)t=)@n;v3Y{XwFOxD1h8^>km?RWWVKT;)iPT# z%m8_iLxX98pc&H~kSE!!>KWF67|d1-D?s!Hkbw%Ia(0d&q@0C@^cECiec0vv3{pkTWp0M1JoaehYt zIYWVzYB1dp0LS?QG%c_=eszGk6BWIL8YhWsrL21ZbFps;wr z4-N)LHfYn~2|rQ<*7JbXFk3Oa;D;{6;x}V@!>_;rT8Q-rL^E44`~cAnV5>lB^9^Vn z4rtm)2wIS}poA;PL=C0}NYHdZbitDmENFTlTI!)K7>J$@0Y%W_k_l*fV1?`y6#pB7 zBO(S=#c4225CBzMph6O**aQiHLKD=v03E;ZmmAhIhaRIgJ?@V<8{?np57{K(r6{A} z^qv326{jC&k#HcT90j`?OF0UT3IkA7eBc8`1xo$&g%2qN$}xf(79xxW(;GP@yriEpS}}kt zLssZ=GQ5@H4X|4=Bk=}5sBF;(MdAc-B(gX%K=acSlo$jl(O{au2QCn2fR&=e_Z&Xt z$bqPy!3XYhEU1Sl$H*&7_>@4mI6%*V1?d5;oLm7)BkX2OYoMuP4~Pau3it+_1$^KL zJpeIMfx~ePAGkt+Md%R>cQ`WFTQQsf8OmnHbOvM?n-#+y5Y24Ga06`U0X}eqK7bo~ z24W~ILZ9#p309DEe zi+5h+n1m>uzzdGa8DOPM3as@SOt3cn9A4x|geafE3y!1(5apQh&I?|F!=S(k>YswN zfI4g|K#grsyz@dzg*_me*@|HYFDN4~-~~s~0f>>HY`KOPHR3Ux4N6QWK!$ReF`WS! z28wqO4O*THHuM0*oev;}DsVWSftU%8cT6)uH43jnJqM@_`UYeen-#+!5DhBbz=l5H z1tko}25=04%CR>PLj|Bso)(nE1oFKGQv)Aq#r*WJKjM6lVgXUS>rKz(k%%XuWbXhw z5wlR}0H-5eP&zsRo`FE5qcc3n=?J7mgXshhI2~O8D@7?3uJ9lyC5Y+^Jm9o(13E*3 zkvQ&P=m8~;2cS!**vy!ofX2evtQfw4Xl5&h58w%h8$95|@dN4t4#y`vC~4yl4|4v6 zxI^Oy4=A3%ISqIB4z+g&D}r@Fxz|hj5lKaG12~mohIRulDA($MLi+(XB-gS+v*HtO zCV=8%21vW(14tWp0uQW>I|r(}9x{dv((bqbq!iM& zn*mz?18dtY0MBY^gM2W98*4jv4oY}{RW1MpnWF;8O*6Qa*x;-DmT)5{J#A2b3{)Ph zfQH=yZZoDeAe-2%81{f@Pz3{`4}i=A_f*!v!VVI2N4SyG5Xf$jod>whn9hLAWHVzr z0n&c~q~GyABpgm~!@{Bd3Wj#a8z7~SaJT?nxC`#A+~5W!2rX{#vQx+)GiVi?5+iJ< z&H`}#(8I3?x^|Eeygvz4&VU+&Y>rweOHdi1YvSt}HJHF_Q1R~3BW0xdPEU)tqn3by z0(4n6cuhQ*4V{Mpvmx^^j*Pa7@WF5Vi{e?qBh8H9T_K=VcA%jW=t#2`D16^Q=4X+* zGwjgD`UfuL%mPxZ!Ssd;Tr_=wYJ&G;966wxesCejDo7J3R=;qWF||NrwE;wf+E(>U zph>MiprNe}P|P_>f-VB)f{pU^phPgpB*zILWsnH&K#t%E;0V?Pd1nvQWr%@3DX7a1 zpm;}<8$27a2jZV2P+cFO6Ev_E@(C2*fGhy{<_Ku1Ht51BHZ!IRAR6QwuxHMIJaYqN zn4>hP_Je!o4u(OF59&ecAilZ5g)~m}06a6U0rJfZuoC2H8kle9pcn{J400LhNT?+! zE?NL`(F%|;j#8jeAuiZR`5LZzxRMq7HKF84j#P%mohQR0L9~!E}ZLl#1#duW*2hXUq|o8yv_^1L*;I?h1z)(-RKJ zFu(&44G;D^9H4<9kYSE;3LK7iIACe$4TeFEA3(~$eynGD!GRR)AHZu`)IeTY0akPe|AI=@3J3ks$s z)&KwJH)jI(m{_1)UOdy1pthak3eW;qM@4v8u7Mn?4UJu}k_{jwkf2-v+U^ExjBEfe zeN_O(;tY@yN6-=Jkjc$CD5ijwEC4Bim@)%w3T#?r0oWLMkTIZRbr~Jy;g0D+F$Sz; z0>YRMurbh4uL)pN^jtx7s#f3U;#BxWI(3e0Gk5Jbr8qgftykf>e+$SJOHVI z1kDX(V;+Ewkp>xa0;I$d)OLdya|Uh<$P}=W3m_#BQ%)e8ash0L6v&hvASI5VV7n)% zV9KG-xCg};u$luPH4tNVARBW4Y>XtRS+6*Krj&#MWafq)I&%YRlwg^;*#I>SedcBZ z*fa@{qh2tBstguK7HEt94Ks4}0#*X*#ekL|acD5TU^Zj=!VKyDwy-F0fO+7~0%-CD83_u7Bg|$@ zS3t&s8a^Nz9vWvr2HpS}=m_e(oMDF5z;`eVa(n<%21zqFK)Z;bB}6^*17=W05CetC z1Mu+&m^I!LCgkV_Db-+lzyuDJ7ho+cjvUZXdBcPpDj=nxQ278lB?Oc*n9P{Ifc(y8 z#n1wBJae2CLj#D>0d^ip>I>+CBT%UDLqnwp#WNryHJCb>LEUeXdc88tOps|fMzQG* zauT-Wk6KLtyA^HJY63VI!P^*jfWri32w@LO2!d2;FztYZ-~otgc+JWJU*&d$3AsTA z(gaEl2f~=ln9hI#6x3M*h1dnK380*Df(f=~@d}1s#~WZ};5Abhpr`VI+W;0v!5z^T5Tg$JYy!0$DZ#bjvT30!KY)Kx_fX zwiO@~9B)8uTL7_*L!WUChIYpdAeE4uwE{U@H-N)c7}oIucU6usf>v#TfKzv`zpvxq63Di3c1{;JdL!Srs_Jmk@Gifj3;-Yks2;zCrs0rxQ6mXopU<8#aLZF)wSV1QUF~OGUHZp?lV!_t3 zV_^c_^9wqu2NXyP>P54ZSRFM{#sTm*?I>v3-EMCYchnRx0IkM_?nI5?hj5_d0N^Gc zY#e~lFaQ&@Wyb;@2Ee-DObArqHZX!N2IEm+5_r#|Br4DZZoGG(gfdti=w>U>nn^|_ zUQkqZ@PoH$w=gP!)^;aC4tD|VIMrpCzzE)=iMgDQk;wr(9t0X*VR2Ne#~ZFx8(!J7 zstI!B066%N7V`PQ&Kv+sU-UmH1BgMGIJ|1OgC4N5KI6km??~i zVF7{D;AAxiBU$M(%wPmn;u=g-7!}#Um8lZsrd1}#2YjHjly|d$kCuYoa|k|+?V?OOcZYd`%;0H8+zZW0t^4 zMv%b|#FW@T+w#Gityw{f*dK`roSJT_A)(AzH9b~C!jtjI_T?H99*m4)(?4iRWHLUP zzE)d8X?l&8L??``p)JwE_+Gd`KVK}SMvx}|}H zIVik@QItXrUm!ZY%RoYbZvn`1A&BVh(dqt%66y6jz!Ar+0A0!s zF41=|f=YBj(8ZaI;G<8mmElaNWjMG9zsi6&vtc>kq`q&4IP}IyQo83aX10hsUS%L7 zw}I}DLptC@8C>EJvus!pREj%fgNEoFxuH#97v#n=SOK#Yg9l{AfP)#652Rxh1L+q< zfR-&nE+PaCU4rfl1uflRhPHiEkQ*x?vp|iN1ki<#;AQId8sJt%256Z&$Ph;}(2yJh ztW#8iuGzpYnb2ig<#P!+N$85&;T0tz~qfw9eGx~aK@A|vngGLw+0XNS3j4dfC?RKr~YRt|FsqZtzm==>?@?s?EjE^Hu|5TgfD zWq?A64Y3RrbnuK6`1Boc%M;YR1E2N7tpHBRphF?V*ciE;7!)O@o106>OS5o;Hso`z zb^8CGx!FmfO+lhXK@xN}KM&J%$M51IjEo>kc=~b+iFn3m)7dR06d6BF*R+%{WqdY0 z-cmw}@%{8FONlbZUDH2WO4!@46=mYAXQ@+WaNNL@t;D9npuh&HY}pl91r~q~-eS{d zWI?#UOOqG-n3KK4>={$gM(73Z3=l%qy6{2@o6_N{o(Q+R=^_RN%sLgy4*qE#i*S z&=Ukf7pxE)e4tVYDWq*7`Y_X(0=pw48n)KCBy zj^Ifg@U7}#7AL3$@Q0xubXAu|wgQL1BhUg7ooq!=dyq|+p#jt@Wdq%N%%i{yI>Quv z#WA}Ax4=$t`P9J(DxjEP1r(?d(q+(9;45_HWl~^rWO3&OWie(ehBcrv zi^Gg*1&GgBZ^f_$B*1M3y3>!%5z=r6olwK(xPlRs5I}t}a6$mbAfyq`1&S_E7ZFqe zL28IOD1io2puncdG=ctw zP`N`?2!XVNlQTGk(8C85hoEIIM?g;DFk?CZ_PZ6s8OC}AHU)0*Ev;;jQ8ERH-w%NO zegf1BhGv2*C_PWGiICATa20m}GNdwq)Vq00k*zOcZP&Xpz4F%)k#|1KGJ1SV4ElGJravY>trOwPSEI!SV9|tdezl zqmzWL94I$ifCAV7l%*hf*$0$S7(f|i`U+jmCVS96h2 z6NFi>V9vwtae==)(>q-xWZ9ZtwulSNnZCwFLY@tD zP`kk2>58j`g{MDpk?3RmIK9|a!jkdh^tG-MvP>UVPe0=-VQKM~TM2T$t1B-f=sIz5 ziNXRZRyYJc3d7}?Km`wj1``i>{U@8ipXs)45;}~#r)RlI)H60tf8{3O#5jApuDe7K zN z5Al#tU_3p&)I-9;>cpGr;^2bmNcu7by&X_*UOTvor;Pi`L z5_XJtrwe#XI4~Zc9_TG$!S-rLi@3n->HXdkR*ZeqPkBqoi!KFU(kK8ftJy$X;z6fS zPXFgEp~HA=y0(vm2GeoD=>@Z8#inQbNQerHfK!SBlcSL1z6mqM9mNF}OrPi@A;q|7 z`Whbz9mYM=Z~91dFfN#$51RvM5bT%m5^h+HvN;Y z#68BJ+b{Y_Ff$sxXK`fAhF#uk;wBAB(V)_sL4gr^m;#d{XBMRT0Nti7@OwI2fP}Z) zQ62>rP*azY7n~?q967QS7#!b%F56)iI66H)KtjrWnLIOlJyRWHjWUDd2S#Xn8Gd{= zJNWo)&^ild(3mL)=m2dtM};gvKvhxMhbgZ^ABiYIVvz1E`)QJPtFJOmH-;gH3TF(dWP7vpaS+sHl zFA0vAO)E$6kl=_pv~mPDs4y1DQee|%P!X8R3+jV_(yf9LQ6PPE|aADoxqZn^+UiBN~&O27)> zI#^&nu@1rI4rX}n0aeq)=AH$VS_`_?2wUy}Rqez&Vj-;@!Oo45Oh|~5MU*-V5hb9O zw*owEI5K8~lPn2tSxk{z*g$id0^N{w%1T0RUP6(z5L>Ypt}G-tVkvDL!Cnt)-{~^! z0rh*>6u6+(5+|gB0Il5wx!-Zs)m2xk92o>o2`YlyYhaaEKpC6Uj0s-4!0JHo=#Id0 zn2SN}V4M|TJ){N%S7e}GGRQh5Cg>>20Y)WW@F)VfMk)juq`+$jt}($*1Kqz2+WiN1 z79;3Tel`szP{E_bsLQ|r8iG<_gr&2KAlEWmF`%Wl1a@%sjVKsF)iC1%hmPz(y-1rnUo=f_EiiuCbprjw{F%NxK|-z`>HJhCP`p5b z4OB|8RIrQ-%eK?`k|m_VP;3G93#Q>UnHYl^ zmH4I$CQFFBfszbns~Egc0qi0r7J=z7+u-9dEYR^7Ch&L+ixT7XdHmw4)Ay%Hn3*z} zF@c)Qpgc}|lX-exhJ<)Mq!_p0Rs_WtV<9ht0%Qb*(eW<>sJ9F{W`IqfaSbCV2Qw-_ zb1-=7YXK}Wk&?>-a72Q}@f|@UFref5*fcFon!mP$PX_XA!g zF6hmEuxSEN{|L13M+wpGVF7h}cmRKfPb_GdGHYwHqg-;M(*h)84}7`pm7HUE`dc{pjNF2 z$bN8_O#wU@0^j=1rpYWZ{a}WKT|KDdr6hnfq696wl|Tdippj%fP;mvVF_;w~lRj#1hmyiaBL77K`33F`Nkx`M6hZ%ILA2+iDxD@A7;C5%3 zzC2UHwtfba0zY)@gw63GgB61TsF7#QsH4E9z~}gq!Ci^Tia`x@pM({Io&p=*#c^c(OZSGnb^&x$OszsA|ip{HIg6A$ms<^8C3S5Tky_HLQDnRpjBW6 z%_T#|-m$3!ImG}x+^Ybp2>vjDjt@P~19A_Fo1rtv;7a?&^pm*~8jMG#f6A3mXIwg6 zDo?_I@z`|lJPB3CzUhT|5(+#=!Ar1Il$cz3nWigBD~e9vlqVs@czpVYe{v$zALdC& zGtD?T{a+q<6iz!|LYwi)^zeKMbHJTSppPw(` z&A4#->wF0*#--EQ3M4!kXHE|&kdWh?#ihjU$do0pdwO|+L@wj6=}!wJjF^t|Ot&kP zkeY5>C}GUDg^h`=o@shcp+vy+54_SW)Atohh}HjOas1C%=-9{z8vW)_;6kk3bmIjj z7I3u$TUH9%eena_xaEP|tpjbsf;)=fI!KAfoY?|Ybc5O|kTEZCF>jFtnLUM;A}r8S zgts1~miS^mL4i$y$DBC=G^=jLl%l|m5OdBsh$-h3=!`R{wdQ!^_;hhaaK+34 znlo2m1%;;)yCX|B9}5#RGiW%T-Bp3zk>9OIf!*;WgIf_~1RY#nWYpuf08(0nAZBuX zK-Gd7lZOHu=qyDS1$M}mQ&8=|=6HkwGNu6mV0rcw!QF=(1K0v`g*02%~U0NqsSTq}%eyN1$^c%~B6&PPk|G7+9n)%I#=IIYBxkRVyEEkpz{rG zy#>T$<91|LWOAHytPR9t<#rTOWO7`zw;9A^;dT^IWOAGZQOOM9eTMLuASzEzpR-(8 zf%zyCgB$27JO;&L9BFC z@>F1`cf5-v!s1y3ic!ZKNMa`byx`Dd5O~4F&#eG+FSFx+@bxc@jvaF#7ArwYQC>#S z$+wOIjtq_+GiQhkd}jl@^-M#9xFfTG0ZbKx0wc&Qe~{(1yYP8@AwyLC&*q# z$0tkMz<%Oh%*@DEugu_Rkgdd`!ocL9z~Fd=0W@*IB(Qt?g;I$MM#d%6Jqxv6___qab{p( zu$|KThf#?Qv@*1RI!BenQ^w@!@2Vuy87EB-tClcioV>lGS|XfL=B=Ot=t6rH25x&$ zegNIb^-j={u@KacoGxglC^lWNR$`O>gPGICHJKUAnHdxq9B;rmpq?@VsLA>PE~LQV z_+sYtPqh+H`5R^-Y5Fm9`?ETUi%g7@rtfH!NHCs&EZG6)fTqLwL6(C|T>uwWU~rr< zYr1!nL{>eTsW2B%4HeLF+=nWlK)k?nH;-1r$16ASkwCMG6GKT086iCG0C&giHp z@P4{NnX0lpQojKl39!4Xm_UOle;!YlDp!@QXR2p%0N+HY#OV0>^bB!Fex#~Hfk~Hv zL0}nVt1P%KX*x4Q+>s4Mi3Sr3X!?r-QL8{Jl?P{9kkvXe@Gx>aGIA@jfVz|#OcG{H z918UepaB>eGbX5@h#9EHV0Kidt=EUUqCAE*a33B3`jRruAa#eDk8I(~KvXxj>7!+6)7@*Uy4B#c^Y~ZX5YRs^Ld(_Lglpy0TpxmgzRG`SNz~K0X zAxoj2Re?#MRRkf+3R;UR18NqUF-d?9v^QfCQD6nN!2}do71+&~coZ1GOG;Q3SRHw? z1eSvr#6$9^0y8WzD?3hD1W9F`*pi4LsK*JO(4MYdrYb{vO4$kuD%50vo>F#$l!&9G z6kP^Jl*F{@bc?tnA6yC61OiVVB9K&rnn0$nX^~LSKY?5h2xK`PK<0B~IqpE_Z3f@$9b(!PKZ)Nb4`J-=JRgK^XL9o-UKjH<6UwScOd%^>|O4vrj-%nDqNpbeIe z%-N3jni|9%Sp_yvf8HaZ!Eq8)r7{a_o-W=iA;+{~)^_t=iDu9R*t`2ARAnB#oi47x z=*Uu{#F(wg%;5L}%m*XWX^jV1h&& zBjc9s+b2qdf@t2!5-A|MXo`d}BjeWT%ce@GaBl+z38+~luzmW~sS=tTTX{hvkpkPN zvrUum$aycrUbjFYB!%#hf?xMjNKOo``=8>TDHlCWmnGCg*dgcReX=@qji;u$AR zzcEXq3?e5yJ!!Ut2IIx)-Loa)82?OvHCy5!(?s#~kT5iCAYT!9HRm(QiZ)2zU$z}@V`1q!F>BJ(6tA(9T+3h0s(=1JHw zwTMi=Fi*lmX35MMVDBojDlj`P0C6;!K*w=2JIYz;>dE`fGoWNLwXOg^cD>1E6CDkFr*(`ny!to{04^n z8)WTIE^SXP#Fj*ltHs444O=!yMh@tnHa!@Ge?#qQhmt) z3R_UC4yjIMfiCD301Z}wN@*4ac5`OXW(78Ir%XbD#Ze$jkx_w{NrQ<)5wgTkk#%~Y zx{wrjd2>CBBYz?2A`MPPCT12^Hg*n925wMa9F&SdS2#GHpFRt*o|BggGzkMQK)DnU zmyPpqqUw8vqK^|rA817+>3G9pd|ICHFtjOlDpxVC& zMI#G}H&~GMf$qCRvhX5EAKcx{DEdIR3`4vxP;UV0z#+TzGf1Nz%%z}9G$1YoIg|<6 zLQuEC@m*UBXq}M(H*9JOtsl+H0I$(N3({FMAWa?y1r`k^P>aV~0nCKdXe^K>54;9f zb)3EmQiDU=9@36S8X@hRuS`tb^^BlJ_5#^T94ZV7OadFW>#dZ?VRSn1eX6*?A_;CM zaNj|JQQ#-E=K^Y%&%c9uH9e?U=gC4*@_hUBJF6s=Ikz!^n{)zir*o{9P!`$71Zt%* zD1!FWXk>vF0t#%KZogWhobmnig^wkKr=MCaA)(aHsK5+TqRU|82;Tb2?C6lK1eyWl}cyRVVZVLURuWQ{}!5oi#ZF1%jCmZ?!>deC|aO|Ct^ri+6{_ynFzZ(T2;%F@orR6kwO zKv7B>Tp>(g1O;&dD0W#uJMzGS6Q@63FA>N1V7k)=2^aZ8yb7$2Dp}w*loDi>-6>v2 zkPkr{mBLiU4d(yPHcfJ4q$T> zSOj)YSKKI}qxXRgysm6Fw-a+)5HEuxqaqW?MJ;T)3?Tx4g}@a*Xd+c0OMyk;|McpO z619wXrvKb1Aq`q_D7HyLUkjD*Y0_Udh+alr1czZg}RtYJ_bJNwgN`x{Vo?g3E z;)&EzP6ZZSh62c-D>$4pKwirc_%gkEn}j6yRM2&C3Rwya0#m2Y-zFi?_+|S3Z4%-r z;t#h;C|jN9g>JY6jkK^SusBM9=4qxfD=>rfGV?HUE3h~kWI-gD1z_ef3rwAEw_QSp z@$B^I?GiFtA1+N77dQ(u3)H*@#g_t$z!zqy`JjG_0+Ya<=?k|@1T%eDJ^kBui6Ev9 zk?CGLBxD%RO;6t;p~`r6dhZSicg8!@ukMgg1WEqbAt3`&EVffZ4@BP!kd~Ytzf*#p zsY_&f#!iWT&h=bO^`OyUndu)5IEAMR?~?e!)GacdbGJklD#yCwP<*H0JTBT>iu z8g%R%s3X86&?7Q^-W~~6#%a@!?2)i!yf*#c9tjsgXdHl)KqDY{uY`eUp9p-?3Or7w zz%0-&GJVEg2|32~(`O|q7;S&KS3;kWas775{SrSJ+17I@a0zUfE^$y|7UTNqn-5A9 zvCn7b1{V)Hha}c9G9I3O`>=!qV|vdK2|31F(^nsn&|sW8 z{mK!E4#uO?V~p*FJ3*2=bC&8}UauOVjcTYHa*c-UJ`%g<~3r}SR4X1&umt}vK(MnZ(~)^yP` zU{5=qkqBknJ$?Eaus08$kq~FxJ^dzx$9z_zgyk`d0+E3VDhu|2&m93p`Qfu*^WUG9 z@MgR>-TIt_hD-|+xVTkhB|F|g{=Wma;`liUZC0@Vr}Lkdkfl6$LCN9|-1zeI659Gx znR%Gek{DI@Fm?LH^AcjB&|JXcpuhq>;s+EWf6jwLMB{>l zJmb~r9v383d0w-EmdS%_#H-UQFG#4dfs4hf)0bY5a1-c*WeQL`mq}p5^xqdGZZWQ( ze(j>fWwEc!(1Zq>B68Hp0yma!P2Yb>LQQNcs1yc`WN0vHC@?!Rc(Bwvepo&I_azBA zp|#L73tFuK)^lyT_GJk;K776+3t1e4;gX$j8 zAu3=qKy3siW`VoYIj=}qN!;UwItyGoID+=QfW{tgO^?1Jp&t%16L#x8ShS4x+<{6@=hXfs}%e*e0J6650SOgAL@ z!6h!Qz=rA5Z%V9XTtD6QmP8Tz87@ePyYH673P#3#)6?%rgfKpvzUPjFHskc^FYZW0 zviC46u<0}QOh5QuMrL}-U5UT!uXq($G?^8qe|#t*KE3{)gau>I^d0vkY&aki9gGke z;rkLGea`nKY#3inZ@4cJ%h)sh-hByI#u?L99!P{S_DrvSATfjS)pU`E5-p59(`P=E z2w;3Q{nbMWUB*|_B_2tHGWJZ*dnDluHMoHlV(^7W68el&r#+Tf0BO+~^S%akwjsw# z3GAEx@UesgDDae@NSHFVPuDMz6Pup@M8cY}efsJr5;}};r{8!Y5hwkY7cv$d@A9=_8Qwde3R^jQA z&m?>p_f1cGCZWa)Y6vOtDX@a3|JP5S`Aou6>alsR2X+pPk$ld#kg_$rWX?JjE|>Vy_8S`xjN~kgaL@2@=~Hv ztKs)_anM>mamNWzmW1O1C`;0D1C%A@c;NSR`&Sa)f)KyVU~~M-;KR!Z^1|#_5aZ6i zk`QNnGyUl+31f>#%#g)cYuL<~wy-I%DsU=*{AR|qgAJ7V9HBng!Uk&Jf$m0Tb=<+0 zCGc%}z-tK&KB(*-Hc)eO$Mm+>60VHvr=NK(5zKgZyTTjLX%BCvXTFs%VEjCN)>{c9 zkY~=lm5>6_iSHy7LC4w%Jen@>PQpaCO+gRoClSQ>d%Em<2@RG`Mu7#>J>N?x@V#PJV0C-}u6Ec3_DwH;FJZwrb^3<)5^jt= z)4#u$(35~V^a^-13v}8StK%IekT+~UNN6)|nx6SVLLXw_oDUKTe49ZAg3ecCQ~()x z>I2w7=8xcv5cLsZ;2joFxPT6}V|9GN3^H)RM+t4lpVQBLl+c$1xsb(-=?jYjt0U;N zK2THm3rm*3p6Mc=B%B%dO^^5_;l((0`r=O#{){)LfBqz)&(tM6UFEZcF3iQCOT1Yf z->`zL0crgZ3qDH(b9@v~VAW*)!8*O*gM|2Wp)V4W;u}N|hn%uHeqqZ3 z?aC2YKi%nzgbm~F>GfYEmVvS$izE2xWmbVl(~Z7LXfeK-9{W|og}s#U%`#SM_(m$8NW>z_$DDCe4h(3;RKqJVimYM-TIq^q`?+wxmLr-2pYl` zfDK`TCQLVhc5Z>s&jfXfz!5)fddoM7IJu<~+};ok3mCJNm_Xf5&^#AtF$RM``?T*8 z5{wh3OMaIKV(gio^IgK8wVl!N$(rdKzDsmVYyusn0UEgjRZ*ZRZw}A^x4@+7!9OJ2 z7#~lc^+O_`ar^WG9r8{V`zFs6cNBy5!5P3EskdCPE;f_n6_7kHRNfUdfd^_d3GA4@ zu~lA-Z6~Of*fD*@b4XL$E6{f#z2j6q&#dc+BJ|U+Bo}&dWHxa67N; z^z+-5S*Pdyk}!oh##&N=$?+k`K6$8p;Hp?53)43F=@$(7*rr?lmWXD&JALYJ32(+- z(;xnp$Yb0-J>ZXoV|c@qnc|L8P-A$(-f|Sk5{qDI46+1vFgh}VTc8Ro zj!zgs9U_A)B_;u=Phb3z=m14EWF!mP{{cmH^Ir)|#>dn5{*};WyfXduUx_lt?b8`o zNUBaZ*r6?aP^b52y7oGrE1U^l_ z`(MI}@$pm%$u7q2)BTww?RCJj;mnR}U(E!cBLofw(0X45c2Loe2q1fxFZ1GD;Rg>~}Ib z39=YAVZq{{zz#AB68d;8Xl1-R-J4mmm+{>6o6M395|BhC23qpNsKEr9^ip6_U=Ua^ z-H=7nRO2--q$KB2;xuCtP+)Zw0hJk`EiwXsKw}aTpcWXjz?zGOrt@=1ipqe~DJQ7k z&H-viayVLKDY1egf>mJ0b_Wj0g^Yrmzz5e^D6zrYlAkywryJdY)QXPGg`gSfY(6F? zX7J*8Mgd4z^0|S|&j5uKcv%Fez~y>E`JxivYZLDF98fgMx|o|`_=UsPO(Crg1t-~*cyX#1%Qm_5B$Kyn)6_US5uk{+(_?#=`s zU=I!jUeIxc?4ZsPqGVukoN;d^@|3dzivo|pa_~eaXq^*_;_RBt0gx=tng@$vL15lIWi$I~Z^NUDh+;sqTE#^cCb$O~F{#G%2&qQoljc=`nq zNfnD%pnby}8cY&O%%IomPzY4iaeyL|Q(z+>ct{AO8>ChOy6_cF9vYnC1VfuPe zNjuOS*uxpq4a6lyqb-wN#c^GvXGqd2D-wXO@UK^9h5a#6}Ui| za*Md+9LBrT10^J@;8wWWyu66I^Z|6#rv`Ej&g|GWbEdeX0JOxx>GWJl$xdJN+K3gD zFhED!LH5fqf({Wf01bw*3T$Bq9fcJFT3!dPBRO;#Qb0GbgBIa%=rVW+oS5z`C27Fa zBRIWOO0pdq)b+b2cZ!1-_9=iW5hZqM&{`w~c4@SA8qAJUKpx|Sx*8NGj`t_Qv~oEz z7AkQ`J90WQC~#qD1%+F-z(?q+M$od7xgfJdKxQd`CQU&53D^|a;c9S($$x3dt->c^ z>mWcSCFoq}|BTa*%Sfs--kttlMlv4c!2nrFbMY6yVUvyuJPJByOdX60JdO{3PoF0% z>B_ie`V(2nos9dZ&y$msW4thZubgBl({{$`(~BitHP(P4$PnZ_i0fEDg(6yjuz=bZ z3*{xn7gNqI5mBvilhS5jrQr6RU})OF0@aN zRF&*j?_z-}0}aCPID-0>JdU7KRTu?YKsJL^t&38NsPVI9W*7?8K+Ip(3DhSJiWbJQ<9UB2gOATv?Lc|h=_BraVrQb@CiJg zo}(?P%|2@iIF(PIr!6VPcxL)eZOLwg9wvcP(*txQJsBrXpQR&tSAP$(V+67sw;=O5 zvK-eS^OyXczD!p#p6Nf=bap+-c?eS(L7}B5smItm{ehn3WDE(J>9h4Er5LA8-=;4) zA5}KdK+;Bd86T{IVN~Ez5LS>9cr$&2fus`S^68fiB#jx*Zf7@?6hjM)0#ixx=?+Gc zU8n|vh2I)UvNJxO{?$k_S_v8+UE&JN(q>Foz|+kNJdOvrvJ`k6uW)4voCAfC%=A8E z$$W%S(14Phu4E#q$#`eFkBOubW6Sh>6Ujx4r=}N}N=i@HHI)=%ygJ>%R8n5Bg^62% z2Yk*yI4KE$l_W6!nSRk!vVmtiqXLgU;|vic7GBQj4)T&lu?j4X$KK8q2b~24uJ>Je zITUytCrHCva-5(Aax9L|{x^#&3W4^Yuqm=Q_O-Twcud@mJc=xi2l`q-JVpqwaT!P@ zXrBt_^oeD%a?`oYC9N2@PoHNYY3~LuU|AjSg31XFL^;8#AOxD^0IlPMG<`wiPL5AO zs^p-mz(pI>Wz#pfAMIGHSajoLDWY6Erjzzt{~#|2WLK%XFu zXhKgHv6M7r{59RnQc^+WKcfO@6{agM4=6C%vJ@BvTBg@oN{UIIVFDfB^@a;{jt+x@ zFo^Sk%aKuF*YvfPk_L?Dr{A-blwdqQ{kx^4EzcYUJ&-6Ac$p*&P)7h;h!x`^PkGGbTMkD}Gnr^d}bQ9msuEZknnGKX= zgtH)4w+IWgPk(GJxrp)Z^fnvGTH!{}LB9V%g)gImumb3g@y_XDwvtwi7p4c=O4>1Q zpFY7>Qi`!@`f6Lr9L8VMCF~>>7%xt@w3AdYZDs^54-hqDVgQY$^Egfr%@Sy31Z`u3 zu$w^((iM0d&v1jn?g>|xg0R5m>3w#RWs(hWYZ*Yrpcu$`!V1y?+o#LgONukLPdBxf z)Msp*o@y`Y$#`M66AX&!PJ$;*lq#4u3i__mZNXiRc5dnEq zB1?%?L0ExPflpxjba_Wf8OFWSZ5$T?kuT> z8UY6*CB>%~I7@Q-?*m1^0!h$m2_gbu&IBotGr1s~25HctSiB$(r$94kP^1|&?gOzA zY&s(-gMx0w5>{Xq_&EKPv*dHeH`6z{NLrv;`OQUAjj?6BtgEB|BjfhzdTx>~c0Yf$ zh&%rK(IO6NEO0oofhe>NBa7pfSx7@6IJ3=zEJ?NLpWP%&b-oIL3WXaype-e!0}sIk zhZ3UzJQJ`ZWr8X0k~)lsrXO^dRA6kG{>WWYpZ~lFXpB^W*>T3o8K8<;!9!Alv1PiY z2Utmzhon4X*Yqk6NqNy0&{-{@A^?QJn%D$BO<(5$&cIJV)SKy2o|49lpQrnIN{TbK zOi%NaG-Pa7G4Z!%I?@v3)bs~llDb$*OgV2!UB*+>eY_>r7*9sZK@A*hdFfO0|-A7W6@ziv|ILQtyri1H+W4@A_ zjC-el@Rf{*sH~lS)=!d$v1R%#KS?#luhSX*CCvqoz^Wq_2L%BIRspb?V3l0VtO705 zFZ)YoGaj05A0TN|Kcy9^WN8q{a)eIcDzTa|fih)}K$hc-e@Jbe83I|La}q&vO9ZkU zmmtZ3PBMJKufU_gq9Ep}#A3y;Qb2*nv8Qzg_z)z}t-(Bw7usilmZU3rnKS+1SKyI! zobV6Y+-MO{;8E~0XPN-gH0R%R&Opfw_7(r8i#s0pv%MlvG8vSd?*vJ@h(80>Jh0u8 zpebcY#RDqdMFrVFqXujOJHS=e4oM}>>3j(SQq#+WC6ndvvMX|OD~Kw9qg{zf;258R zm;w{1)g+(*sxSrPBx`wHc|mP5P^*ebpk;bI7vJ>4P)S`50Z_RuBJg^;bEu>a zXM@WWY z(~rYRX2h!9s3IxOCl7M|5AfCEtO9SQABmDo0ZklSovsrtsmu6#dQ`Nex!7x71s=x^ z@U8Pqpq*73Of5nJSEnzJmIN)<{SZx(`^2ZS#!AYQ;>hWbN!4&LPEvyL&GcJwl5UKj zrz^%whBNj|uZ)-UCf3@V1WA&@ae88+q$I3_Vg{E`ZHbaL5bKyB>6uyJ)bxvqSc{T| z3`z0njY*Qm5Dlmq07pCvPtQ-5)FM`cV+yzo1eaO$DU$q*;I51~pA5GGD0hQ8E71Ig z%{q`a0clWDK~Cu)(dpf(V8cLc0ZFVXZX#4nO9LwwNRw3M2URkTNB&L+Re=JB`KBji zN{V4AWd+hCC8xKfNv4rhb)ExNov;E4U)4Ezx@?9dM>M4Be1N;^1hq^+B@m-P3utBp zwYFjcx3e^u?(isrDn^hbE2wGpf+0)b)bxf7Nd?Bc(-&q)ievYm6fbH+ACxhtvuA>X zN<0%BZ=eLiB@DWg4Lmf4%dh|)N%86PAUeUO9L00mr@q?>;;C`^!ct*|%}XoY}= z4jm_fbivk$;tR>yc91~4KxQCL-F*09HHBNiyAn|xG+nz; z(g<1?gF<2fiy{jTCwh@`Fj7)@dVis$JR>+~iSt5p1)HOgK#$P$%Y~Ar%8;-|F&v{e ztz9Ik4mDzWRuMQk zbkGb^M*JbB#5%p8~IvewBj@RmBQ?1#^Ioq$D3|QNDd* zg`^@Q2=kTx{T+iuc?;QWPCmSTD7DeJG4Q$XJI`(lu0v6_+pe8n_z>evUYb5J5K#gi1Zf*rZ4W<@0N1ZGs7Dq0D zTabZFC2<8F$2X#&1ujRXch*X#!YpW9FkQb+QWP>PfZKwkI>|c5yVD=mNs3Ed=LXMV zfEwq2Btg@$JdS@vvK$!&E=?Dzm(=9@v0{d}0w@RGBPdVq!fY zB^}t5NSKK$NH|tFvMaDi!$QHE7c>$MGkyw4?*t6JGaDogc)=@e_#6+cnISIFJpEdO zq$=ab>3)b@pm5*=he2ecWH;mX=}#La?QEMt zWdv+71}}qx9Atn4X<37u;{=cz*n$pdHrpTxT0@c01Q{g*#c*wtWS`L+F6e+Wc>at< zfe$o)28m#>2xx6SI2AB)E3hcYg63*$n@#~DFE393pZ1mHu<5(1~DFVK<{pVlg= z&vRzlm+{o}j5ctO z9$e|KZIk3?ygPkoo1~rkF?Q%ONL~g7(6UA)&>S4Iz*f)^87~+>1tRD!&-v5k+9fp^ zKTr2)mvm#?GrhlEQe0#|y8;Vn%A66jgor}{bb`jI>ATt`m&(Zl;OO+T9g?b+$Jk+; zRv8so9c{9dK#Q@!>#R(&lsE(qvx6*gP+|t{T5vo9S_kTQ9JEgB$aL*aNqLT?v%nh_ zYo-TvN-8rxpI+7}DPMnrT@gHS#{gRJsl)+Z@c=#mZZ`|eGSIe(J7CkE{F^Q=aFicp zO@b0LXh2qjDF(EL7Q9M^QQ!b*(cl~=xU<0yTEL_PT5-w>Ilc|lT43acEXbI{q%>Wm zOH#}o?lJJT4$%4Vpq&vgrH*Srmo_?rJ-UP`3+m4e$i_mHPcQ6}lnOiowsi-lG`K;{ zs=>5{NfET(Y!6eG0vp7?Y>u$70eS5JvQ{>Mmg#r8B-JIK3xMQKAj?5*mFbq0OFsdN z8|+><1NH)FEfKrpHwJ+d;Ph|-(=dn|9j`Ef+d_~4?O_4!9)akazOY+T5|oJ`!O0-d zGW}S$q`m|^wpbiMr_q7(50e7O?Yupb1rkU2pmB*VJGDph0Y?iHc(qK+^x9rYQ^w`f zH}^{FTfPRJ9LuJ`#G}Mv#v}k5oC9I-k~v6Ajt#UzgbggPfCaR&Mnr)fye3AvPcn*e z*YvVJNhikb(|7hsde~eAEhCVGR{P)<3+Pm3q#_G60f;^Y4L+GhV8?XZen^o8nh=cY zm+a6dJi*Tf+SC9#NJu10VBd7X36i#q`=|R)khEvqF};6+q#fg->E|X$DhtiyQvjc_ z1HO8IksGuWlzF10A>-8PrV}Oo8D~vzohYfp_+|R0iIS;|ho?(SlJsRCYxfx-dSTu02^&NvMMlG=UG=F2|_AEC8N@kDn|lF7ugJ5j=7ZZlee+U;*tVX9ATD zi~^shPns-g#rS&q*~yZsjF+c>o-C=x)WJ7hdWxhT>N4zLROD9R zblk%Tst`bn7V4%*YRT{CQ{dERyuhf$&dUr^b%xQE#laD@)K-z#@yqJz$EQfDF@B!@ zZi=KF7qBRC!y^+i0?Jgczy)5_kT_LRS-*uJWTp+cnBoGp#yCM|qHqa( z=9N<51ea{!-C3-TA3y~`^YqPACG{9TPk%I3Qdg`Utk(om`hb@LGYa(cPgk8L>CU)+ zdhRqyL&p8n=TDRLV*EV))igY)A!GiG-tds{re0_HO6hz zDIF(rFdpMm?;jrRd5EAz^3Vm zvn1sLz#=RH^T3fjhe?T@mq~#c6snHbK_8?B#jt%O|P9Jsl@nr`hq!< zMk7_2oq?c2<&RmQKu(B)r11K zz&G%!pfgOMdx#xDH}JA5a0^`JQs4m94B(UqN@M%^K+D|jFe$O}vV&F;-C$DW0j*oP z!lcLty7>*f?i&=|oB|M~FCa>JTzT2*K^mSgfs{XBQsh_QP~bCTdINIO2PV+%j-b6t z9H0~=a7PGa%MXZF4o&6{OiF?ZT#gLxYipE*1Hd&3sI#?AM3I$;joX!%O@Tv!-;AjR zv{3fR@`S2%0l5 z0NqE;YQ{7JWE3BGIgA<88W0DOLAgK~6ujS9flYzKaRzgiz;=jB6gWWV$!&p}0lqGK z2iPH?%)wFbxB<*Lz?7xLE3iWZ@ z#S10P7(Y*6wNO%x@yqm!3nk?kJEnhFD5=7@f4b-*N#%Obp>v>g%BBEI6`-45LFfA@ zfDiNo-K7S)QwJ0XHHx4x?EqbL0@|s{C2*C?RY3s0JGO`ybe$fX8B-4<=(=>UGSIdm z4p4CniRu}QN~|bm`*D~uO#t1O!vQLo6u_%XIUG9}vjld6gLVbF1`hC+Bd9u1(-5pt zpp_dGV;iRbUnD6izlPC_X$!~=pnDjgNnW+@0L zfSn4BRIsx8BaCKDXFz6wPL2iz6et4DfVF@Q!iUBuhATmd`2r*8(9s8sNI?V&A@DWE zP*;J@A%u7ry{h-}4aQn9jOHQmh`-kOnybROvt}T(F-PFd+vi z8|VgT4h^O`OyDC(IUHAjv+oix$pg!A8!+@Z!tN1=lvW%XOe>fKJ_{&7ZsP=%SM{Jn z1vnhPfSVl&$DuaN|GO-!@(IG8LSyWrwVasFnwVJEgE2jjx#HOif4h9 z0?^I1;1mHq>l&mRR1YgKIWA-bU9TfB3)Cj#&}434WSV|siKHx3Ki~B4OC;6nJE0O0 zpyip&pu(Utu>p?5Bm;`1*R$IbUax&E`fG)e{09_RH z22|GYnK8WpC7BuEBH#s>1QmUdVsrt>bs*^v%vnkx`VDgyq-x^OWS+q+unAmTfHqR| zGAn>PX5cbSiCMv$$#E7VL@Bskz@g7L2V@v(yMPPaE`Z*V242zlgBdjRH6I?h9Gc8O zrkgI4G-qmHnVz>yQipNE^x4ZKgBc%Bf4@vpM)VasXef}`kq2}MA2X=e#U!wKy25fv zJI2S;W1rdaJ!r|IEVMrW9-jd1 zI~Uk7{oy|e5f1oP0-o*4^3(OtD6vgHutG8mV!n-(0<&ZDoSEW|2VgrXz&k`hyEdjb zu9Or7tqumQR-Lm_(uncb^z$nr3(GgomsOe0w@NaX@$U4RRgyCN;Gsx0$HO3_v;-zk zU%pCGRRi2803D?WT3^fV$OXC>i@~vDJ!Br8kpUDm430hPr+--m_Hh1cNhhWD4>QFb zVQZ3jLF+GBQGC1m<@AS+%A(3UK#PsQamwllI${oVf)sp_EF-9Q88f}$yR77N{$z<(zK3MluLxrw6D!0PUifu|`r~rk&A|L6HG;VwjC152!oFfEF`@_Cmw=*)W1` z^HG_;pj}>m`r1vBMU300D{Pju7HfYyL)=jVnt0#_O)uOGiF+o29n*U@gEtlI+bp?6 z`Ku7f92O-e@RkJ@4JOba@LkZZB=9fq$4x?3fc`9ZB^&>#Y+pUf`sczXO+Nj23)e9(2~te{Kb z1m5r|v4d7`gQ6SJbeq0vtE4_-`}A8|C3Qf%Q&Dz^2(hE@58;>|y-kt}zDcBJo1~&L zxQosTwVFvvfemaOC_gfRjt5m>7g#X;z&1%8><$8*bS497Ie^=e(*?In+A;2!9uUDUgQ zcR0=vX9X>%wqmGJU6L9>nX)p2Z4` z1sQ)%FW4jL$+%o-EhC8s2gII3HyFUQ2hWZf1!m9C=Gz>9MsY#2UOZfPS@AtW1GHu zzhs;;5&IdZ>l}c)CU(L6nc|K*(6R~pmP2ftDM@i0c++FdLCH8!y}$%6O?g2#27uNT z-kpB-pkx$d&-9nQ%4*a74oP}5zTH0SkmO2c#?I;I4#}xb&pak6DY*%BF92j~pyQm| z)5Sq)heLr`;Oz9-$0TzZo2PRgm(-BBB?K89^MGFPcYz^Gg@L}J7{+om%v6oB_7BYI(E>+q`-pdi;qh>Fg~9CH2d`Ffj$5LXa>oD0`WJwkk=0dOe3gyO_Alm|PUVcLkdWEMQRt6$+r*4zwXj zflJ`q^u!aA?u^f-uRI~C&I|7BgAUc`U=%nx{q70LY{qBPJx@x?Se<1DT~wgSoB?V@ z3V<>!sCxr71Z0l}(*#CG=0Zm%cV5tFHo|Sw=bx062aQA=I4P;bh49DpHzy_C7@tiy zJ|(FQl1?}!DbILtdc!G6V-R;Mh`WFK)l=ZnLaEb|N{sE(ZBI)|8hr-!_!ZrFg~2{% z;}Hh!Q36%)%mOb3Kn0s9$a!~|K*0c7m?yAeddF!=E5=vT51*C38m^z!YlFp28r#GAh%Pc-C zX%CZmaaJ;f@x^r8bCPOu*Fl?5KFVSu3-m_$g^lLsesNm(oh1Ox5=0#@QVqgYYRJQRT~TFN=^k%0TXV}bQGiG4TdaG z1@3!ZQnvmFXulmJ$f=+-c>`2-a+)!9uq%MJMLlMc0@WL=SxS5g?2b3svXuA*j207{t+Y*`8%p!1sq<_jpW>oT;k zx$-i~fQ8sKm>SrWm<6_h4(kA2uga&uFVMh0o%MpGxyu@MCeXQ6(6j?_Dl;S}fC5l~ z*^KD{n*uv1$Uu8x*`Qqmc1KXiFbjO)6`063z2SnSq6sKyK}iKPlfou2kslO7PuP?= zSR6pZwh$9Q^5FYS9JpIuL3V&VH-kM3 z)Rkh_XWYWB#KFrB^56z`a94^0w3ToTyCNs(5Iacxf`+c%@Pe#=!3I(ds@`-Np0I)a z!>+;ffK7?XjA;ib5|{+Q!?2*8Mi2+`vO9LLgHkuh%1zVvUzF5ky}<_B^ziYbq$Ddy zbmMgXOOpCv=Dz99mn2mse}EI!4zRu(Y*`A-0@s8T*g>6|#!HeKjL)a9x+JLu%6Qi< zN!qDHqJ0S~$d(nXSx8Y1DnB-`g0_2c3+$P0eOc0oankg>%aTEiZ>Jx;EGfeHX8N_u zlA4U0rd^SgWZX1e>WZYkM>`{ElEaMY0w{5DnK4~q1BJ*8HbpQ!g-sE(j}qi6cE<}~ zcV1!3QVmpE4(p%;uT3BaPT`q{4)dWpC#;|3jtQ~E3hkYfdh@*5$sV7 zrXQf;n$`S@ppDh9!6q+a&jMeL2D*OqJ6NO(Nrb_QVG1a6In9`!fZWOoO<4?93==?+ z&0xjwq8=o{X~y&cM6;MNy#XaX1}layAU?Z3!vc0|hL=!w2fH=HSCBj;m4NP3dBBz> z&@Bw|*alEK0rm9RHJH}0D={l@gC>zVz;zQS3xEy)gk)46Zf-{g(CQZjUN>G=E>I$$ z{@|*lIC}@!pcm8sU6mBC2PJNHM?|FE0^dstPG6u+?Vu0?CDb0Uuivm{Ie{Bs57?X- z1R&-#fE>gDO1OX6KtpBhpa2B*-9T9aydRVUoPt3K6`UMF>6BX$G%m-%!!~`&HA%U8 zXh$F9Q%E8OxrbArM;K&m54)=ZpCglJ5ic_&u3&);4qQlNP5?*g6m~=cm;-VasF30^ zV_E>-mOFzTT#td`oylu7GF&yBd_xmVmBQ?iHTyb6rxI@z(T$ z>yVT_=enf4%sX(E0WKEVHJCQAgN70{6u|j^&GhTnC2KRlom)p{NQnlDN6_{-f%*K7 z-x)yZSD$eMyCMfDlpy5|$Te?RQOW{Fkl)eD0yc;a&~Y5>piM>s=caevkd)=vC=AM# zJJ_cyUXhfZe(Hv#4ddhK>^CLl7`IPXyD8~X{}NPxz`D(#;sR9cLFy0iq7g{>0xl_( z5DUNA^%-BVDRIK<4{&~Zzy@x9fc(S?syd+c2d4rj=(Kfs{lN)}YgW*;Z~`XWnxHd8 zq4kFXg90b0!es|lDwv@sbW5_{0kTt@6;?;HJA&@<0Cia)0nY-ez}_%|S}S`%9Z9f< zo*?S(mD4ZYk__bNVFtzP0p{rnDXP-bU2jWDGQOK0e_K+5sa0@#A~1HUEr>yd3`5rtGFO&S2CLd3#4ELx21k)WI5jW zKOM9V-<%mVbN@jj%kcuTzzdBm#}mi`2Vk5B8lXjTtl&WeR!7hR0ycre!l1)vd_aR= z;Je8@lsKm!yDKSL-^mEtQa(Y;aR;L!3upiv+M5w@=Vf)=4iV#oIE)umkw4G?ow_hV z3p7i^3c86!fkR*wKSVdHF2fTI&|Vx?(0n5&=uDso8VVc&tN9f;1WqzJ-T>`t5 z8cZTeoQ~qzj?<&=Ns2J`OwYe3Db3h3z5AY|Jmd7~tM5r_Gi|xP{l+~>Cq~gHBB1my z@KgjkQo$SP_~QR`{Rff~Vi-~pjuRSYOpkpaDISR-7w)*DVTQOO3r`qmRmKAb&_*9v z_+Tgwb9?|%912qWg%{*&NKihRe)fT+v^pff1`vF>Cr-0KJ!Hydsii1Fk|KL{~5wB3nC zVS2+ONe;|l4s>j2nlXLeBS~>g2L?EC*bk)m2!6$Wjz1uZ zeL;#(fE9b=^t-R)f@ZKgd_bztfK}sE?BjT%dB*hm$CBb17$NTM_yJ;&7s#M1_zm)M zoY4Zd)f1$64fyU|BwJZQ8}h-)`T6vJk0rhNo``_XPGSTNd$0>UpC0}MCI*`IWl;c$ zZGek`=HVb>oKIouK=V})u_UQ-<-?07ys0WS6dF18acwu2L< zPUs~}Zvz)hEE_I%0xot0E;fN1rcU-1Oz#c2SQ%Vw0S`>wdAQgMxR}OknBEP%Fm;V^ zu@!tUv0HGl4{$N#H!!_B_#x_EPVadG3+E2dakb!Z`3_fi0V?)#dca$lx&?v|z0arb zehV}21zb$z9ZYP45JcUp>ACMp-~qVCo7uJMK2n++Fx0T=rM7u%o&Q|J2wruPS2Y#ChafHF+of4EqO3QR2GCrs}JxY$Ox*bG&e zI<8+Zbr0ZT$#Ah1YA|(s;9?)(VxqrcdUvS9)aAj&8Z=;H$Khh2wVaS*Na2s9sNn`! zBM8=JT7fJ8YBMcB7MSsWdfFdJV~+P7(!z4))B zYJJP|sp46n^WHcVI2>7hr9syyf>wbrmpJZNFjG8Bk%bv_QYi~ajRHGpwhBDK0WxxD*#s5jZ9GSqU&M82I7EhOFkt$~FnLe3C%7gLo z^gAq4=8TJ`i?B+mGwz#i!z!f-pKm#+EF&_#fmMo!@#OSgRw;kR$J6h!N=XY}0}Y6Q zPQC-r3n?%QbO}x8W|J~vd^6pSO-e5gJhB09fJ=ZHd@Nax2QJPK7XTkA#Hz_G0UB)t z-6ZVvlfmg1D2a(=DXlJjul*@QU3LwCq@)k--skKpwLO6OX{->C-u+f_U$6 zfl>%) zDwe&S5!3}qnZBN1N`CrYJ}C}q(4Ziw#eIj-5jtJNs=>5?QHe|7`}7BVQo4*krt|Sj zfli4r;+HCAY@fb@U&@H_;`H16Qo4-o(>VpC4D@e2m@cje8mb4k@7Y0PA9j(vW)MhcZ*87F>Pm^ez9F#bovWXDSpNi(|?FcsWV=gt{^6*%D8*Fo0!y7#!b_8 z#HD1IK8Q~D5|>gmZedbj0QDq6TPzir6hJqOfUXGvUFEC9tiYhbBm*K;1kSK2Fo2f| z3$#q1CoUzyxN!P*aVfd_K2Q%Hv`!hc`~kFTvxgrviOc~Ww+7`C7SJ(WYy!RfP$z>< zUItym1|E$DWgGA*q72}%Xi(?(4{Mg=?!7JIj=TajAd>{ZOL#!GL&wEHNAGJe@hF0B z8(`*upVb#5A*HQ2OAwbW&;XylLPE+`?jUG=3=5>J0iSBF!obZ9343ONAKRHFrIs)< zexANUO3IY+%=UXyQsRt^o2Gx0meP}jY)@cOV&(}+1<1e#1E_P&4a(mh;B5e)D_$8C_(7(E2RH(h*vyzh6j(t+LkbKEoC2?>ZZ~2Cog5oxPAIx1t}MkH@9bsJIW&_ zMpzvma6uavg-Ra#5QiU+XPQILhxEC5+!4PMd z#PnW8sSd{P)5Vmev>CTgcT$paiJE_BCMXF)&ea1?PqKne$Pz%FJnaUl0Usy!pSchm zykM6?3JLIrWmd-roS;hX0aq5n{STC+Ku6_>DN8Mq1h1}O26baQ7(x3OAj@6Y1>Q}+ zs4S(x_-^_qWhqm(C!mc`zo+Y}NKIvYKmD+Zlo{jx>AzH@JQ(*+cUF}$XKEIhUZX0N z&$xa18&xTX`l+vGh&#eI5r9YXki!+cVFolL2dZ2_TSYXOK>IiZx&@&}^0GL9uDJlk zs=$9n9$v^e9(XL6iH8T|R?J8NugUqrp~M6VhUs;>Qry!ULfAN_?^BcNXKE3c?yoLo zsna3=wSX6Lcr$2c&jQd&QpXz%3cLz@0<)%9Ye>m5&YnI~L&}Nq&h$GPQYwshrZZ|vDad^g z0<9W4!K}o@%L1yMPJwn8f!3b#C~ydTm~O8rrN+2_dYYz`3*-Ljt2L$E>cJCx;AAv` z1rjxHn6nhv1-|krFe!3?+}yyDrO2be>ImBL!!CeOKLx5Dv>OGg9vp0-Ap=%N@WN%# z+6aNq;DTZSXu%B&sGOL=qA1A(YNRq2y7Eph(2^3-?PN4#x&hj1bcX|!j&5*(T<}f^ zvMJ~ehmwdH(*w|P#q0`90-e)0YDtO6z+_)=m@&NpY5l;Fr6j7rt{^DTKK-GVlni70 z^nW1g;dE(jDPu+O0n-X1pp_M@jvF|$c)+bIaEgU$%GZ{10G&^0CNe zva-9mr4(2l-+)~NVQ&DZ^#xp60w1Tl=tyaZ?&emItc&7>W@XT*0+YbU>5V#4<*+=v z29$+hDHR;p#O2vGL2%9ik1?}4K41o&;m)BaWyRP(-C0k{i1E<$GCe7M#>LZ@=}8$d z9-4j~!eiH$(qn9$Zl*7##n?JMQC~`*amVzD`ciI;-=^Qtm$GC0JYC#CN|o``bXx-{ zCB{$F6AYvb8Bb21WFV#L0^XGfS~JOd+eefn<$DK*dlwz8p=5@;7AxFCJOYR2>iRQZ9<=w=tVK0Ve@N*bi9 z%1|moe-0lk+kh@=0;PJ1ECqhhx=ZMq2AHr8XiDt(bVeg7amJa`C5@z18DCGgHd>=17`f(D>KwGEd7 z==gDoEP+PB=_1Bb3NoNJH>hG*zz&)~Uc$~)ufXaEnwtT+KEN1aSB|li9I{;pK+`-5 zoC59B=NU_RFg~09+*nGUsZnq`hl!LCjeGH`5oJN}XfuonB-nWzRTm`X)1}GR8O4HO-|? zGk%)>)m$opdlH`l1FHfnw?L!7^aKm3dd5%FA6Q5Q@lN6c&4E~er5;bWx0I4)JTN`h zQYuP+6E{dkLJ`s{1Yee>z~Cs8CC~+GJAkTuW{?675WyqxdipadN6;E?$Y>~Nw@i$!lnmqZ>6NxpvP^wK(`VR9*)l$!e$7@&LFO`-0;?lv6*nvR zruhl$LCtG@#xslp{X)})?4&?Ti7wug5@lu+I6OVTPD+aL+VpHYDHEm%Lem%8Nd+)Y zoc_s9N)5!7vX}B?oHRYfUdo+u`}8&TQXaPF_k%k@@VXRK^gduh-U5&9Tvb-b6YQXU zxP}f=;B#z2D^>j*r0Uht4<}^-wWAS-lY&p2<`;N89qwQrN3es{9i>beyQarFLLA!a zDCNL7W%@BkDLuxn>0hCuvQAQ#j8mtFJ4xB;!Fm#`j-ZVmpe>9Fte_+S>#BYLt^MZV z;8p<7OiVxQB<0L_dOEwalsV(%>GsZ2&Ww+zTe?bVFdm-1##u^(@z3;b5bxUbf6h`` zjMt`Xx=5)oo|*3FB2~rMGySBClpf=m=|5bgKr4Wt`jS8z;QF?>g7w{Zl~Q3mJDtT1 ztgqfpN{{jE^mT4h){N(-zjBkZ;J62Fl(R@pPn;nuI(>q@6#sNTcPUFqd^nmbFgrd4 zMF~o|3l411vM*?RbPqeI!a2d7r371KJk3L@jq&dEb`L2{(8h5Oa6&xqA*IdK#5etq zhm->2?&-3gQcj?Y(h@zTEEx|^pY16X!gy`^2Tv(0#@*Aky&#hLUQ)S?U#H*ol1gUm zneONNO6>&96fCqV8jU;uUVE>CCnk87!OXr=PPBv)G9Dtz)wmC zc7VDY3#i2V!3x@M%IwG}@OXNNAGp}6@RL$!oIQPkpOhv@&uKp?S;kq@U;0U%5CttJ z(_r#Y1l`*NYDMODftzMeAPS}zgh`1p&YIpH zCgsj}b^7@*DJ#Zj)49T>Jdm_Shf5hTo|@hlE@i?vYx?1EDQCu6)7c}WtQpTvcaD%! zXM8_B8$wNvkWvNhf`wc_0B&G_PP12F7m!upP~ZWb(g$7d$_ZMP!KA<;aCiFi2q{g* zP16M zF@eQ7vOvq4wns|I>qC0~5Su}x0}KkhpxJbA6ZillD93>sli;F;S)i4FI%||vAlri* z)5QfoO^=C^vXI^k&e|N{RlwjL3AFpgEbxE&`Y0(0vHy%9bD=hXcIAP6IsI;wlsi*1 z|8%uzsci54pv^0+n#>;1!88U1Hfzu|_pFW=Sh7?Yxc3+^iPtlM?r?m-1;2kolQ}|3 z#++F~fmK1qoLK?1JM#H&u#{qng-nz?E>v&f`X6LQD=H+jFbxJCti@WK4ZZ2rWh$@HV-9PbLNQYt7D|( zwNpUXvoL@{2(%!TT>zFvGC&n(4yYvxmUPG#IJf;O`1R9ApkCRds0aeD12UxQdz#~~ZSe4iWUQf@9lagS3JiR?mN`cW}`ieLy z4aS+%FUCo!gO-v)ZXAa!*8v~N%^ff0%hd5{dQ`lWqSz!31$G5q$5mHXU9D0OlvWUQ zWGWGuG<{;cl!z!uPGB;JqO1a|;|4Zx*z`mT7XGRAe&4HKkv8Q)BgPmltgDcznR zm85v|NrSi}sQK8!4q7g85?p9aVOIjJ8RGB*S)fOhB)Y2aHb6$pmGJq+XLdA z0QWZjfUAH8jx2#S)7K|S8Od&7gx(9o3%bFRQ-i62RhMBu2dH~2@OApXBq?bL1vW>6 z9LF843&cUgv+Np7433OhW=sszO_HUQ7&lB0PnJ?=+%Ua9SxQC(QiOxo4YE4E0Ua12 z@MZe?WGN}e4bx90OG(!kfSQ;WSiyr2pv`!Yo&0dMyaJM-GOL9VdTN3KWQm$A=q_$h zu3`m`UDPNtgN$ilRN`@DDgg%_v*Uk81-3t+d-cGHxdYUw23^p>3ff)=O-t+oB42m~ z>_9fmVFYUfZA(y^mL?@WeL{*9o6rnKC0g)BIFx>&| zwqtTo5C)B;L6Q<^--bW~zmgz$86LQjfM}ooK3$4a$?*xeUD&T4rvJ?Zw-j5lq#Ww!fG#tFW`G$WhjLgk ztbo!}K(qiT1AzATp=AKjQ6`8CAOH$c5l9Aro@WBBxLH7{6nf7ktd7uNTEnCSa{P>X zrYwO;;OK%LbAqHx19ZL#sD9YPl%)j96QC$&7nlqh{{$@!fvzc0U>3N^0m^tsn83vV zq_zZINXZHsIRlqYpg|pwV?l=x?g9CjU4yBCQGP8rU@XL!;A^kRC5F^TV)2- zS>TKaDdL!wK)&f=&Js8-1YO7l9?Jt&QVI+T;7dKg`%FQ~Ku(394}wh@sN>J1z${P? zS@AwELVDbZmqGBvUS7Mh`E?6=40K2_a@BHUUU( z*ubpB1=>TTzy&I_LDuLptYHQvEl@jQ3v)fBExdvmyv>{ybiD2!P)Kl_G3@|(1hnm( z)e$ro#Ok<%IZI$FIJ!?TgKGt7bc3n_N6>H|q`7ee)K<`7Is($JlLd9|1!g5CusfJQ z?f~n!0&;FWC<@OoLtT3ZQ`G~IDv+Wppt;wF(8kpRW^*P6a4K;GZEZy=YVLrGtQX8m z++gdtLDoUM{R-@DP~5%&IgQbZ;RCZmJu67y2gu8;8cZ2xOkbdKQ&<#OK^ylcfHo3C zJT?Oq5sqJ&vjh%|o8{%Y#5S!GqJQP8P_jBcM~Qx9~$xA3;&Z>Uaih2dm>Arh4$g zURHg^E9i!?>M~ql0oSlM!2X;L-#W~y&v=Iga;Xw>z60eIoh;auR){Q$P{Zm7T0{m? z2P(=zhxMHZ2bTqJP(lryIzND&2vQ48&o4l614+-|8@N8Oz?0wus9I)$_q>qnxgJb6 zDUebS>tcbo>Ak|Y1jbF% zcNa-HFwUC(r$`EPmt}mhlmg?!=?%qF`xrk>w=a<@WPCb(V~LcyDy*gN0=nAALxD|! z8M-+TJWHhnTEWr5H~nvklpJWY6DV(hI@ciKZ_~9)rA!$6rzez3$$*;2rBY5jllUOp zP&+`K_S2pkcNz z44|Xag;I z0PTfDI|!56am&l8;*RXdsz57fP!H7v4b@F=%n%S(WP;ArK?jULN0+dIP8Wa=7)_6? z2DbwqR7*)RE}s6YTFQ}e@pPLSsT!s}f$6(yr1Y8k1*X3S(Gvuw%hXDBfUblB-}APs zR*H{t*7TFLQePN1P2X211>UFfs!qy?an^L%dZ_@$*VFUrr7RimOkYtiHJNeybeje# z54&l1W*{zA1I_6xc6=7A+xn*K^himvK@QTK{;)x69^>}u4UJN6 zlD}7=ZK8+kxZeoT!6vX{`oBggGsa)j=XOZRFoSklg)~Xc5{1{Dkn-6EG=Fn^I&-s> zA!LXabV)F{Wv0L-aCo{~vy>X+k?Fb3Qre8Orq67a3bK66q-YN6A%F&ej1_nsnX*7> zi>V$e2D&0r5VTK$)$s^pmXfprq>m&fuwuGOi&Q1!-s$sNq%0U`PrnYLc5WAFm6Bp) zoHkv%O)3r&Y8un^k4ece9lbOCLYtJR0(e&%bkJkPe^5OM4jm>CEYMkM43KJ^k6S@ZL091M^w4&2^nk*VY4^(Mh8x(a|Dbm39MH%T$XpZ)K$nQz>VQWI)5(?74|Y;wSXP(RbmhD3;HENmD?#Hh0xi>3 zx~1wNNkMD+xo#;1rbDZzf9RGHQ$tJ!6P>KQd!%~I?sF-@?+gW{3-ClJxVMGZ9lX6# zT6&uV1m=M&gcFd~D61o0J*mA?OO)q>HN1c{$KV>+L6HY)B!ePux=x?eHthvqg&i!Q z-Ej(Vg{+P!5djSq-hQb`jDM#u=$D!e)whC0i4)w4!0V#42~yR*3xx;HvPgxsU|+q zMQ@OCs{=erY|}S(OW86_TRnaLBq=d%;*tnx+?{Q@VULsutoZpg36f4AV@=TWMZxI= z+ycTI9D629tuk2xj>tR*$TU6Q2v@VMQQ>hPAwcj!-%Yo3qV6= zpexIl3PIYkFag4bEuJcs!?VWz(u!m1T(k_<( zt`chck?B%>jDM#G&yZ@+L zySSqk+=>E~13C)q0;{HX&Xzjucb8p}U_`@{B;g#gXpU5nHm)E6nFDSgvvV^!K#Ohp zxl*#)tHBQJVFh>N2owkDbEVX^*MK!lAxgu}xl(e{pc~Nn6f8kEp@VXe2GbHIB{|Se zoxb(cKh2f0V_ZAkaGsPXx4i-%%>oz!09NH zqa*-2rb<3bV66~n@SVj$flq;7K@ilQT{~TEp;RK{+UXq&r7{`UPXDw}%8PN`blXKz zU5sm|pI9Un&bW5E!eS|D#&y$e7E5h602={14q1Usfg@YN(@CLYxdKPFz>wLC zK_iYJ8>cHTk+SCBAjHGK%>Y`|#ibxAaCm#}5~*-T#*N#LE|vPk$hc|yj^$G7OpKeR zKUgUx&bWU1kCjqe1U3pO@j5bQEAcC^XDhG?tlz$8mDGPm#tRy3kswON?u$KV2*3EWJetltcs-*c@eYK%1=DvK6=$*s_(_1=de@UMJ_q9hhf?6+{(8vK0grM36lq0Mf3+1~MjFVD0o<>!ltsZk@h&gH$c!+UeFC zrSup#PtV#Yr7s3HMp}`bhY@tlHRy0Z1zv%z)7Nj5y2-e0dgmr7eb6DMo1{z`H%x!O zNy<%my%4Aj5mew*0G$W7Rft5n%{ zwK8s)p1DQJmT}wkUWk~VCh#CaU^$1&;kfqSPgJc5SZ;U8WfRY4YYB1x2&5<2pBZDIolKm)FqIi@Q zSrbYiq6Hh0GnrBKAVnxj;8;VFAv6$~k;4rodQp-NBo83}M^|L@T znV{wom%u7s$G-K5gSS~hxr^2D0(X|cD)4M5_I3rNxd^XgxVTXafvydM7~V`I-+rlF$7!I&4!od& zTu|5k3PY9vx?c&nYI@EADM|C)VDC(TjCmr})PyweIUp6pIB7cnK`B)pP%{=Z%#CQo zUYs|*{vcXEXXnou;*PKjZ9uC%K|M}L_j&h0NM{&y{PeAZ;Lfn%At@;r)J`1%CxJp4 z+|C9kDNs9`O+idx_4NEhQcjEyrf)hVrH|}Vc2IL$Y&!E{DFwS-t58pu1Fg*jopSmU zx=s#sSsVDEEtG3D;C=bT!w~0#I=KyprOZ5jF@b_(L7fsiXs(wGT2fI3R-+)fONp3s$Cpx()(qf(%=;2IjG zw7{KwhZ~>}vV#urfV*mtkq=P+15ckHyt;Qoy%N{-!Ui^}=}V7Er5fC2S48cx5^&{o ztK(8C7U*q!c#%O!_q5|uv3X}6Ocxh80y{1m?0&)q@Iyu=zztmR($*EA!(tHk^|6A^ z?Qul90Fc#j4jX8H$n?Y$QZh_S{!OnxAth}Fzo2gcsHTM9=GOt@LHCw`Zu6VMroali zzHbdke9ph^7fwjEG8!J^QxE{%f(pvxgk22kiM5@QlCuYwW}w+94$$&(upvw!-w>1Z zK)3ciJ|(46zeNDl8V1kNLl;gnD2RcEzYCzVPXeH$5n#hckn#vJ^&>2Bl}||sHYo~q z2P5dZKoUHY4BlD7pa4F94m8W*2wGOa)(RcX18#Frw_G`} zpsSA8Pk(=2Dh0HQEcAj@8snzvdoF<2Ek3*;CB^t@`kxC@;M2;@FG?9O&YGTaQA&{w zbUmFw^Ys3UQo&^SPWY0Pz8Ay@Zcw^TEKW_wd}YB>jLQiut_$~o3>#|CcD z+AmIlL*NK%;0Dh|QydV}Utg0_Wjr}u@Vbr$d_9?;-1^OKX`*jXCbs~Lw)eR}V)W-q}yb3G|TmpwcLj(%KkPBl#7p^g83G8N3 zf?SmZU1Ty>;Ucz9;}U3@&U;fTgz?byq?=OCj4jib-IU5>oH1SWmXsRf%;`3_ zr0VSjUq?*4K+O9-iKR7ra<~)mmGYei2FD`SKOM%%J zJZrlEyjEZj*i|f9pwr=|v)q?5k^@VLa!9sz?3D>H9g=y#2FR$rED0d zOy7DRymtNxRFvm|6zG6drw3AjjB`LMpv9-JejvreIBWWj2U1EB@YV+_c;yJI;~YlN zY}n=LpB_l*i2eaB?^?qQTHdq-bP~7%n?S$NbmNCoW{i)gXFZgXW}G#>?IC#bb@f9j z1I9vOBJfNNaNHyCj`<0Xz}nY5l9Fe9H2usYxV{g}N}&0B zMzB5(f!Wi!9!t3+#Vy*p|LIwer2-irPv7$xyr};vi25^~?}?NKd2BMFm1a3Qz>gu66tv=70kGO`h%xZE+%W1A$4BB zP1_FG8IjNlR>*jG2PczW=2@ScMj5Or<( z(&ym40~el4sW48T{`EQ7VFfRw^cbg4pZ`LtmT}W`*_TqbOua(WV_r&C>w>Zo=%8uv zs#p;vcBCA`Y{sMjy7~l!A=B~GSzbvg^1osSpDh5|@XRLA!8hIHm6U>R7dRDyHuOVM zCS(f*L=@Z{2kmApS)t1( zrgOZOQWQr@RG=eHnH)bdfX{?*crB&GID7i~26?gRm9M4vRlye+v1&30K$k?Iolno| z$OyX0a_ws=(AgAcUrXKN*>QimxFQD+Be&yH6c#S@IQP>|wfpyatzLOGT{4jmTJ1Kp}>(gJn zlR6CAlk#3lg0W`$(f3m7jGLyveJ>@;xOzJG2dVW^;034#pc6(}L3_Sg5$jK8hWlT*P03j-OXX?z@7@q#e^6K0_8Bf<_(Yeg-c%Q28RI$#{0U-xsOpnvhKw0g9kY z=|C~VsK5!T57;!AA{0SqKtEsr)&A@Pucya-m6A}0okX3X#AC*k1Gg46f@kdk5CKK<4YDJ2m1AA~FYQ!0UR`}CTh zQXaOQvu7fPY{07`*wFSevpCKGso{o(F4&!Hpj}S_JEk-KLWHl}FR6CW3V0T9rw}nK zIeo`3sWYJcEvy<$0pK(X32JtMP19%omQn-x<=}6r8pci2?fyu43V=@h0Chn@v(F-+ zWh~SGNP!OAKKe&0ld*TY{$D8-Zt$g@tQt%)0&Azo{gqPU1#1Ge%RnofruY7pl4WbS z1{x3m?H!V5JTU#jU#U%?!}nYMNrf?8Xy1P4A801!#MC>|3c@X*4fCv!h6d>123CQV z>HLh+*7dzCpsvCiR&ev4QGwfuz z#3ukg-yWRpH?Rt<Hmxer}r^S&t$wZU4unhhacg6&>6@r)00`G zEg1JtpTi<8fgyL8McM*Gkc(AX(HzYbCI!$5EugdvzAgk?&_QfVVwIl3_RKq?tF5Sv4Z1#|%%=>EvZ)BV|{#ToZcPiL1_ z(S#jk;K-oJ0-CbQQs5A15pt||z$tx}@$U3_ zT+-5v&!_L=l9twb1ipPlMv0x5oreq5!~!2tEC9I~0dy;qqYY?HoVmdK>HoQ;r5KM+ zm*SSzWIR9JgY=?qQ{P{qR~u$^^!{zOsH>AU!)CG2fLHn3_i zfzE6KEyQKlXLL~l?Sg?W#s*b38cd+`a@lnm9C#VI6~K1~vV%gGL*UAEK>=w=Asa9x+B9{WYE<+mVuv7(}wF;bTofO(y%$YM3AonaVDu9mP zeWAyYCGbrMWPJ(RVrF(n(CO_gjy74KO+U<_vydAYr#}F>xk3SSfb9?PaWWB&pZ-EfTE?)28Ja>lG?-f0K%)YnHY(_#ZO0a7&|*vufh&;vlNmsBeggNV zn+i+2F?BFc=YK9OJ$;6-G>;4D<}+qT0oZN`c1O_dXUvXB4q*m6WCbX|Z!m*4N1S31 z08O5N?9pfZz^ueJeTt%-Sv_b)gX1^QF+yt4iWSt-Q($-O0G(F=UjfGIcon2Z5vm4U z`La8LZ$tx)%Y&DZu!GigD}Y7e#|?o`i2uV3+PVYE#R^Q029C^*3<~@jOgw@N3_J>; zM5n>@gBf&ivIf%^W>E5Xst28Q%cQ`r$-H9vUJ+?k{SC}nn#>GfQAY{T;om!$5q<|P z@kdEBGo}lQN{jhV0L@sjJ5FHEQebg}rkN$o(hA_@0$sBNzA+E7Lrfq|QAmLu)G^={ zm?;Q8*P2~}Nkx$dl*kkm`KLSPbD3^mEh;U@2+D{YkfK2eb}lxf0)qkvsNUrQ&ECsb4y5T#DOl123fWOJWk2( z2s$;CSAhw1Z7jPZ=d5 zuEDft`b7z8HO3v&e@I9xCW6XD(D~mQp#4i+P_OWTTTGy1q!a`}tq=wU@cMjiZUugD z$pUIGfR25_t&S0NG!N*A{HfEcB&FjR_e{SjDXqx3WBPANX#<@vphgR?8Pf+44LXeo zd_^J1>^DqV0{bDyH9LZR!9D$mK*02TN1*g(M~1G=z4gGoXW z6utskpbJES%n}tanBFce%~y}KOd3ZP25o-9l7%;b1}_*u9$o{@swra6P&-3`M}bwqgojZATt|VjJLps<4N!#z%JWJb(?9Y_icNQt zkxu3VEh^&y)s5g{eEMb?=_~w@%9saqj)efI&i$w_B0PPith5!=4d&?^n&d?oS*HJz zm39D)6N-);!%2!Ka(c$N!%*xoEB9nQ$qBsBewymSlW{OO4b z(su07sk`Zk-{r)o?^TdC4S`Rn-C$H;aeTm-uN`Kn5yKZ*NqV&ShlWKK;Flv}5op(B)pRL!-c*F?NBE zkSh&AJjZfW4tqczm~LyX1qKkyKnZfMfi&odvjaxb;NvFv4W+vn?@pg(C|!rm_5IvSy>X(x-t@S81#71$h+3;+eY0yq^hnlW8r zQebnu!IY)I2EJXGU0~w$B_`5ojB}@Rn@T$|^$Sn;HoV;`SQ<`VcY{j<4ruHbxl;DUM! zf&vSs7g|V5h%SH&gL*G)j(?c51m;hlXCbY?xM2Ez3u!6F`O|M%NGmb!p8nTDS{8>f zT3C%i7!Arc9W0=$MHWoYwUl-fUnUF^0v#>G=6HYw6qid_vji4SKV>Pc%728>jh9h@ z+3_NSJ1?)}#OePmrKNaK z&4TF{tfVEF9xRyt%1YW!V!1H5gcWEwNzJVCn!}QR!eUtuMPmSdkTUm=H*U zNnj<2#|}Aqk4a$F^d4(zCC1g$*IP^L%dY{+vB2ckf_TiJvkV|Q=THA@Ev;+^KAcd< z@!I_vpsS~rOK@w054cnS#Q=*Vv*UqBGsGP?+?*lqxB$drc02;2svNllR!DGHO*hyt zEza0Jz05{hj_Jvo>C=_*y1>Q{8wv*P-YG+hnaQx1| zRIk9I%U}b!oeJDlQ372%$|x`a)Tv-rU=sK{z1B`Tf^o+5Yj)DcjK8*X*-OhaGR~N; zs03HQyfeuC`Aq8Hf z+rGi^p}-<=N*L64VdPfe0##_B+vna)cXpIEVB9~w#8Fy{^ULZP;);BrCdG0`X?e!a z(~mn!gRZ20=O}F_KkHqGxa0HfUE&J7(q>E<;B*5T%j5!|&v<&ex0AFEy9r5d|)N#uF7WvAgXt_T z(q@e9)2&^krNkyMg7#G^K=1Pcl}`$+0*j_+yGSQ9P2it?!9}_QL`S(w&((Piy3dUR zw0NEiR84b$M#DHj!%7kg9H9N(GN6HXP&(JN6^jJpb09_Ch+~!H+V|hF@Bu>-cvf14|D^dBk06U zP6ZBuL(_x2qzf4@PCw!$?az2-x`?-QEaSfEMc&dr+#5JR6%=T@&AI6(y`|?dKAWE5 zBW=pmz(0Myk8}fL&vXS}XvqycuoMj9 zYdc8S+QYM&f#cDyGsFcZAmt__#~lwK87vug-Kape5|avp0;3~?2l!6W=^_Erw(6g` z92tv2gKD7s%e{@6i5W6R=#ZtvqQc+^Y6UB@GC537Op#WV0r9{+1a_nz0z?hdbZcd4 zWl&$@UVyZU@grtX?i2vU2Iw4O(4+y!awYJ|dOS+30{3{KV{yEUOb!YRjy72WQ>U8- zN(VB&ncf~Kt;*CaJbhiDw5vdqFys((P_keZXc3;y93<__-*S1nxCRpg=u8U+$3K^* z#|KG^GPX}Ycuv4@`UeR{mg)5t!feww1W6k*PMH2ENO~$`*Yt{D={Ux3)2|0ho7PW2 z*57d%+NogR5#&~2aOB8xoP#Vs1tBj0m0y7@zW^c650&47EWZXJ&&RF6;KX1)y*os@ zfERo_9*ctls6Jjaog-A*8(j|;N)2+g#K_~Hbhf8aL z)NBuz_U7neR$$g=T){H^?lf+t={gb8<{+um2qzNHsL&2Jh)`aXbTU^Lw*s>!^9eR3?&%M=2@6ku7bUIF z*fU)&S~>w_QbV+~fxw(L=s816*cF%^m$Xek5G^gk*fafZv~(k5&-C~h=@5|GtufLD zCUCV^IKXP5L-Th)ya}A35!y2xAo2o7mH@x8tTG7oYUoIi^)&l z6)U|$7UKdzDFtu`f<=K@VBYllIB99dFVknoNiSyHKHWZE+RbbK`5EGl0?_6yxNE}( z8kt3`A!c^G`FEzcBM+()@G;j5~W)~6KIf02~fXT zfk^?>1el#5JqPLp<{f`$PH#+<7BNP)bU(;aDO5`}K-Wc5VCj@3X%EI@)9)rpE6D8u zHEkWTl{mpC=xyRqU~>eG2y=qlzMH2@Crg7?3V0<;t1|AHUI60lnLa;RTA%Uq^z+Hm z35=hn8>C39aDwu_A{(eKi%pT%FBPGxlufOOuXcWc)Qf zH(lC_@$mE&>C$(T-tZ~0I6h?n?Tu#8VCrC01hsrXM_<1N9e@Bj*kq?DXmTHXNV&iP z(79@^pfge7ioqwEYcewkoMBP`T?C*68vkMh&2m7r?415QLwYjfjp@~y(x&x)Hh>c= zs7uZ5D4p%d>I)j30e3}t1debk@qot=6qvnvnH`bTa)4AQaVc;LTn7(KvpB$H9ZxWV zFNFmUSWAP<ldL$nrb_$nq;XrUzt$Q?zU@B1K!}O1CoJoz9gb z4O(grvM7>}McY9ZsUTa#i(=7jkh~yN9z13N_Orl_=~yg2kSpB?^`Y7ukj68x%kDwL zDGD5*$`p}BK>M_(ug{YfQ{4d?TL+JTaDdk*fUSTJsW5`Vb`9h7^~a=TrnBWsr-Cvq ze1HR7%M09{UY9Q&pa*KpfZ8t#pyMf26hJqhLJl@#1FeYVaJ0x$-~c5h4o873foIeI z3|@X4 z1GNdV!h%JhZ~Cl4X=SBOM$jeiIiQId@FiW4zyd8o2OUJCz$UP1`u##_S;ke<{}xJ1 zfbMu<5jZ(rx=31G_QUp>kUL&LH(;e@Vb+AM_o^kth#ZqY-vDep-PP_$;!8s~` z#$zUyNsECtc(V%ZnBHG1-3d`{X%7wyR>#KcsOvOX6L0FsAgU~s-bxChx> z`RV(AN^ndME0+#d26c9r1pcGU;cty@6>vj36{s5j4;U3K%7L3|+03R%3iT{ZF-Yw(@;0=$?Pj8ao9Rq@VzIQbB29x?r`m-1Mwp z5{9gtj*0@?r{AlQwlkV{Xr{O$Y?6*Rd;Myq8%(fR2wkcGwUCk9krA|$mjyHrtiqtc z#{FvgYhzJqrU%{A;JrgM_G8Iy(r3#hBZEU-!he1iqJ zW5+5`H~m(fv?=4k=>qlAUW`4{bG}QcaqxgU+X8E*ch*bWGQOUEyk1&~@%8jq_0k56 zucu2lNKayXJ$+q+v6aU%0~nW1S80@9!T5Um*+%J3iPa*YX`n5P;5iA&xayrot8ALE+o zo7_FE|1pL^HcfTAlIW^ut}!N3B3hA~nG0_d;&v1l{Ta z5d$qR1D}Pc#0EMc5!6Ot1ofevZ~tt~s$Ev?UZZThEf=_`zjrXTN-j$}MCU9nf% zjq&XCj9zI&#FTu@H zR?wUYQuzRGa_;Ms7Lx;4ZO~Eo3E+jv57>|vjehEr?gCY3@TwnF5Q5sE{r%FCpj&kM zr41P0OuyAHZNhkdI{yS|J;wIwb`zw__XeApyuJ;tZgTS3%?>02gA z>%(MTPLkGun#2flH~8SP4i*%5>rX~FGC!2TJ=5>Zl8$5SnO-_W+JJG>^kp-sW&0&`+oc&Vf$Wr@K5dq?E5c&y+0xob zAqrWH{e}r8?pkIe;%>)mc(^ejha1}*X*-g`t%mX1^tW@sK_)R*T8Z)UbnCgWATwmV zJpJ-q=^W4^)_LGCnmY%df zGrnM*UTCBsF+F{ObdQ-=iu}m3#H{5 z4^O|bP+E>raQgR!(mjmZr~g|l?IPZC1pPQp$g0@;iy(y?sMGm=sdO9T-RaGXrK@1t zHi5Lkrollqp(9Rhf0syC!nEB7Y14<6Lin|nEdw{B-Y%1NvF!sDUS=5DKy@}~eYFBB zcm)P4$PG#yph-;*fgRvIr*D{)I3RmYJC;i)Gv1y4X1R1Zr#ZKITT>0nE z%f!P9TF1tsASbYU`nr|U``O;CogpqTXL|7}=?KQC>1S3+moN%VcU&GesZdfsYj z1;$O&`&Ucb@q!P;0WYu?5r~?8YqhjGqtJAwHPU9F#fji^zd^_1X)vu|RALhVE%F36 z*1)H{Z2+Ah7rRDUf)_ku3fl2$09wr2v_@K+_s@zM;-CRhN3hVYHPZUhpk>t>Oah?u z+CfWIKE`RC{TT(Px381dVmvr~(>m#5MxpI$>!mXo zr`xWVR+eH?0G(FLq#&Un_=k&u0km8|Fbj0DB*XN*8>BU4g}~2gvt65O}QAJEYGsGVb1PxJ&v0h!)x-eI7K~{%EhXM-Y|s^J0u!en+Akf$_G9A=aekdeR zmW8i7AiavQeR||UX)WCept-9lj9H+K7|f2KHFZo1i~tX4MjCZGB zKP;`t_=Tvw=vj|+Ei5d$fUNfc$1uoF+hyoXA<;1z^f=8uw7{Qdt^q`~C z3Ig5Fo5U3b93QlU=Ura3Pj5OZ4caiU=BRWQ8f-QWoc6$DCX$cE( zTLLt+>)6l%K32nuA%TYpw3wJjK?J&Kkr%W%n+rS?#|2*9z$5T;`u^k6qFN|=z%x_) z0$W7Pm>L)rxEx!+=VU{sY5J!BJ1(uEh{HAoF2^3mECn8c6Vu&KNQW^k=$JnLgtUsr zL(nt{FM|RXC>1FQDDVitMEDhW1a@;PN+^H?cTazPLOPmp;&k_u(sGOwr>C6+mlFy1 zq&247ACs2W0d?vfxBQ_@N5!N>y^dv-v61?6HiHt^P!E_)LjD?BKo(a zMLFPsyX%y6m+E~k#F86Op5YKc6=70f7Pvb-^R#pn=lwcEwDVS;m5yheJ)QF$*m*|hq{E>x&kl-t z9`JPI%yZICatl~MHy!jafg+3vl$9O%6j>ejfs!((DyTC5uqV#gc_tP#(Ylw9VLgNm+9~8X88Pw~u zyCf~oxP5xuC21F?t&P(SKS+x(?wD@>5Mmza(n{0o9!d){{+iBnSy~Qsor%t6 z={bydr=Pqmt;YC!`iINX_Ke@A8(fjrVf;Nk_KNg=#>>-XuS#D4jUgmnl2)BAa!p#n z>uTFfaYrG9mzY7bnk-oY(;-VR!FAXVkhj%Q)l5KBv-{n0lZ~=nuG0>VB_ZtvDrQZPiiRC6ZKTWtP?dEi|b0*?~L-5!iH`2H% ztKptgYJ`B3B$F4ey!4PF=o8i?|_1)h0GxF_vm(%giU4-oDI)r84~>NJ^tx@_obz{|AS`L!HdJWrtkY8Ek0fEl{D}42e+m38ShRHxFZcZ zM-%LqNnJA$BWqx{qWa}H$S<0t`laWtv=R3ae#k^SkHC@XC+|v6gJgFXla(OP!6K6k z&w)~!)_riS9KSC;o$=!I_y^K0uqeI&G9Bq$d~hHM;7z*{EWDsJzwV**94W}Ucvfx& zE(KmQrVT6#T#g%9K*jR==_!w-4H@50pY}*vjd9QPy^o|*AqU`a=`&8?R^pu=_)^*g zG-1vTnmb2n%zzg_f7mp=?y@Oy$&Fr8J7iLFH8*lhhEtpG|xHH>$sCp?pGk$eGa*Uu1C;B}NQbS+fi zQ{Z)k2u=U{Ou7u7!*gCrOX3NWp3T$GKL=MU;5-Wpgz3yLr283XPM`cjT3cuyrtdGj zkd|beIsMfOX$>PxX$8by6fVafT*#}I*&Gc7z@-`_bePUHPhY?)11j1`3=h6n(sNWH zX@!kjflq-O>U+>`GteX&Qh1zyC7lnNQG6}!WU^{AQX!9s4N!`}-GJHpTDo6srXZ+Q z#iPg$qBs;eKKq{PA6u1?5 zF;qc|D98{N)MSboO6M$WMzk3(9WgFyZ|&%!NbZ8?gw)@&S3?aad*1> zS7{Z-_USHPrFDh(fTl7bJGP?yvY@)haYF0#_1~pMRS|2L zSsfR*&JuTIgVsPOsRY~7B0|=>z~u-{Fau0jiK!NEv?D;b^4Rv z(h8s(MA`mG8#B(EZuLi6m2uwmgg?@?jL)Xu`y;Ky_;@2j4}p{^QXUMlu?8jAR(}6x)>AK0DC4GO^BeRz^3U1Ofm|LGpA2v zk^x;~w}J_*{W23+I}5Xng7j-%1tCz>%-{me4|6%r0bQP;z^(ua4tr)9b*6s)>5AW^ z#irLW%Yd#9oWm@m&p2!P8D<$xAyDU7gXsz<6KHQ4I1f!{XOU4+UBDtRpG9B+Kd35w zzzJGU0dI$avN1Tj&7U5?B4f$8etH*+j4k8N=_goZK%H(bRvCT9$J4D?Wk3yYP%Dt> zQ3JSkf)v8I+kN}lWRR+FR#5c~y0@GS)YS(aIP#xyx(b_&5+q-`m`nn-ft8{83AGNQ z$PPhvnYoO2r>|$1F=jkE{V}_Y8sp*VTpThQlAyU6&?FgXegkD9e7ZM>j1}Y5>1`Y` z4xFGPh(W_4ozu^A$S87vQ-ZX>iRnK$WVBdTatJg|SL2j%V{D(E%PFJHcyannP8oN` zx6>bT%4Dd6PZLyhe6VdMsChqGf;$qtj81_O+@}WjY8;sac26(hlJR4FKYc%!Ol19) zbFJcvOgv)TjvxLsgIJ>6jvR{2jz5-yc_Q47%!Di59t z2My5)oKe!7e&D`B5aZqHFL`C`q}v%mtA%YG`Q3OKxgBAP06@EUeoS}blQCs%pI*Ty zBPaDkNQuF*-c5nQQPr&oJaFict-z?jAkaR21D}j8WBc@bd@@QbKZFF@r?c?OSc2xq z_+?BaUI~DP`(hj!+!euX7X}4ph~ZuQGRlnY)7SCK$TPm0evV(pg0X!%yMT-?XeT%u zXyFqmjWUB)NHVUOeqB%obl0z_kcIM()f_)@# zceEd^^82zWkqG=ltIDm2wA$zCGdw=fgKd~FTh*i-$2%9J)RyX zDx=RdyK8#CsEiuZ%&zI%MP+mt7f(N^A)_DyZEHccygL43%yMi7D-@fqCnh7n)YvuM zK}^Piaq;v@F&SURYtxU5$%Hdrn=UUdBh9#Jy0y5BE>n-d^ek~1d8TfG>D}Toa*Ug% zuM(FjVB9cWT0+Jebfuz%OatTB={F=~<}iMpUMeXQ$oOUYaY>mv#>La!q-4q%uT9@8 zCF95YV$BS3MM1}UMGnU&Yo<#`%g9SXT?g7&%mUi_%L5|*FoBlY21?7guz`+|5jZ=2 zwzLd*&F%qdnKs6r>FzQzK8%~D7wXGMGESYoPDaKbrtpD2M4^VP3}~_PN?DnD#zWIJ zv=vGn3(F+`s*mnaoT^rW1Fjw_3ayA7n8ug=?RuHI~ku$&$X6Onr>qy(+Ok0u##zku>UbWnLgKE zMs9nTjZ8Tsl|fT z84pi4agxat0-u^=06Gzc4YVzsUEt01^-eNY;-Isu!1G?7)|@|J%mUd1J`f0WMe}rB!E}YujOhkwpYILEEN+1;hY+=eWt7XKb2o<1Q1)*gSojyNshy10!Nag9WtexOw_ZcbNd8Mn>q$b?}-&jx2%Z z>E0ePvlv^ZKl6|YWo(^p<0+%b+sp{s9ru6{wD#lj^de80c*Zl+FL}ybk~z$zz@f|F z;>ruUBNgNm4o8J71r7}+2Z7zw4|vHOV(Q|X-r_A|3|cR^(_02~kH&j{nNY@_>DE3n znhKEhf-{&DSQJ7QUG1-CXl7TC{Q=OKR`x)`Vt=*W1THs;5F=!4Kr(? zjVLAt&}1^B29pf8B52!I1Ly$DCljYL`^soCcRZOmUEfzmjSsO^fz$E+_vy*LGU+03 zctLBI7cheFxdgAT7T7WUp0A8r{0qp5?4T|qR2;Nhk0Z&Oke0Hqr$jj`Y}HlUB>Ctzxc^$2JawX zHRuj?&?0?YmO9^- znF~RMAV?jL5|_Z^=}UrS+?dXEPCpPVBd7Qhw6%Z@+P8=7YC)RYWprFNT{~DtjsL`t z4slHe26F}m1qR21Kc*)H%cwAJncf;KV+k{g>CD~f4}xVxRS{<*FgiBfn<4JVfnvM{ z6N|t{#_0|_Smd!8D?2?kL?#Zr8%2R#poMSxnGhKx#+lRqhsem8&gXYzP-FzHP~cHw z;AI3QZwALDtuw^+85uywzk!N%21Q0N1?mJjGJuYT3<{MAV4N|1aj1+U+k&nc;sWQU zp9+;Ru>~JE{fP^7iX3Q3K4{G;6ZlA3&;fTMW=t}U>lhV5TP`^Tpof=%Zt0W(E%k2^ znrd1%ml{m)Ab`{Aexx&bx(g7B_jeEae`V5 z+6)NRti%Rda|6;R94%uc^9y_{Lx~a_sPtd~T|)#KZ~`qM{?9l)Fg)j=w?sf*>P5itM1nh6FBw2F1Yv0xEK0+O|&jjggTO zz041b4$w`bj0)@uOadpT*Tl#yU_3KjHdZE1~&XHBLsM{s5>_230U0rpx%8|j5Mc_O? z;)Yu`#~+{y)=?l!i9rB#oFB+A5DS#p*&IQuaM>K+a4=>;?47vVacY1MLdt5NMe$6)$s9<{%%)wR@Pst587>g;>R^z#z~vojpOunDOy+>jW7& zh0W{=;4v7`QEf_~KmpxREAWb4fq`3rQQ!*y^!>KdVw|du|Mr9Ts7{}eAfqq(m`RBn zbQUL%qnMi#uPbQIQ{eIRI|(x8Tpf%`d|-aZblF51(D9dbi88k0v!)Qa1u1)qrmPcfqZW$ljD|`(+?!ch_EN;XfltGqVB{Xd3Hzij0{#WU(=uJ1+xxnG6r8s_Ec!WG-}M%;sZe zU}S)r!{pfbtx4SR!v1D)M+t$~(?e2a5+rx=gT_ik6j?x&0O+V{N6=z)fnC$jrpn}j zE+0*kab~*LIlVDWMkEV;L~je)U9?Q-D^5VM1RD3lhyVlVy|mz^rLZIR46@)6F#Ug; z3~0knL%K|u7Q~0(<u1Q= zFjm_)zdF$$kem+Fe`9Qm&=!tnO>AB16nh`FjFQ9JZQlL@;H+t z=yso()48)`EEqRUcgd15=exx(r2y`pKn52(vt$fR9y3Wn1DJ`K33OPKBTts&l=U;j z6&M9pi7GOKssknkRx_p$1+b9{i~@(Jzs-`75=jJ&Zh}W2nL$wsGIP^(>1-L$!2tf* zGV*L~U9-dmmP{|nmWcqZx@UJ(0bNDR4%#lyA@F4Sy=)m%h`0bmoC9=+-{2Dm23Ot(Lm;)YzoSP$~B?=ko@loOc9WM#m z1M0{rFnju)92pJM6{4VVQa%OHF?%Wu-0I-{DbSNCj2+K(%@TKHhg?Q1>9`rhyU8H1 zYPw~vj3;t@K@VeK0i6uQ1#0&|;)@Hk*^Wox@bopgG6rm*4X6Sur$5RC$C_duIM#yl zWIPyGPM@78Q_t8lT{>T;N%%Raya$g!fkFe+{<%DTL%xit%w;anq>6$kcp_CLO98a* zPy}>=9kamd=@0W|v>1O(=P8g;W_&u`pg_i+amDlk2(_U=Mp_std2vD0(e!%-GG>g| zri&KJ#4%o*UQ#Hd!?GSMPE%pe#3VN&AcWmaGYg|xt|>Gz9eWI$VQcKh84t#T)7#5r0vL}>57buGm{u;MRo?*`p@keo2uc@@ z4aoc-9W%ti4I9u-@DDH!11K+mn!JuHkQEDLIW9ov&wz12nkT?G;08Nb^9hhp3X;_a zKmsuS4j2cddjpIEuDHOuU%-XH>DloCGXDmQ1JZneiM>9Z?jG&rCM z#C>|;TN&}`k1AxWKxa@?%Ctj*MrXR;6lFH4v)l@-j^HcC1vX+NnG@2xgcZ3#>)yE?nM$%it7ozmSQWUll~@F}ZWrv55nyE8 zI$fz-W+LP6>07#GRx<9K9@it|%(#2{q8^zN#y!);du6m4_fB{2l~HBfIz1D_+dX}1 zuS_=Mw&{$0GOo&7g+T=`s5K<4z%H;`7-Sg-sDK2WJ<5`;z#_1FdS;(YHRHDFPy1vn z823z<>zC1F+`HYQUxu5PsZ)4*=p30u#>dkO7t1Iy9-eNnN=AjLQD}PNQW;IgKhqml z$tW^jn=UwCMhzrdxJIU$v1fYVG8sczS$G-h$Ox$w4IF!S&lGnw5tuA7y>S_M{s-CA z2CSww2u(+rnv3cX#{bh3mda?Mx`Xlm^nx`qH4tZ@Yxsvv!#_M4{$kVc7mtQN*fjjX zqv1C;4Zrbd_=QcwFFYE4V$<*wkA@%EH2lD$;X5`B-|=YphE2maBn^hsb2iA>K%!fL z4SdKlB=IqR1!)zX&bd)WLirCbxZljI$ixg&*^J7$=EV}o&I{0Oc~?j z=_gJoLGzI^s7bs`6qJ>ur|X?m;$!?X-S(ssG(V|=4t-rF3M%3ZraQiuF`dr8Oh$G3 zi<3$+kfd!m{lXR*1wqhc6_W#~&;*?c#Vqi6I^$LuNwx(nN+7nvRvB}qg`(4SA4^G1 zFWxF6#lJw*nh|vMm!kq`V9$5@oUJlS5(-QKEcK2ItO`t(%N^^B9qkJpL8FU}(=Tk5 zaTnMrq`>T`1_~OEECnWk%hT1j$%HV@onEs|=9COrQU@d{0G0%g^5`hCC@=`jnVz&= zrk8Q&^bgx*Y#A?4*V`eZ&p2m#+zy%9Vy}5YD@H(vDk*@+J3-A{fydMNcgn~!E}5>s zQ$`td??=c^86(i@laKl$%F|cxl<{MHJpI>B89Ct&MkOulecV=KUpz_G{C-_RDB6b?{B!vR_68MBmyk zBV%#yS(CWqT~I%cTi~?_=y(dy0wPcj1D_biBXE@qWDV%(dho(DE>LrsN8svoy#q3! z4Pv_v$avJB`-ZvQLj$=t%>rrNvm*inwBXqwONk9>*bsD9$5gc59hc(?*sVC=?j4uo z6IRd?u@kIWh_gGUHy)Jf0PPOp0H+l2cqHh!nEPDN6Q#i-;B^Dj^$y9%OJ3ztUa}z#9g|6hs;XHt~Vl;d7X# z*C(k;Oh0;9Mw#*U^p}TaOa(z9?f8NTbj~>!XdLVQbp0bTI*eDR#~hJSW_&Zf;fRbJ zyqISQJ9Fg$^?M77;lM>}o03}~8(BUI11*U^UK#dYM1uoF|#>(jdM`dIo zi`Q5L)=w`zDx(JBu?no8zW6A3ecPF%u=Q;s0-L7)Ju0ICnkMAZXM8Zdai+55bk}1t zdl(l@XF4w9z<74L^Kls?#~IS#n11Gjj1=SH>CaEd zI5S?Gu6K{d+v$}jWvUo^rhfqmzMU?AO2!?J36oEOO}KtaMvLbfHz@q? zuqbix3QSKtDI?DKZo2Aeuwe^M%V;sa0~sbd{lRG&BV80Xf%=G`!GZ&zqGo&9wltpsyK~(c83)Gq)8C%~8=ZAl#t70keLwx;B^lA_+t11v;c>Cp zIj~t#=TKeD199<(=_}5Gja5D`qs90E;^O4wUwN*u1d z+&nDP4bRKSFn)%3WzrSg!NYiX`o}A9XI}xO4VLMG7r@R=xGJN>_+@(YRdC?^yDFo_ z_yuC3-8C5#5|haMYj9h@fx`?79KP!^4vb%?`(Fp!a_TxPT)u+BMRdFP4H+NC`dhFu z3rHEm4qdp-%&i~*8XM;V4HC@(rOr9vog`4@pus@U1ThCxIe5b%zbh|;0*?XS@8AW9W0<5UzoTRxC9`YSOqpse{)ktQeqRo0t0B3_5`pBM#u_r zCV`pLWpBwCGR~Ure@jM;X)Yi5ILYZXw`BMjXHDmDB&-mC<23$37jr_ut{3j3DF2=|T5otQj{= z@4F{c!+2ym_k9@yx3k=epb2ZxEgXyjXSo$Y+w4F)FTotp$-9s_QGsdVyA>cubAXtO z6duZ+|S~Yk!nmflZUSLXj6l6)1wHNI*wR!NLI|ouSANl1@+r&9#7LXJ8?7bh_{p z8Fj|%)2*M#^fUHMKmA0;jQ#M(8R7yxfe20 zj2EWM{*jSpW)iqCo&BYZ7UPcTMlWT27>`b`e~C1}!l%Fs>Ucm0SayO2Sd6DXdnscM z8D&Z5125A9EoET`U0ybQ@+%oV_8w-?EK369B#8&FWR#ft1g5jRmeFQ>KHcE8j2PpM z>F%#(bQyn4FMTazz%)T%`tsK@6^wbQ!Nr=Y21u%eZ&C^?UGm@b33AganN^J2r(gUc<7C~qeWti0 zQqPDHveX#b#R4^O9cO@)z%Imq6p@flSNtwz@EU1GfgRJUcPUSu{{O2CXg3$U^sV0k zI&2cP^aU-;M3~OtxEAC%q}~hzxPOk+d}nYx1X2P!CllfTTxB$PHr_^w0kl<2gK2uK zmLexgiM{bVcwqF+cNt?D@S=MO$0b{5iaW{(OqAfRW@M@dFPi^yYP$6g8BLSzzrf4L zS-BlwTm!RMxE<#})}%9YJGRULuVH86c0Bb1yaJw)+i~%q=`()Fcr&hplmY9ZWq{>R znMkH1+|wKM#nh+o{wc#F1S+^eBd>_@*zGre%KTuQe!WtLcly2GGUC(!f>=y{VA)?5 zGSUjo#)cZl6AzQPzL|Sx#7y5jy1t?uD~BPGQP|T!N)tM&pPhZU>tH^k4`dKDf zQ^xJnnVDrBBtEwxZD)4nWr8?LV8`@mW?5~}lq+bTAIKPRuOBoe$_iQo2VRQhkgdQh zaGTSSxzLdb5^|uT9@LGTFkPKRHjMGZ^g0$B?Q>1nZDzJi1dkFz8OYs1mH^&BI1qgu6wP*Y| zJ%>wHi}B?2>0Gi#>WQEUIv!9x0a^CQ91adg^2QJx8#xK*WxMkHD z=S^S4Et}8uf_=K8qKe3LbspIa#+TD4@W^U2c1_>I16J{bN7jaM-gHG?**wO_(P~i$Qm&oneH7SuQUCCfGn%bS#E1a2XGDtEn#^88^0kkCpG^4-(>PHK}&rA6xBx}mlAUs`HShidf z<}WVD9ZD<$s{|Yw3tfxA?FCRmWC!gpVHKD<{j9L8xFlqACwQxb0%)~Ac-_B1mcZxf ze}!c=8COkL7m)=WsJcf?*28B1hMD4ye9%@lC^aasgU);w{U}&HGpmo zP~Z@FJY85qR!tG)z7z#^@FX1U!oDXApoIZ5MM0OTWlaD0P(plqp@ggVMyu>Zc z0uIc1Qi#CZEhXE{ICHzZw5$W8)I9LiDvu%;Xoi(Tkw<|Av|eumqd?L0g)*|BYW2Wkry0sRCK+*z$b_+F8~-3S5q;i!qoT(eJ}zRsgL8MN$P0Z5Ge~2&9IG zOeTXv3oHs-JjS?V`Vv`LBhapY7JbG&jIa}eKqHdi6N127s6WffPG-D2yz$Z|Y@%-;dyfM#Vj zz&H$`!VfaV4Hp7W(>Ojr=HGyEK$iL9P6oMPvue7F zmMo~_I!{a1l<~;)Dev)GSlr%WqBDl zPWLsHO=s_96j;C_&@p|tsjLd)#pw@BWg{3bZMQU&y~Lzt$jDf)%-|@H4Zc+Zyby{} zU>9hhhzWG7IFkkw?2f+a29~mhOg*C0lPzVlm?o^Be%?}6lJVs9mzJ`+pu@;O7t4Th z7i5@(7c$=s%3V%YvZkO5$||j7^BIp#e`zHv&-i#cr?spCWBYV1YgrA(&C`ReWkH7+ zp0$?si24EQ+`ta<1$8(S*c}^CZsf!^^T6)7fEn7#g|6(o0=mcvBnqE-n4WI~Y34%4 zY@l@uXbUBet*nH0J0s|ZP+bNeM^4bxDLbfwR|2gJW(M6x!|u3+5p?q{hXRYh{OSI- zvcc>V!HcazrtiBXD>2>EPF868Wm{Pl$T(Sp+suH?x!VVw^s`(N5N$@y+yucCrRSlR-B_NCIwc3o70)?Wu4il zf^9T`j4Gts%L<~LhRX+D@de&Vpui?@V)}f0+0~5Or!R1nb&Y?CwgjA2fdw?@fGAX1 z9Z#>BDeefX^q@6{LpG$sfHw0%7j1*uUGP>uxMNtO#5%pZ6% zOqK$x0-M0q={1hB%20<`|NS#l+|e4*W&t@w0lA?7>b9WID}n43*fCwfNfv(0wY8J1 z5#z7vc}}vDpp$<(on$8of+hz+`!pIr`!p0-xlc^jah5$Gya}}N6f!l$uEFG>#4GT6 z`hRCxaWP0eB@C*k*d5O>fQk)fftk~FTx9iZ?sGwxcY;sA0^NU!WB)C9Zz~JP3eb{h zMg?AhH`AxN$WCCapRVC5o5VP0dbg`=7-P@$N3ODJj1Q-Cy2<)8KARrtCaVV8?C2(& z&-iTm2RB(e#*@?a-DNez!OlIv1Uly69|P#R2MwkjOail}=ef%&Grpfb$z8UZanp1@ z4_O<=S<}5eWY;lnpAOoAZGj%gph;as1T#6#1l6kg(4dD#F!tIyk3;;E4!JF$9LHFf=PAshRlFeY;KE1+6 z)?FF>`T=GIP65QEGPC2EKQpHXddrHc>;R3Df@^nH@Rlc5&^8ZPO9gTO>6+>J-({ty z^DmQTn{MqZ8xOkaz(*EzcpAv67(!M(0i{KhlV-qnK$1MkHqZ8zRpW5UlzVvIYcGv)|@Tl}Dv%vyo6?V#csqbNKQDC@>}csh5GtRmyr>AFF(vW$(>y@OO|3VeNE&J7H0w z8?C6~4_c?MkCGL&e1RtZ0nX=90Nqf;V9h9?z~J};E)2Q#sG)88#2z_Otqyo&4I(}P z&gYSXYiDs}5ZF6i&|X+#`fWR5E>;#tMi`&JR}REyg7B4CSsa-K_D}?Ctk4HGlpD(D6+yT}0Ge>}`{a}rSsb|qZgE1c zEEaGCokj0>fx(TJ+i^x4Bx0w_$I6OJuH=9=16@Hk_JQs|767kv0!N(0^z>L+ehJW# ztGWzNK%26_V@13y3akoD0!ya%#mWXS_DsJYE9=U*Z@OxntUTky>8^3IlNo!a-;9&h zm4KTLI(rGjaI<*Xd5pWKUyYXq9l~vrAZyIHWO_z|Yy{)p=?4>JZ$h$*q~qQdGsPWc z1tw2lnJ8<>^qP12MQ48D>F*O|IiY7>vw^A~UIjh{0nl0D{ANrl3cL#Zpe;(g3Id>; z1o#yA1s+dVNs`sF-X#EPT5xbH@H!e~De!{ke)t5w@hb4@GMFfeDDY}987PV=fHW*% zQ55E3<%X&0;G5o=B&(xw9Bcqc9I8r5$c)KCffv-L2Ng7+v3pK|PQK}Plfccize%#< zjNhhR+I7X z^u{#VOadmuu6R@c)qtR|X9Jmh0Lf$)6qC)-Yi|nD7$2CIcLl%$c%|jQ!JHGi41J4^1!2l=T9g zWsxas&iHNm&rDe*rcS=;vRShFj0>jwX30u0ew&__1rhDak~I`wz@j8<#soU{6`FcF z_@{LcnEyDdjnR|?iN&Aql{H|zGhM4p z))yWJb!D>UjN7M!;(+PN_vsGhvSRMYS@b!`ktksrBVVX zrzcm)8i<2JA2gQC>)62t>WF}@Lt_y*IDJ)xtSxei{8#}=k*bxl@_b+;cr}=2K%yt8 zQdS#TZF{Axt?gNGLfylr1U>?cK>>XHD=W9-6VQ1xqK+>>l%#^7f{5dP#zIF1_d;Gq zh#))Y92&+dS!u?f(`BnEVLM0Un>i`4CQ34 ztf$fmZbfMYUdIdUkZ=Q)&<*Ta3VZ@5xRs<7q-zDfOgE_m&(tK>$?7t;PM=sOYYJM` zQYWjyxOMu6I@wUh)zjVTWm}+0AbtbLaY(levM8WLx8nhjJgoAAI(`C2mJ&PC2r;PT zjoy#NmIeD8WZST|#5EdaHQ6_V77_6>PFMV=Bs;ydQPz=h`}FONvQFanm(LV;M7kmZ zX0$*PB&@guc1+i8lD(q#Peci_UIo-A2Vdi)z@Pv=+Mf$nZGvu>QE!%QQU|9ea9RSL zR?Dl;_<;kIY?!1#bNQg^kChvAz~S@@&9Z@@6^s)k6h)?+x5)A{&YJGtB5T5bqaA)k z0k7kQ_UTGkCHb%?0L9k872cW;{B*s#R9Q>^#2`C%8%k z$2_Y7xH5t6p#{|xYzn-NGkCHD_6aL;D!`?u-)NOJ1eHkKZL-RY`={%-$=Wj>nx5Y# ztHAl1SAkQ3PoRTu`iwSN3&zjWFSg0fV0<<`s~y}cKie)Vt^wXu44Qg`)`l&RlUf-S zcpWEjLz0t_Bcs6f={y~>DvYzI8+OR*Fg~6h*C8v1Qp#_d-q|55$9R4EiVm6G;V(R^L9 zDvW2Q8+XYnGoG0q-X&|oxN~|>mn`T&z;j))N{ln7f9#T#Wc)v!yIVGpv447Ow`>CA zv+4V~Wpx^$riw4!Mkf9ZJ zXxr9|X%3eHuj2wPQ0&j)0-YB*Qykm^-NgjDP_9o_Ljv4504AwhQ)tcD!T6+$@>6#N{)kI$Nf~HRy6gd=F z9YK2-z>9*DC&=nBwojihK~|lqhj04M39|CiJ$#_Ft;w7K@c?Y$fC7ua)9Ifl$ht5- zn{F{tHj44t^vM&!BR0Dx${I0k;RjhLD#YrzgE311bji{L(CDDRdj9F})m25OYfX~n zmOQ=~GTIEk;#c1B8Axc!biYZm6^z@b=dYHuHdSDDJhE+uxT6@NVFlU`hB62Nn%n>h z!bd-*pPV8KT57&yvMlJ*nEcg}P9e8IrXVeFXI5ZAs-u`4UxVafYf>P&47}h3)P92w zcHp$fYpSf7*X<>sfgYs$iFF)XmO_M(*2h5iH<>wZy*&eTc)>&@4eE{?z#68XnkuWq zwpmz-L*V1|KT~BDnYvh}PxvM$%BsL2@LdSZobESGHkuWDa>n!vlV#UcCs+!d}$_bP~%Ji)D(TlHT|Hnj0gvKaRcZ?%>3E1HRAjD z6<9QxK^wbSK-0`DplrY_ux~ok99aX#7t@XBfcpr^b7Yeke@;I(N7j|`)pVY@vYt%6 zeAC0{f}5lPe5VHT!Nb3xfJvS&YXmxL zf<>P(2R2IyzsCf8SK-F_vJ*ig!pxu%;Sbp^!O8P&d=@0w<_Lo4*(m9iSsC-!GJ{kX$GRJu!%v0Ti)dLIFHg z-mnPl4X|;iLB{DJ{J>1Qak5Jg#{C2thjj5H8OH5eDjUMsGo62#Y%*id^x|c*A;vw- zptgV}^AAQ)>Bq{g!0ZT0uFQ@)S&kQ0&k$E&)?_vS5f%cQ`4pJ-89SJ!ulp%2Flqc@CejQ4_Pj2&Db-2!g5(n#u?LhEtl0|oH_mJa#>ZT z538s1tdQNxcxC#b6|(w_ozp+9kPT+6pYFa=Hj1%l`l6Mx6^vJ=ORthm_v-jGRou}6 zbRCicv*QnzEG1S2&_*&x7J*5iZJV5sQ#2H~r4>M1Mj?V+P(co91rA5160o4aPY@%#Lr^vm9Tno-Vgm*4*yOYUr6nH$XRTKY;O`fOsF+L7T^xfXNl?SpsX=L3Vv% zS7L!XX!2TFgQN|Nh}j7?kUK%gqOgEkXzbhyY_J(kUS?1NRS@{frOR-MnHPKqYy+zj zi!Q?q4$w8kjG*o^m!m8phXG{j*MAmObpXC*2yXf!R>M7WmW)NG(BdW ztPvD5CV`6Y#P4z<)7HznGi~6T4!)Z)cD<}4W6$*Y>t#zBA5RzE zAgg6LUktLx3#6AFe3ru*&>0ylj%S#%9M7x-B{+er0*b7lbHu=_T*0Llo4}#z6&qx2 z>cLVRAgft4n0U;X6ciZ1w`-zkg$&s^ewx<^T9yR1kqz9?b=*F`5i}GB76LV7bs0dR z3OdmmJ*W!)bdyC3M`;Q$8@F}Zo*unX zR+(|f^!kmma^i?hXrP5jpfM;m1xA6b)3#aODhte??z36e zQh1RVxLL-c&&Z<03@+JDPM@(^R-bY4^b?z97c$^@jYWV@^v%(zz|MHWzMfaMil@S1ymfzzP1)u28Kzk;B^OHhDW;rqn zT$;Xbrz~gz{_~x(6G7JvXrGpKWjZr|`oUeYVkU^WITpwJ^Jj`X8bhlKP>`Sx;ef;t z!8HB+X+${L@0OkA`vzscQUG;y6mnNqb;<)JZOi=!S*Nwc64eX%0@!=kXEB@^PulLN|E9=YnaQg1OvL1}frnBsm zJ2e2UL8qnr9h8-4Y@VKX5ZqateNa{!YWWvNMNtJ_@F7c}$CvGo~vmr~f)4D=%zcY5S>P!k3;j`x8rO8|7%Ag^NsoOOW(bSRnw+5zGS3;DdvBHJC22DDr_uM<6EdIW7z8%f37= z+XYIR)!SrU)y{yDp)hhX2qN9##NxOYB#*MD9+p**GwhqwvTa&-*+G%Ppa8qg16=ShIm#D0vbphs zQVZxbCP=wD=M20+)mR5|C(`YXpsJJ=dF&D7cE<}Jr#GBMk0VfdDvDA7f+vE61ujhY zKPOwnxPAJebFw~6yI)QhI4>&_j9x~c1o;i=j$;-DK1aqZfsc@tSm35U)U%NE2F|o# z5yT3d^7G&#{oi?6KgJ8weJ_A*1yvLpji4e1W!Vq5dScSK=>`|E`HS)H^w$?_VBH1tO^{CJm9Ts7sFLVrkh=n6$I^H^SlBcMs2$yYsvU=`hhF5 z`k)z{k5^>%;I5hoTCZ(&RaTJkFR}ZxJ z?-1xHAWo1cK?h_B9GlK{O;(O^&veaevU-e@rbk?pt!BJ9{mM02GtdUO>$2^j0gmgk zR*Y|_pSvzAAqL6H%plKjI?e&lcQFeboBrpztXIZyAw=Vo8DlaI+%aWVU`MNJ(C6&1 z9S_e5USkCs?E{Tn?4Q2whHNt9+v!3#Wpx;DPPe})8_76z`plcM225ST(@)=&)nxoO z{p(FxUB(^Lm2b&vs(@!0K(n>r!iE{TgOU|=IB5g;P*oOz_UQ$;Wc3(tPM?2E)>Ud1 zzXGQMj~UYgCIwE%2TWO@vO2K)N-#vF^Wf)IRzj;SinsNU0uXkik7(Y(ex+`nLws10N0A_m5 zU0EZ>*VE_Ul~vJ)L>*f;A2Smp0~_doU6CvWR>-Cj$W^>-pj5&JT3o^^aCQ2pyRx2) zho;-ylT~9|ab-GajyB_-tg{ekf&jEfkrmXTFi~O@cszaYJz06itJCk^ll9Q*<#S{# z1Pz@sf(@5aU;s6eB_Nab3a~AY3LqQ&@5@Rtc1+K@FKfbhXZrm6vW^1amH5(*(=N;a zm8TOWrhm9EE6LbCo$CR3U7+>@Sv#jrMl&WJ1@Nc_o4|E0&~%OfXbB#R0C=e$D`=@6 z(k6aLe1p#&0Pmd;5LhsM^#fUX#?RAFKallc?4K_3P}Y(0(Dbl}vigkArnfzm^<`|G ze&wO89^;Pb%#UPU8Bb03d?ahc_;h;BBiSIvL(|Vcl9gqAHvR1**;4R!a7E_n=W-Om zec1lTvXYEbr>}f0s|-4Co&hw%16u3MBCvM)?Z>jJjP29U9g#_^fPDu>hXh;{shqB=Ch-U?Si2Ur%IJ z7*9@@e<~{n+OuQ-R91_roqu}vQ&~xYt?UY%j-XLa4h3!nP{(h|Q&|P34*u!ep2{lN zeFiOh1i5knXzd+0(s-bNW8a4v;*M;P!6Qk~jxhLusEXsO_n z>|Dm}(@(vSb@$kMZ>G2-Y)u*Xm=VyxEm8xD$?+UW32Y!1szf780C7e$Xo36mg4dvW zZhFB>ND~`0{M7qWwgWU(!~~uw;ROxefKI!(J6+?I>;i}b+@|xtmSv4Wt-F~VKc1Q) z?#P5_w}3{hk1&A7MiHG5><&A_K#a?lyq0Z6av8V;0}qMWypdH?YzJTL!l}UI=#Z_# z04g@P`M^pXIUO5V1o|bWH@}fJ6zgPEVl!g`E#YAUB~$RMs=$Kjr{2g)aUS9YjZLU1 zvQIzABdEy=T37mby7XIFdHz#i852d&N?lfg+tWSY%1SftnV$MqR+sVi^vQ2!RT+;= z-}zP+bjR?sx3UUy`?wWBn{k-Rl$bzg``Ekl@+z=6+GQz#&hWfAUFDsuDdU;xQSW3U z881%X@=msw@!52z_p;iIf2QZX2TuV^eJ`8C_-s1U2U$(V*6BJQWR)C1#S;^YgCk_T zRltl%M}Y;Ly%bml-m`&sJ{W^$vmu_E&jRu(vXbe2A7oXS`UR(N`5=3e@!9mckFpw4 zu=1 zdfz8mZN^*EcYTsIWc)k*%_rFakf_~fSxpd~`B_$v@z(SipJlBXpH08=8SImPpJhE6 zmrwWjBJ0QaZ2I&sU_T%JBCEu>c>1$1U?l=yWh)tP)e*G62s{c8K2DQO0d#%|sQJw2#>)&E zRAB{mcoo3v5F^cYKV=oBziSgA&wqjQVo6HIt4T3v- zGn&Koet;c5|A(xb>R*s6VM`f6`*##rL04R(dSv>6U*L?b_!E+`L8IArKV@5F|MOwE z1=>gg&ClNdDO<|8efs<#vKrHCf62-v7nI`D#y(*i9(1|P08{q}EJ8Nn~SN*thJ64+3|y6GH$ zWVOuJgKrK5uXzVATjv4wO4$@R1x|t5p`c~JoC5HcFlYfh3%Dhm@kbVXh{J?GvKFAz zdj81jNWc<3criO@-8JN_-%Znb|H>*bUYoA>SJs(ngD`lEkq2}PumU^CedpN0BGZ@u zl?9#fu=6i$#j26xWY7eTnZV@ful~x`GM<>8@lQ6Eankf-|77(+*ZzH%P@69EUv@2H z+w@caWsMnEP5<{_)}8UmRyVm|My4O^(-$sg5}m$*Q4TckdYMr!5_HJ15a^I&en%E} z&>_d%;4vddCOK09(0Qbe0-!UGSU|haE>CY`lDov%GCh)6&Pm`1wvz!j&^yxpD>W>?^HJi-JTxCI-@EdUld0h)1A052c`Ex-qzg#}*iA@Fd&6hO^nw}G3Q!Ofcr*P7o16;lM(B5Ja-Nb`!B-W&VO3;N;Bx!{KFm*$pJgE_#RTdo*n!X9opKgO%mxq0MlI6i<*J>nMFJ>8#2 zE?XFMBctOME+kjIntql?P6B4aYaWOjl6d7p>Y>MuL83+pbj}b$M1fo23uxH^h;rv; zaAZ*A1O=?X7hXjHW(QC+PeA}Y=niU&2^`}DCj})QD6iO&v5*%O6CguR^E%oWDnO*b zYEG1qAF0htUpwPU-ou$MFRR|V%0A0BNT2zV_m<4=t&5W(nzwpVaFm9eM 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 B@df|@ delta 1005190 zcmcclY6Ii4^&1!`yx?Q4udlDKV@P1GudipUo6N*$$jt!~0%6Ab%|?tYER!QxGbTS` zEuLJ!!ZO*4Rc`VDR;9`JSlA{nvD=Q0&7%K}83kxd)gB2?) zJM&~!_Dp6LCV|QQ?1oGNERzqgyHDoeNMux*oW(Ikm6e@^m5D)?g@cEgm6@51jX{Wo znT3gojgg6&gPDbinTd&sjdij*XPUSI6B9EV0}}%W7Z)QV3j+%St1c508}sDFoHiV6 zOl)jSyv&M|UvS#0$$|`E;^1HsVq#*Il9FPTVgW&RR#sLHHfAvUFT%F4#X%Ervh!OSen#=*+U%)!da%EQAjIi6dJhnbC;lYxnqje(Vod2$Q4ilq`0 z$RtKiMotE1HYPR>W)3Eho4JITSXek%m_f#|vVuq^2+6?4%*w#Z%*rJ6Avi(SXnt(89{cjFf&c=6Pk(-T;i<_03ot=S^g#{F&un1-0Wm0x? zXJ%qyVrEgCEFqx7C_C9zK$TH(a<)Lu-Q;6(`pS$}w_Go-MeN zQDL&HkeP(Myn?WTurNQfynHmXIET2nc#Jr+xVZe}$wFqK@@(u}>?|zi3~aJ&oJ>qi zjO=Vo+>C6D418QNqFgF6jL8g)Yz$mnOe|b%EG#n0<|#6K>`aU-GJ@<}yzE?T3`{I+ zqU!1_4D1Xt+`KHTj0KFcvXd2r)jg~j85|k8W%e;nU_Z?AoBM~@FR|ZZom{5o7M6d+ z{)%1TIM4Be?Fq+Ij-PB@oVPjeaNgs*&-tG79p^J{9;P+&TwDInWSlKA;qc~(!lEqv zJ(Ih|HJBL8m>3i|99t$&-YOm}@%eSLI7oomktfTM4Z`Bca@;XlK|+k_>xIb{5<4W` z?rafvo{CRyOcmEKWE9Vf4rQWtSlV9;lL!=}W<%b>vE*ub9U*fV+Z zGpRVHmdTUdq|NyoCcr(;;P|6|a*wnZ(~e1#Z%BtQZJ0D!Po}7T$`m9O7x=Rrdyuu< z;m>lMfh_QXKg)3ml7JI~Inxe)1qR2SDG;|ZtpV{`CO~;7K)eYs-W3pU4vhDJUx7i$ z@e6;J0wXB+85}zVvK%)|m~1Gk&$ME~oYPa&17`sC{tX`==cvR&<_@v#pw7BDli)?u!hkQq(zs3L2);ukPaSfIy&!71UcM5ikl~eo5?|eMS;n2?TVNV zkRZr6t}G4;a~TyG71lAj@-p%`z|^dq)gtc51j!IA5N%%?o5da3AVR#1+zJeijAl$N zLJACyEkdB^>=bw0F_%%mVX~~Uxc-_I9q9UBH8+bpvO@JUD=;|zV8~KnaNHr7C2(_c zva-IUvjT$#Q;8xwh$>JNP+)L;!H}iEDBwJKwX(eM`8BN|zk{+Ui-Q8M0>9(=$#<0% zc`i)o7SB>-RbX>GGhs59iaF!0$xbRt?4ZDOY<@R6TSbxa*5qE5494im-&B+sVUbFBUqt}}DV|hFD9%0ACho`s%N`60ERH-`3QUeX*#dW19hnQQ7^buH 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

>jCIw~%27%Mlzi2X7Grrhf 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

|p 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%0A*+7WpoQbr9EiQ3OqTm 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

BBsNo6n4mhoV+nR`5 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%0DR6ixDe3- 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
UlR^<>;I-Rq~U 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 z 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≶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

9J0RY82ckjgj~fycQ_g{m0M#tJpzc2kr58Z` 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

rwr2@Qn*hSvH6Q_y%ncBO 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 G4h8_ncR&CD From 5060ab99c94dd8afc8b84e74fe4d050c88cdfc0a Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Wed, 18 Jun 2025 10:59:09 -0400 Subject: [PATCH 37/76] aarch64: add new from scratch self-hosted backend --- CMakeLists.txt | 8 + lib/compiler/test_runner.zig | 39 +- lib/compiler_rt.zig | 6 +- lib/compiler_rt/addo.zig | 4 +- lib/compiler_rt/addoti4_test.zig | 3 + lib/compiler_rt/clear_cache.zig | 14 +- lib/compiler_rt/cmp.zig | 1 - lib/compiler_rt/common.zig | 7 +- lib/compiler_rt/comparedf2_test.zig | 1 - lib/compiler_rt/comparesf2_test.zig | 1 - lib/compiler_rt/count0bits.zig | 1 - lib/compiler_rt/divdf3.zig | 1 - lib/compiler_rt/divmodei4.zig | 4 +- lib/compiler_rt/fixint_test.zig | 1 - lib/compiler_rt/int.zig | 1 - lib/compiler_rt/memcpy.zig | 4 +- lib/compiler_rt/memmove.zig | 16 +- lib/compiler_rt/mulf3.zig | 4 +- lib/compiler_rt/rem_pio2_large.zig | 2 +- lib/compiler_rt/stack_probe.zig | 1 - lib/compiler_rt/suboti4_test.zig | 3 + lib/compiler_rt/udivmod.zig | 10 +- lib/compiler_rt/udivmodei4.zig | 5 +- lib/std/Io/Writer.zig | 4 + lib/std/Progress.zig | 5 +- lib/std/builtin.zig | 7 +- lib/std/elf.zig | 2 +- lib/std/fs/File.zig | 5 +- lib/std/math.zig | 93 +- lib/std/math/big/int_test.zig | 1 - lib/std/math/float.zig | 6 +- lib/std/math/log10.zig | 1 - lib/std/mem.zig | 7 +- lib/std/os/linux.zig | 1 - lib/std/start.zig | 59 +- lib/std/testing.zig | 1 + src/Compilation.zig | 2 +- src/InternPool.zig | 14 +- src/Sema.zig | 9 +- src/Type.zig | 2 +- src/Zcu.zig | 29 +- src/Zcu/PerThread.zig | 35 +- src/arch/aarch64/bits.zig | 2063 --- src/arch/riscv64/CodeGen.zig | 10 +- src/arch/sparc64/CodeGen.zig | 4 +- src/arch/wasm/CodeGen.zig | 10 +- src/arch/x86_64/CodeGen.zig | 51 +- src/codegen.zig | 51 +- src/codegen/aarch64.zig | 194 + src/codegen/aarch64/Assemble.zig | 1653 +++ src/codegen/aarch64/Disassemble.zig | 905 ++ src/codegen/aarch64/Mir.zig | 275 + src/codegen/aarch64/Select.zig | 10981 ++++++++++++++ src/codegen/aarch64/abi.zig | 20 +- src/codegen/aarch64/encoding.zig | 11799 ++++++++++++++++ src/codegen/aarch64/instructions.zon | 1343 ++ src/codegen/c.zig | 33 +- src/codegen/llvm.zig | 11 +- src/codegen/spirv.zig | 6 +- src/dev.zig | 41 +- src/link.zig | 1 + src/link/Coff.zig | 76 +- src/link/Dwarf.zig | 8 +- src/link/Elf/Atom.zig | 70 +- src/link/Elf/Thunk.zig | 15 +- src/link/Elf/ZigObject.zig | 10 +- src/link/Elf/relocation.zig | 24 +- src/link/Elf/synthetic_sections.zig | 75 +- src/link/MachO.zig | 3 +- src/link/MachO/Atom.zig | 102 +- src/link/MachO/Thunk.zig | 10 +- src/link/MachO/ZigObject.zig | 10 +- src/link/MachO/synthetic.zig | 95 +- src/link/aarch64.zig | 64 +- src/main.zig | 1 + src/target.zig | 18 +- test/behavior.zig | 4 +- test/behavior/abs.zig | 10 +- test/behavior/align.zig | 20 +- test/behavior/array.zig | 42 +- test/behavior/asm.zig | 9 +- test/behavior/atomics.zig | 25 +- test/behavior/basic.zig | 19 +- test/behavior/bit_shifting.zig | 3 +- test/behavior/bitcast.zig | 21 +- test/behavior/bitreverse.zig | 8 +- ...n_functions_returning_void_or_noreturn.zig | 1 - test/behavior/byteswap.zig | 75 +- test/behavior/call.zig | 19 +- test/behavior/cast.zig | 119 +- test/behavior/cast_int.zig | 7 +- test/behavior/comptime_memory.zig | 2 - test/behavior/const_slice_child.zig | 1 - test/behavior/decl_literals.zig | 3 +- test/behavior/defer.zig | 8 +- test/behavior/enum.zig | 28 +- test/behavior/error.zig | 41 +- test/behavior/eval.zig | 36 +- test/behavior/export_builtin.zig | 4 - test/behavior/field_parent_ptr.zig | 5 + test/behavior/floatop.zig | 86 +- test/behavior/fn.zig | 13 - test/behavior/for.zig | 20 - test/behavior/generics.zig | 19 +- test/behavior/globals.zig | 6 +- test/behavior/if.zig | 6 +- test/behavior/import_c_keywords.zig | 1 - test/behavior/inline_switch.zig | 11 +- test/behavior/int128.zig | 5 - test/behavior/int_comparison_elision.zig | 1 - test/behavior/ir_block_deps.zig | 1 - test/behavior/lower_strlit_to_vector.zig | 1 - test/behavior/math.zig | 72 +- test/behavior/maximum_minimum.zig | 22 +- test/behavior/member_func.zig | 2 - test/behavior/memcpy.zig | 5 +- test/behavior/memmove.zig | 3 - test/behavior/memset.zig | 7 - test/behavior/muladd.zig | 14 +- ...ultiple_externs_with_conflicting_types.zig | 1 - test/behavior/nan.zig | 1 - test/behavior/null.zig | 6 +- test/behavior/optional.zig | 22 +- test/behavior/packed-struct.zig | 46 +- test/behavior/packed-union.zig | 6 +- .../packed_struct_explicit_backing_int.zig | 1 - test/behavior/pointers.zig | 13 +- test/behavior/popcount.zig | 5 +- test/behavior/ptrcast.zig | 19 - test/behavior/ptrfromint.zig | 3 - ...ef_var_in_if_after_if_2nd_switch_prong.zig | 1 - test/behavior/reflection.zig | 1 - test/behavior/return_address.zig | 2 +- test/behavior/saturating_arithmetic.zig | 17 +- test/behavior/select.zig | 5 +- test/behavior/shuffle.zig | 8 +- test/behavior/sizeof_and_typeof.zig | 3 - test/behavior/slice.zig | 24 +- test/behavior/src.zig | 1 - test/behavior/string_literals.zig | 6 +- test/behavior/struct.zig | 62 +- .../struct_contains_null_ptr_itself.zig | 1 - .../struct_contains_slice_of_itself.zig | 3 +- test/behavior/switch.zig | 33 +- test/behavior/switch_loop.zig | 16 +- test/behavior/switch_on_captured_error.zig | 2 + test/behavior/switch_prong_err_enum.zig | 2 +- test/behavior/switch_prong_implicit_cast.zig | 2 +- test/behavior/this.zig | 2 - test/behavior/threadlocal.zig | 3 - test/behavior/truncate.zig | 2 +- test/behavior/try.zig | 3 +- test/behavior/tuple.zig | 22 +- test/behavior/tuple_declarations.zig | 2 - test/behavior/type.zig | 9 +- test/behavior/type_info.zig | 6 +- test/behavior/typename.zig | 8 - test/behavior/undefined.zig | 4 - test/behavior/union.zig | 120 +- test/behavior/union_with_members.zig | 2 +- test/behavior/var_args.zig | 22 +- test/behavior/vector.zig | 98 +- test/behavior/void.zig | 1 - test/behavior/while.zig | 12 +- test/behavior/widening.zig | 5 - test/c_import/macros.zig | 12 - test/tests.zig | 38 +- 167 files changed, 28210 insertions(+), 3730 deletions(-) delete mode 100644 src/arch/aarch64/bits.zig create mode 100644 src/codegen/aarch64.zig create mode 100644 src/codegen/aarch64/Assemble.zig create mode 100644 src/codegen/aarch64/Disassemble.zig create mode 100644 src/codegen/aarch64/Mir.zig create mode 100644 src/codegen/aarch64/Select.zig create mode 100644 src/codegen/aarch64/encoding.zig create mode 100644 src/codegen/aarch64/instructions.zon diff --git a/CMakeLists.txt b/CMakeLists.txt index d9824e5c12..b78b0012f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -550,6 +550,14 @@ set(ZIG_STAGE2_SOURCES src/clang_options.zig src/clang_options_data.zig src/codegen.zig + src/codegen/aarch64.zig + src/codegen/aarch64/abi.zig + src/codegen/aarch64/Assemble.zig + src/codegen/aarch64/Disassemble.zig + src/codegen/aarch64/encoding.zig + src/codegen/aarch64/instructions.zon + src/codegen/aarch64/Mir.zig + src/codegen/aarch64/Select.zig src/codegen/c.zig src/codegen/c/Type.zig src/codegen/llvm.zig diff --git a/lib/compiler/test_runner.zig b/lib/compiler/test_runner.zig index 8b60a75399..e618f72d2f 100644 --- a/lib/compiler/test_runner.zig +++ b/lib/compiler/test_runner.zig @@ -16,6 +16,7 @@ var stdin_buffer: [4096]u8 = undefined; var stdout_buffer: [4096]u8 = undefined; const crippled = switch (builtin.zig_backend) { + .stage2_aarch64, .stage2_powerpc, .stage2_riscv64, => true, @@ -287,13 +288,14 @@ pub fn log( /// work-in-progress backends can handle it. pub fn mainSimple() anyerror!void { @disableInstrumentation(); - // is the backend capable of printing to stderr? - const enable_print = switch (builtin.zig_backend) { + // is the backend capable of calling `std.fs.File.writeAll`? + const enable_write = switch (builtin.zig_backend) { + .stage2_aarch64, .stage2_riscv64 => true, else => false, }; - // is the backend capable of using std.fmt.format to print a summary at the end? - const print_summary = switch (builtin.zig_backend) { - .stage2_riscv64 => true, + // is the backend capable of calling `std.Io.Writer.print`? + const enable_print = switch (builtin.zig_backend) { + .stage2_aarch64, .stage2_riscv64 => true, else => false, }; @@ -302,34 +304,31 @@ pub fn mainSimple() anyerror!void { var failed: u64 = 0; // we don't want to bring in File and Writer if the backend doesn't support it - const stderr = if (comptime enable_print) std.fs.File.stderr() else {}; + const stdout = if (enable_write) std.fs.File.stdout() else {}; for (builtin.test_functions) |test_fn| { + if (enable_write) { + stdout.writeAll(test_fn.name) catch {}; + stdout.writeAll("... ") catch {}; + } if (test_fn.func()) |_| { - if (enable_print) { - stderr.writeAll(test_fn.name) catch {}; - stderr.writeAll("... ") catch {}; - stderr.writeAll("PASS\n") catch {}; - } + if (enable_write) stdout.writeAll("PASS\n") catch {}; } else |err| { - if (enable_print) { - stderr.writeAll(test_fn.name) catch {}; - stderr.writeAll("... ") catch {}; - } if (err != error.SkipZigTest) { - if (enable_print) stderr.writeAll("FAIL\n") catch {}; + if (enable_write) stdout.writeAll("FAIL\n") catch {}; failed += 1; - if (!enable_print) return err; + if (!enable_write) return err; continue; } - if (enable_print) stderr.writeAll("SKIP\n") catch {}; + if (enable_write) stdout.writeAll("SKIP\n") catch {}; skipped += 1; continue; } passed += 1; } - if (enable_print and print_summary) { - stderr.deprecatedWriter().print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {}; + if (enable_print) { + var stdout_writer = stdout.writer(&.{}); + stdout_writer.interface.print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {}; } if (failed != 0) std.process.exit(1); } diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index 46db464fd9..17e9e04da7 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -240,7 +240,7 @@ comptime { _ = @import("compiler_rt/udivmodti4.zig"); // extra - _ = @import("compiler_rt/os_version_check.zig"); + if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/os_version_check.zig"); _ = @import("compiler_rt/emutls.zig"); _ = @import("compiler_rt/arm.zig"); _ = @import("compiler_rt/aulldiv.zig"); @@ -249,12 +249,12 @@ comptime { _ = @import("compiler_rt/hexagon.zig"); if (@import("builtin").object_format != .c) { - _ = @import("compiler_rt/atomics.zig"); + if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/atomics.zig"); _ = @import("compiler_rt/stack_probe.zig"); // macOS has these functions inside libSystem. if (builtin.cpu.arch.isAARCH64() and !builtin.os.tag.isDarwin()) { - _ = @import("compiler_rt/aarch64_outline_atomics.zig"); + if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/aarch64_outline_atomics.zig"); } _ = @import("compiler_rt/memcpy.zig"); diff --git a/lib/compiler_rt/addo.zig b/lib/compiler_rt/addo.zig index beb6249223..610d620690 100644 --- a/lib/compiler_rt/addo.zig +++ b/lib/compiler_rt/addo.zig @@ -1,6 +1,4 @@ const std = @import("std"); -const builtin = @import("builtin"); -const is_test = builtin.is_test; const common = @import("./common.zig"); pub const panic = @import("common.zig").panic; @@ -16,7 +14,7 @@ comptime { // - addoXi4_generic as default inline fn addoXi4_generic(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST { - @setRuntimeSafety(builtin.is_test); + @setRuntimeSafety(common.test_safety); overflow.* = 0; const sum: ST = a +% b; // Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract diff --git a/lib/compiler_rt/addoti4_test.zig b/lib/compiler_rt/addoti4_test.zig index dc85830df9..d031d1d428 100644 --- a/lib/compiler_rt/addoti4_test.zig +++ b/lib/compiler_rt/addoti4_test.zig @@ -1,4 +1,5 @@ const addv = @import("addo.zig"); +const builtin = @import("builtin"); const std = @import("std"); const testing = std.testing; const math = std.math; @@ -23,6 +24,8 @@ fn simple_addoti4(a: i128, b: i128, overflow: *c_int) i128 { } test "addoti4" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const min: i128 = math.minInt(i128); const max: i128 = math.maxInt(i128); var i: i128 = 1; diff --git a/lib/compiler_rt/clear_cache.zig b/lib/compiler_rt/clear_cache.zig index e4a0a9d00d..c43d35602c 100644 --- a/lib/compiler_rt/clear_cache.zig +++ b/lib/compiler_rt/clear_cache.zig @@ -97,8 +97,7 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void { .nbytes = end - start, .whichcache = 3, // ICACHE | DCACHE }; - asm volatile ( - \\ syscall + asm volatile ("syscall" : : [_] "{$2}" (165), // nr = SYS_sysarch [_] "{$4}" (0), // op = MIPS_CACHEFLUSH @@ -116,11 +115,8 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void { } else if (arm64 and !apple) { // Get Cache Type Info. // TODO memoize this? - var ctr_el0: u64 = 0; - asm volatile ( - \\mrs %[x], ctr_el0 - \\ - : [x] "=r" (ctr_el0), + const ctr_el0 = asm volatile ("mrs %[ctr_el0], ctr_el0" + : [ctr_el0] "=r" (-> u64), ); // The DC and IC instructions must use 64-bit registers so we don't use // uintptr_t in case this runs in an IPL32 environment. @@ -187,9 +183,7 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void { exportIt(); } else if (os == .linux and loongarch) { // See: https://github.com/llvm/llvm-project/blob/cf54cae26b65fc3201eff7200ffb9b0c9e8f9a13/compiler-rt/lib/builtins/clear_cache.c#L94-L95 - asm volatile ( - \\ ibar 0 - ); + asm volatile ("ibar 0"); exportIt(); } diff --git a/lib/compiler_rt/cmp.zig b/lib/compiler_rt/cmp.zig index e1273aa622..67cb5b0938 100644 --- a/lib/compiler_rt/cmp.zig +++ b/lib/compiler_rt/cmp.zig @@ -1,6 +1,5 @@ const std = @import("std"); const builtin = @import("builtin"); -const is_test = builtin.is_test; const common = @import("common.zig"); pub const panic = common.panic; diff --git a/lib/compiler_rt/common.zig b/lib/compiler_rt/common.zig index f5423019f1..1160b1c718 100644 --- a/lib/compiler_rt/common.zig +++ b/lib/compiler_rt/common.zig @@ -102,9 +102,14 @@ pub const gnu_f16_abi = switch (builtin.cpu.arch) { pub const want_sparc_abi = builtin.cpu.arch.isSPARC(); +pub const test_safety = switch (builtin.zig_backend) { + .stage2_aarch64 => false, + else => builtin.is_test, +}; + // Avoid dragging in the runtime safety mechanisms into this .o file, unless // we're trying to test compiler-rt. -pub const panic = if (builtin.is_test) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.no_panic; +pub const panic = if (test_safety) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.no_panic; /// This seems to mostly correspond to `clang::TargetInfo::HasFloat16`. pub fn F16T(comptime OtherType: type) type { diff --git a/lib/compiler_rt/comparedf2_test.zig b/lib/compiler_rt/comparedf2_test.zig index 9444c6adf7..dbae6bbeec 100644 --- a/lib/compiler_rt/comparedf2_test.zig +++ b/lib/compiler_rt/comparedf2_test.zig @@ -4,7 +4,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const is_test = builtin.is_test; const __eqdf2 = @import("./cmpdf2.zig").__eqdf2; const __ledf2 = @import("./cmpdf2.zig").__ledf2; diff --git a/lib/compiler_rt/comparesf2_test.zig b/lib/compiler_rt/comparesf2_test.zig index 40b1324cfa..65e78da99e 100644 --- a/lib/compiler_rt/comparesf2_test.zig +++ b/lib/compiler_rt/comparesf2_test.zig @@ -4,7 +4,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const is_test = builtin.is_test; const __eqsf2 = @import("./cmpsf2.zig").__eqsf2; const __lesf2 = @import("./cmpsf2.zig").__lesf2; diff --git a/lib/compiler_rt/count0bits.zig b/lib/compiler_rt/count0bits.zig index c9bdfb7c23..874604eb2c 100644 --- a/lib/compiler_rt/count0bits.zig +++ b/lib/compiler_rt/count0bits.zig @@ -1,6 +1,5 @@ const std = @import("std"); const builtin = @import("builtin"); -const is_test = builtin.is_test; const common = @import("common.zig"); pub const panic = common.panic; diff --git a/lib/compiler_rt/divdf3.zig b/lib/compiler_rt/divdf3.zig index 0340404a69..7b47cd3a70 100644 --- a/lib/compiler_rt/divdf3.zig +++ b/lib/compiler_rt/divdf3.zig @@ -5,7 +5,6 @@ const std = @import("std"); const builtin = @import("builtin"); const arch = builtin.cpu.arch; -const is_test = builtin.is_test; const common = @import("common.zig"); const normalize = common.normalize; diff --git a/lib/compiler_rt/divmodei4.zig b/lib/compiler_rt/divmodei4.zig index 3f12e8697d..ab11452206 100644 --- a/lib/compiler_rt/divmodei4.zig +++ b/lib/compiler_rt/divmodei4.zig @@ -34,7 +34,7 @@ fn divmod(q: ?[]u32, r: ?[]u32, u: []u32, v: []u32) !void { } pub fn __divei4(q_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void { - @setRuntimeSafety(builtin.is_test); + @setRuntimeSafety(common.test_safety); const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size])); const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size])); @@ -43,7 +43,7 @@ pub fn __divei4(q_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) vo } pub fn __modei4(r_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void { - @setRuntimeSafety(builtin.is_test); + @setRuntimeSafety(common.test_safety); const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size])); const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size])); diff --git a/lib/compiler_rt/fixint_test.zig b/lib/compiler_rt/fixint_test.zig index 57b4093809..198167ab86 100644 --- a/lib/compiler_rt/fixint_test.zig +++ b/lib/compiler_rt/fixint_test.zig @@ -1,4 +1,3 @@ -const is_test = @import("builtin").is_test; const std = @import("std"); const math = std.math; const testing = std.testing; diff --git a/lib/compiler_rt/int.zig b/lib/compiler_rt/int.zig index 4a89d0799d..16c504ee66 100644 --- a/lib/compiler_rt/int.zig +++ b/lib/compiler_rt/int.zig @@ -6,7 +6,6 @@ const testing = std.testing; const maxInt = std.math.maxInt; const minInt = std.math.minInt; const arch = builtin.cpu.arch; -const is_test = builtin.is_test; const common = @import("common.zig"); const udivmod = @import("udivmod.zig").udivmod; const __divti3 = @import("divti3.zig").__divti3; diff --git a/lib/compiler_rt/memcpy.zig b/lib/compiler_rt/memcpy.zig index 30971677ab..424e92954d 100644 --- a/lib/compiler_rt/memcpy.zig +++ b/lib/compiler_rt/memcpy.zig @@ -11,7 +11,7 @@ comptime { .visibility = common.visibility, }; - if (builtin.mode == .ReleaseSmall) + if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64) @export(&memcpySmall, export_options) else @export(&memcpyFast, export_options); @@ -195,6 +195,8 @@ inline fn copyRange4( } test "memcpy" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn testFunc(comptime copy_func: anytype) !void { const max_len = 1024; diff --git a/lib/compiler_rt/memmove.zig b/lib/compiler_rt/memmove.zig index 71289a50ae..46c5a631cb 100644 --- a/lib/compiler_rt/memmove.zig +++ b/lib/compiler_rt/memmove.zig @@ -14,7 +14,7 @@ comptime { .visibility = common.visibility, }; - if (builtin.mode == .ReleaseSmall) + if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64) @export(&memmoveSmall, export_options) else @export(&memmoveFast, export_options); @@ -39,7 +39,7 @@ fn memmoveSmall(opt_dest: ?[*]u8, opt_src: ?[*]const u8, len: usize) callconv(.c } fn memmoveFast(dest: ?[*]u8, src: ?[*]u8, len: usize) callconv(.c) ?[*]u8 { - @setRuntimeSafety(builtin.is_test); + @setRuntimeSafety(common.test_safety); const small_limit = @max(2 * @sizeOf(Element), @sizeOf(Element)); if (copySmallLength(small_limit, dest.?, src.?, len)) return dest; @@ -79,7 +79,7 @@ inline fn copyLessThan16( src: [*]const u8, len: usize, ) void { - @setRuntimeSafety(builtin.is_test); + @setRuntimeSafety(common.test_safety); if (len < 4) { if (len == 0) return; const b = len / 2; @@ -100,7 +100,7 @@ inline fn copy16ToSmallLimit( src: [*]const u8, len: usize, ) bool { - @setRuntimeSafety(builtin.is_test); + @setRuntimeSafety(common.test_safety); inline for (2..(std.math.log2(small_limit) + 1) / 2 + 1) |p| { const limit = 1 << (2 * p); if (len < limit) { @@ -119,7 +119,7 @@ inline fn copyRange4( src: [*]const u8, len: usize, ) void { - @setRuntimeSafety(builtin.is_test); + @setRuntimeSafety(common.test_safety); comptime assert(std.math.isPowerOfTwo(copy_len)); assert(len >= copy_len); assert(len < 4 * copy_len); @@ -147,7 +147,7 @@ inline fn copyForwards( src: [*]const u8, len: usize, ) void { - @setRuntimeSafety(builtin.is_test); + @setRuntimeSafety(common.test_safety); assert(len >= 2 * @sizeOf(Element)); const head = src[0..@sizeOf(Element)].*; @@ -181,7 +181,7 @@ inline fn copyBlocks( src: anytype, max_bytes: usize, ) void { - @setRuntimeSafety(builtin.is_test); + @setRuntimeSafety(common.test_safety); const T = @typeInfo(@TypeOf(dest)).pointer.child; comptime assert(T == @typeInfo(@TypeOf(src)).pointer.child); @@ -217,6 +217,8 @@ inline fn copyBackwards( } test memmoveFast { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const max_len = 1024; var buffer: [max_len + @alignOf(Element) - 1]u8 = undefined; for (&buffer, 0..) |*b, i| { diff --git a/lib/compiler_rt/mulf3.zig b/lib/compiler_rt/mulf3.zig index ad60ec41a5..34d39fb9b7 100644 --- a/lib/compiler_rt/mulf3.zig +++ b/lib/compiler_rt/mulf3.zig @@ -6,7 +6,7 @@ const common = @import("./common.zig"); /// Ported from: /// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc pub inline fn mulf3(comptime T: type, a: T, b: T) T { - @setRuntimeSafety(builtin.is_test); + @setRuntimeSafety(common.test_safety); const typeWidth = @typeInfo(T).float.bits; const significandBits = math.floatMantissaBits(T); const fractionalBits = math.floatFractionalBits(T); @@ -163,7 +163,7 @@ pub inline fn mulf3(comptime T: type, a: T, b: T) T { /// /// This is analogous to an shr version of `@shlWithOverflow` fn wideShrWithTruncation(comptime Z: type, hi: *Z, lo: *Z, count: u32) bool { - @setRuntimeSafety(builtin.is_test); + @setRuntimeSafety(common.test_safety); const typeWidth = @typeInfo(Z).int.bits; var inexact = false; if (count < typeWidth) { diff --git a/lib/compiler_rt/rem_pio2_large.zig b/lib/compiler_rt/rem_pio2_large.zig index b107a0fabb..f15e0d71f6 100644 --- a/lib/compiler_rt/rem_pio2_large.zig +++ b/lib/compiler_rt/rem_pio2_large.zig @@ -251,7 +251,7 @@ const PIo2 = [_]f64{ /// compiler will convert from decimal to binary accurately enough /// to produce the hexadecimal values shown. /// -pub fn rem_pio2_large(x: []f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 { +pub fn rem_pio2_large(x: []const f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 { var jz: i32 = undefined; var jx: i32 = undefined; var jv: i32 = undefined; diff --git a/lib/compiler_rt/stack_probe.zig b/lib/compiler_rt/stack_probe.zig index 94212b7a23..21259ec435 100644 --- a/lib/compiler_rt/stack_probe.zig +++ b/lib/compiler_rt/stack_probe.zig @@ -4,7 +4,6 @@ const common = @import("common.zig"); const os_tag = builtin.os.tag; const arch = builtin.cpu.arch; const abi = builtin.abi; -const is_test = builtin.is_test; pub const panic = common.panic; diff --git a/lib/compiler_rt/suboti4_test.zig b/lib/compiler_rt/suboti4_test.zig index 68ad0ff72f..65018bc966 100644 --- a/lib/compiler_rt/suboti4_test.zig +++ b/lib/compiler_rt/suboti4_test.zig @@ -1,4 +1,5 @@ const subo = @import("subo.zig"); +const builtin = @import("builtin"); const std = @import("std"); const testing = std.testing; const math = std.math; @@ -27,6 +28,8 @@ pub fn simple_suboti4(a: i128, b: i128, overflow: *c_int) i128 { } test "suboti3" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const min: i128 = math.minInt(i128); const max: i128 = math.maxInt(i128); var i: i128 = 1; diff --git a/lib/compiler_rt/udivmod.zig b/lib/compiler_rt/udivmod.zig index a9705f317d..bf6aaadeae 100644 --- a/lib/compiler_rt/udivmod.zig +++ b/lib/compiler_rt/udivmod.zig @@ -1,8 +1,8 @@ const std = @import("std"); const builtin = @import("builtin"); -const is_test = builtin.is_test; const Log2Int = std.math.Log2Int; -const HalveInt = @import("common.zig").HalveInt; +const common = @import("common.zig"); +const HalveInt = common.HalveInt; const lo = switch (builtin.cpu.arch.endian()) { .big => 1, @@ -14,7 +14,7 @@ const hi = 1 - lo; // Returns U / v_ and sets r = U % v_. fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T { const HalfT = HalveInt(T, false).HalfT; - @setRuntimeSafety(is_test); + @setRuntimeSafety(common.test_safety); var v = v_; const b = @as(T, 1) << (@bitSizeOf(T) / 2); @@ -70,7 +70,7 @@ fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T { } fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T { - @setRuntimeSafety(is_test); + @setRuntimeSafety(common.test_safety); if (T == u64 and builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag != .windows) { var rem: T = undefined; const quo = asm ( @@ -90,7 +90,7 @@ fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T { // Returns a_ / b_ and sets maybe_rem = a_ % b. pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T { - @setRuntimeSafety(is_test); + @setRuntimeSafety(common.test_safety); const HalfT = HalveInt(T, false).HalfT; const SignedT = std.meta.Int(.signed, @bitSizeOf(T)); diff --git a/lib/compiler_rt/udivmodei4.zig b/lib/compiler_rt/udivmodei4.zig index 6d6f6c1b65..0923f3f222 100644 --- a/lib/compiler_rt/udivmodei4.zig +++ b/lib/compiler_rt/udivmodei4.zig @@ -113,7 +113,7 @@ pub fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32) !void { } pub fn __udivei4(q_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) callconv(.c) void { - @setRuntimeSafety(builtin.is_test); + @setRuntimeSafety(common.test_safety); const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size])); const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size])); @@ -122,7 +122,7 @@ pub fn __udivei4(q_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) ca } pub fn __umodei4(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) callconv(.c) void { - @setRuntimeSafety(builtin.is_test); + @setRuntimeSafety(common.test_safety); const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size])); const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size])); @@ -131,6 +131,7 @@ pub fn __umodei4(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) ca } test "__udivei4/__umodei4" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; diff --git a/lib/std/Io/Writer.zig b/lib/std/Io/Writer.zig index 0723073592..55672c557c 100644 --- a/lib/std/Io/Writer.zig +++ b/lib/std/Io/Writer.zig @@ -2239,6 +2239,10 @@ pub const Discarding = struct { pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize { if (File.Handle == void) return error.Unimplemented; + switch (builtin.zig_backend) { + else => {}, + .stage2_aarch64 => return error.Unimplemented, + } const d: *Discarding = @alignCast(@fieldParentPtr("writer", w)); d.count += w.end; w.end = 0; diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index 2634553d25..5ee5828970 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -408,6 +408,9 @@ pub const have_ipc = switch (builtin.os.tag) { const noop_impl = builtin.single_threaded or switch (builtin.os.tag) { .wasi, .freestanding => true, else => false, +} or switch (builtin.zig_backend) { + .stage2_aarch64 => true, + else => false, }; /// Initializes a global Progress instance. @@ -754,7 +757,7 @@ fn appendTreeSymbol(symbol: TreeSymbol, buf: []u8, start_i: usize) usize { } fn clearWrittenWithEscapeCodes() anyerror!void { - if (!global_progress.need_clear) return; + if (noop_impl or !global_progress.need_clear) return; global_progress.need_clear = false; try write(clear); diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 8f4aefc713..54376426e2 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -772,7 +772,7 @@ pub const Endian = enum { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. -pub const Signedness = enum { +pub const Signedness = enum(u1) { signed, unsigned, }; @@ -894,7 +894,10 @@ pub const VaList = switch (builtin.cpu.arch) { .aarch64, .aarch64_be => switch (builtin.os.tag) { .windows => *u8, .ios, .macos, .tvos, .watchos, .visionos => *u8, - else => @compileError("disabled due to miscompilations"), // VaListAarch64, + else => switch (builtin.zig_backend) { + .stage2_aarch64 => VaListAarch64, + else => @compileError("disabled due to miscompilations"), + }, }, .arm, .armeb, .thumb, .thumbeb => switch (builtin.os.tag) { .ios, .macos, .tvos, .watchos, .visionos => *u8, diff --git a/lib/std/elf.zig b/lib/std/elf.zig index 47b3add84f..2583e83d19 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -2001,7 +2001,7 @@ pub const R_AARCH64 = enum(u32) { TLSLE_LDST64_TPREL_LO12 = 558, /// Likewise; no check. TLSLE_LDST64_TPREL_LO12_NC = 559, - /// PC-rel. load immediate 20:2. + /// PC-rel. load immediate 20:2. TLSDESC_LD_PREL19 = 560, /// PC-rel. ADR immediate 20:0. TLSDESC_ADR_PREL21 = 561, diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 138807972e..39111f634d 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1554,7 +1554,10 @@ pub const Writer = struct { return .{ .vtable = &.{ .drain = drain, - .sendFile = sendFile, + .sendFile = switch (builtin.zig_backend) { + else => sendFile, + .stage2_aarch64 => std.io.Writer.unimplementedSendFile, + }, }, .buffer = buffer, }; diff --git a/lib/std/math.zig b/lib/std/math.zig index 1cd9a83a14..9f2d12a65e 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -45,6 +45,7 @@ pub const rad_per_deg = 0.017453292519943295769236907684886127134428718885417254 /// 180.0/pi pub const deg_per_rad = 57.295779513082320876798154814105170332405472466564321549160243861; +pub const Sign = enum(u1) { positive, negative }; pub const FloatRepr = float.FloatRepr; pub const floatExponentBits = float.floatExponentBits; pub const floatMantissaBits = float.floatMantissaBits; @@ -594,27 +595,30 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T { /// Shifts left. Overflowed bits are truncated. /// A negative shift amount results in a right shift. pub fn shl(comptime T: type, a: T, shift_amt: anytype) T { + const is_shl = shift_amt >= 0; const abs_shift_amt = @abs(shift_amt); - - const casted_shift_amt = blk: { - if (@typeInfo(T) == .vector) { - const C = @typeInfo(T).vector.child; - const len = @typeInfo(T).vector.len; - if (abs_shift_amt >= @typeInfo(C).int.bits) return @splat(0); - break :blk @as(@Vector(len, Log2Int(C)), @splat(@as(Log2Int(C), @intCast(abs_shift_amt)))); - } else { - if (abs_shift_amt >= @typeInfo(T).int.bits) return 0; - break :blk @as(Log2Int(T), @intCast(abs_shift_amt)); - } + const casted_shift_amt = casted_shift_amt: switch (@typeInfo(T)) { + .int => |info| { + if (abs_shift_amt < info.bits) break :casted_shift_amt @as( + Log2Int(T), + @intCast(abs_shift_amt), + ); + if (info.signedness == .unsigned or is_shl) return 0; + return a >> (info.bits - 1); + }, + .vector => |info| { + const Child = info.child; + const child_info = @typeInfo(Child).int; + if (abs_shift_amt < child_info.bits) break :casted_shift_amt @as( + @Vector(info.len, Log2Int(Child)), + @splat(@as(Log2Int(Child), @intCast(abs_shift_amt))), + ); + if (child_info.signedness == .unsigned or is_shl) return @splat(0); + return a >> @splat(child_info.bits - 1); + }, + else => comptime unreachable, }; - - if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).int.signedness == .signed) { - if (shift_amt < 0) { - return a >> casted_shift_amt; - } - } - - return a << casted_shift_amt; + return if (is_shl) a << casted_shift_amt else a >> casted_shift_amt; } test shl { @@ -629,32 +633,40 @@ test shl { try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) << 1); try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) >> 1); try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0); + + try testing.expect(shl(i8, -1, -100) == -1); + try testing.expect(shl(i8, -1, 100) == 0); + try testing.expect(@reduce(.And, shl(@Vector(2, i8), .{ -1, 1 }, -100) == @Vector(2, i8){ -1, 0 })); + try testing.expect(@reduce(.And, shl(@Vector(2, i8), .{ -1, 1 }, 100) == @Vector(2, i8){ 0, 0 })); } /// Shifts right. Overflowed bits are truncated. /// A negative shift amount results in a left shift. pub fn shr(comptime T: type, a: T, shift_amt: anytype) T { + const is_shl = shift_amt < 0; const abs_shift_amt = @abs(shift_amt); - - const casted_shift_amt = blk: { - if (@typeInfo(T) == .vector) { - const C = @typeInfo(T).vector.child; - const len = @typeInfo(T).vector.len; - if (abs_shift_amt >= @typeInfo(C).int.bits) return @splat(0); - break :blk @as(@Vector(len, Log2Int(C)), @splat(@as(Log2Int(C), @intCast(abs_shift_amt)))); - } else { - if (abs_shift_amt >= @typeInfo(T).int.bits) return 0; - break :blk @as(Log2Int(T), @intCast(abs_shift_amt)); - } + const casted_shift_amt = casted_shift_amt: switch (@typeInfo(T)) { + .int => |info| { + if (abs_shift_amt < info.bits) break :casted_shift_amt @as( + Log2Int(T), + @intCast(abs_shift_amt), + ); + if (info.signedness == .unsigned or is_shl) return 0; + return a >> (info.bits - 1); + }, + .vector => |info| { + const Child = info.child; + const child_info = @typeInfo(Child).int; + if (abs_shift_amt < child_info.bits) break :casted_shift_amt @as( + @Vector(info.len, Log2Int(Child)), + @splat(@as(Log2Int(Child), @intCast(abs_shift_amt))), + ); + if (child_info.signedness == .unsigned or is_shl) return @splat(0); + return a >> @splat(child_info.bits - 1); + }, + else => comptime unreachable, }; - - if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).int.signedness == .signed) { - if (shift_amt < 0) { - return a << casted_shift_amt; - } - } - - return a >> casted_shift_amt; + return if (is_shl) a << casted_shift_amt else a >> casted_shift_amt; } test shr { @@ -669,6 +681,11 @@ test shr { try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) >> 1); try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) << 1); try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0); + + try testing.expect(shr(i8, -1, -100) == 0); + try testing.expect(shr(i8, -1, 100) == -1); + try testing.expect(@reduce(.And, shr(@Vector(2, i8), .{ -1, 1 }, -100) == @Vector(2, i8){ 0, 0 })); + try testing.expect(@reduce(.And, shr(@Vector(2, i8), .{ -1, 1 }, 100) == @Vector(2, i8){ -1, 0 })); } /// Rotates right. Only unsigned values can be rotated. Negative shift diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index f44b254cf1..bb6deeb778 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -2774,7 +2774,6 @@ test "bitNotWrap more than two limbs" { // This test requires int sizes greater than 128 bits. if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO // LLVM: unexpected runtime library name: __umodei4 if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.cpu.arch.isWasm()) return error.SkipZigTest; // TODO diff --git a/lib/std/math/float.zig b/lib/std/math/float.zig index df7d7fe1ab..6ffbd85bd2 100644 --- a/lib/std/math/float.zig +++ b/lib/std/math/float.zig @@ -4,8 +4,6 @@ const assert = std.debug.assert; const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; -pub const Sign = enum(u1) { positive, negative }; - pub fn FloatRepr(comptime Float: type) type { const fractional_bits = floatFractionalBits(Float); const exponent_bits = floatExponentBits(Float); @@ -14,7 +12,7 @@ pub fn FloatRepr(comptime Float: type) type { mantissa: StoredMantissa, exponent: BiasedExponent, - sign: Sign, + sign: std.math.Sign, pub const StoredMantissa = @Type(.{ .int = .{ .signedness = .unsigned, @@ -69,7 +67,7 @@ pub fn FloatRepr(comptime Float: type) type { /// This currently truncates denormal values, which needs to be fixed before this can be used to /// produce a rounded value. - pub fn reconstruct(normalized: Normalized, sign: Sign) Float { + pub fn reconstruct(normalized: Normalized, sign: std.math.Sign) Float { if (normalized.exponent > BiasedExponent.max_normal.unbias()) return @bitCast(Repr{ .mantissa = 0, .exponent = .infinite, diff --git a/lib/std/math/log10.zig b/lib/std/math/log10.zig index 655a42215e..9ac5c6da24 100644 --- a/lib/std/math/log10.zig +++ b/lib/std/math/log10.zig @@ -132,7 +132,6 @@ inline fn less_than_5(x: u32) u32 { test log10_int { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.cpu.arch.isWasm()) return error.SkipZigTest; // TODO diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 1a61076f32..3b72a2b579 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -676,6 +676,7 @@ test lessThan { const eqlBytes_allowed = switch (builtin.zig_backend) { // These backends don't support vectors yet. + .stage2_aarch64, .stage2_powerpc, .stage2_riscv64, => false, @@ -4482,7 +4483,7 @@ pub fn doNotOptimizeAway(val: anytype) void { ); asm volatile ("" : - : [val2] "r" (val2), + : [_] "r" (val2), ); } else doNotOptimizeAway(&val); }, @@ -4490,7 +4491,7 @@ pub fn doNotOptimizeAway(val: anytype) void { if ((t.float.bits == 32 or t.float.bits == 64) and builtin.zig_backend != .stage2_c) { asm volatile ("" : - : [val] "rm" (val), + : [_] "rm" (val), ); } else doNotOptimizeAway(&val); }, @@ -4500,7 +4501,7 @@ pub fn doNotOptimizeAway(val: anytype) void { } else { asm volatile ("" : - : [val] "m" (val), + : [_] "m" (val), : .{ .memory = true }); } }, diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 75494145b9..a02451c0fd 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -503,7 +503,6 @@ pub var elf_aux_maybe: ?[*]std.elf.Auxv = null; /// Whether an external or internal getauxval implementation is used. const extern_getauxval = switch (builtin.zig_backend) { // Calling extern functions is not yet supported with these backends - .stage2_aarch64, .stage2_arm, .stage2_powerpc, .stage2_riscv64, diff --git a/lib/std/start.zig b/lib/std/start.zig index 22ccda1e40..43355d34f4 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -101,17 +101,11 @@ comptime { // Simplified start code for stage2 until it supports more language features /// fn main2() callconv(.c) c_int { - root.main(); - return 0; + return callMain(); } fn _start2() callconv(.withStackAlign(.c, 1)) noreturn { - callMain2(); -} - -fn callMain2() noreturn { - root.main(); - exit2(0); + std.posix.exit(callMain()); } fn spirvMain2() callconv(.kernel) void { @@ -119,51 +113,7 @@ fn spirvMain2() callconv(.kernel) void { } fn wWinMainCRTStartup2() callconv(.c) noreturn { - root.main(); - exit2(0); -} - -fn exit2(code: usize) noreturn { - switch (native_os) { - .linux => switch (builtin.cpu.arch) { - .x86_64 => { - asm volatile ("syscall" - : - : [number] "{rax}" (231), - [arg1] "{rdi}" (code), - : .{ .rcx = true, .r11 = true, .memory = true }); - }, - .arm => { - asm volatile ("svc #0" - : - : [number] "{r7}" (1), - [arg1] "{r0}" (code), - : .{ .memory = true }); - }, - .aarch64 => { - asm volatile ("svc #0" - : - : [number] "{x8}" (93), - [arg1] "{x0}" (code), - : .{ .memory = true }); - }, - .sparc64 => { - asm volatile ("ta 0x6d" - : - : [number] "{g1}" (1), - [arg1] "{o0}" (code), - : .{ .o0 = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o6 = true, .o7 = true, .memory = true }); - }, - else => @compileError("TODO"), - }, - // exits(0) - .plan9 => std.os.plan9.exits(null), - .windows => { - std.os.windows.ntdll.RtlExitUserProcess(@truncate(code)); - }, - else => @compileError("TODO"), - } - unreachable; + std.posix.exit(callMain()); } //////////////////////////////////////////////////////////////////////////////// @@ -676,10 +626,11 @@ pub inline fn callMain() u8 { const result = root.main() catch |err| { switch (builtin.zig_backend) { + .stage2_aarch64, .stage2_powerpc, .stage2_riscv64, => { - std.debug.print("error: failed with error\n", .{}); + _ = std.posix.write(std.posix.STDERR_FILENO, "error: failed with error\n") catch {}; return 1; }, else => {}, diff --git a/lib/std/testing.zig b/lib/std/testing.zig index f9027a4f47..e80e961b13 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -33,6 +33,7 @@ pub var log_level = std.log.Level.warn; // Disable printing in tests for simple backends. pub const backend_can_print = switch (builtin.zig_backend) { + .stage2_aarch64, .stage2_powerpc, .stage2_riscv64, .stage2_spirv, diff --git a/src/Compilation.zig b/src/Compilation.zig index 649288dab2..412d6a023c 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1850,7 +1850,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil // approach, since the ubsan runtime uses quite a lot of the standard library // and this reduces unnecessary bloat. const ubsan_rt_strat: RtStrat = s: { - const can_build_ubsan_rt = target_util.canBuildLibUbsanRt(target); + const can_build_ubsan_rt = target_util.canBuildLibUbsanRt(target, use_llvm, build_options.have_llvm); const want_ubsan_rt = options.want_ubsan_rt orelse (can_build_ubsan_rt and any_sanitize_c == .full and is_exe_or_dyn_lib); if (!want_ubsan_rt) break :s .none; if (options.skip_linker_dependencies) break :s .none; diff --git a/src/InternPool.zig b/src/InternPool.zig index c9036da45b..15d895aed0 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -7556,12 +7556,18 @@ fn extraFuncCoerced(ip: *const InternPool, extra: Local.Extra, extra_index: u32) fn indexToKeyBigInt(ip: *const InternPool, tid: Zcu.PerThread.Id, limb_index: u32, positive: bool) Key { const limbs_items = ip.getLocalShared(tid).getLimbs().view().items(.@"0"); const int: Int = @bitCast(limbs_items[limb_index..][0..Int.limbs_items_len].*); + const big_int: BigIntConst = .{ + .limbs = limbs_items[limb_index + Int.limbs_items_len ..][0..int.limbs_len], + .positive = positive, + }; return .{ .int = .{ .ty = int.ty, - .storage = .{ .big_int = .{ - .limbs = limbs_items[limb_index + Int.limbs_items_len ..][0..int.limbs_len], - .positive = positive, - } }, + .storage = if (big_int.toInt(u64)) |x| + .{ .u64 = x } + else |_| if (big_int.toInt(i64)) |x| + .{ .i64 = x } + else |_| + .{ .big_int = big_int }, } }; } diff --git a/src/Sema.zig b/src/Sema.zig index d2e3e32214..788107f786 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -16522,7 +16522,7 @@ fn zirAsm( break :empty try sema.structInitEmpty(block, clobbers_ty, src, src); } else try sema.resolveInst(extra.data.clobbers); // Already coerced by AstGen. const clobbers_val = try sema.resolveConstDefinedValue(block, src, clobbers, .{ .simple = .clobber }); - needed_capacity += (asm_source.len + 3) / 4; + needed_capacity += asm_source.len / 4 + 1; const gpa = sema.gpa; try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity); @@ -16562,7 +16562,8 @@ fn zirAsm( { const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); @memcpy(buffer[0..asm_source.len], asm_source); - sema.air_extra.items.len += (asm_source.len + 3) / 4; + buffer[asm_source.len] = 0; + sema.air_extra.items.len += asm_source.len / 4 + 1; } return asm_air; } @@ -24846,7 +24847,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins }, .@"packed" => { const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) + - (if (zcu.typeToStruct(parent_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, field_index) else 0) - + (if (zcu.typeToStruct(parent_ty)) |struct_obj| zcu.structPackedFieldBitOffset(struct_obj, field_index) else 0) - actual_field_ptr_info.packed_offset.bit_offset), 8) catch return sema.fail(block, inst_src, "pointer bit-offset mismatch", .{}); actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (byte_offset > 0) @@ -24873,7 +24874,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins // Logic lifted from type computation above - I'm just assuming it's correct. // `catch unreachable` since error case handled above. const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) + - pt.structPackedFieldBitOffset(zcu.typeToStruct(parent_ty).?, field_index) - + zcu.structPackedFieldBitOffset(zcu.typeToStruct(parent_ty).?, field_index) - actual_field_ptr_info.packed_offset.bit_offset), 8) catch unreachable; const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty); break :result Air.internedToRef(parent_ptr_val.toIntern()); diff --git a/src/Type.zig b/src/Type.zig index a199811c8e..9316bec11e 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -4166,7 +4166,7 @@ pub const generic_poison: Type = .{ .ip_index = .generic_poison_type }; pub fn smallestUnsignedBits(max: u64) u16 { return switch (max) { 0 => 0, - else => 1 + std.math.log2_int(u64, max), + else => @as(u16, 1) + std.math.log2_int(u64, max), }; } diff --git a/src/Zcu.zig b/src/Zcu.zig index d337f0b943..df35777231 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -3891,6 +3891,29 @@ pub fn typeToPackedStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructTyp return s; } +/// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets +/// into the packed struct InternPool data rather than computing this on the +/// fly, however it was found to perform worse when measured on real world +/// projects. +pub fn structPackedFieldBitOffset( + zcu: *Zcu, + struct_type: InternPool.LoadedStructType, + field_index: u32, +) u16 { + const ip = &zcu.intern_pool; + assert(struct_type.layout == .@"packed"); + assert(struct_type.haveLayout(ip)); + var bit_sum: u64 = 0; + for (0..struct_type.field_types.len) |i| { + if (i == field_index) { + return @intCast(bit_sum); + } + const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); + bit_sum += field_ty.bitSize(zcu); + } + unreachable; // index out of bounds +} + pub fn typeToUnion(zcu: *const Zcu, ty: Type) ?InternPool.LoadedUnionType { if (ty.ip_index == .none) return null; const ip = &zcu.intern_pool; @@ -4436,11 +4459,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu else => false, }, .stage2_aarch64 => switch (cc) { - .aarch64_aapcs, - .aarch64_aapcs_darwin, - .aarch64_aapcs_win, - => |opts| opts.incoming_stack_alignment == null, - .naked => true, + .aarch64_aapcs, .aarch64_aapcs_darwin, .naked => true, else => false, }, .stage2_x86 => switch (cc) { diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 26f008e1c8..119b742a89 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -3737,30 +3737,6 @@ pub fn intBitsForValue(pt: Zcu.PerThread, val: Value, sign: bool) u16 { } } -/// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets -/// into the packed struct InternPool data rather than computing this on the -/// fly, however it was found to perform worse when measured on real world -/// projects. -pub fn structPackedFieldBitOffset( - pt: Zcu.PerThread, - struct_type: InternPool.LoadedStructType, - field_index: u32, -) u16 { - const zcu = pt.zcu; - const ip = &zcu.intern_pool; - assert(struct_type.layout == .@"packed"); - assert(struct_type.haveLayout(ip)); - var bit_sum: u64 = 0; - for (0..struct_type.field_types.len) |i| { - if (i == field_index) { - return @intCast(bit_sum); - } - const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); - bit_sum += field_ty.bitSize(zcu); - } - unreachable; // index out of bounds -} - pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Error!Type { const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -4381,8 +4357,11 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e try air.legalize(pt, features); } - var liveness: Air.Liveness = try .analyze(zcu, air.*, ip); - defer liveness.deinit(gpa); + var liveness: ?Air.Liveness = if (codegen.wantsLiveness(pt, nav)) + try .analyze(zcu, air.*, ip) + else + null; + defer if (liveness) |*l| l.deinit(gpa); if (build_options.enable_debug_extensions and comp.verbose_air) { const stderr = std.debug.lockStderrWriter(&.{}); @@ -4392,12 +4371,12 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e stderr.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)}) catch {}; } - if (std.debug.runtime_safety) { + if (std.debug.runtime_safety) verify_liveness: { var verify: Air.Liveness.Verify = .{ .gpa = gpa, .zcu = zcu, .air = air.*, - .liveness = liveness, + .liveness = liveness orelse break :verify_liveness, .intern_pool = ip, }; defer verify.deinit(); diff --git a/src/arch/aarch64/bits.zig b/src/arch/aarch64/bits.zig deleted file mode 100644 index 9c4227a712..0000000000 --- a/src/arch/aarch64/bits.zig +++ /dev/null @@ -1,2063 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const assert = std.debug.assert; -const testing = std.testing; - -/// Disjoint sets of registers. Every register must belong to -/// exactly one register class. -pub const RegisterClass = enum { - general_purpose, - stack_pointer, - floating_point, -}; - -/// Registers in the AArch64 instruction set -pub const Register = enum(u8) { - // zig fmt: off - // 64-bit general-purpose registers - x0, x1, x2, x3, x4, x5, x6, x7, - x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, - x24, x25, x26, x27, x28, x29, x30, xzr, - - // 32-bit general-purpose registers - w0, w1, w2, w3, w4, w5, w6, w7, - w8, w9, w10, w11, w12, w13, w14, w15, - w16, w17, w18, w19, w20, w21, w22, w23, - w24, w25, w26, w27, w28, w29, w30, wzr, - - // Stack pointer - sp, wsp, - - // 128-bit floating-point registers - q0, q1, q2, q3, q4, q5, q6, q7, - q8, q9, q10, q11, q12, q13, q14, q15, - q16, q17, q18, q19, q20, q21, q22, q23, - q24, q25, q26, q27, q28, q29, q30, q31, - - // 64-bit floating-point registers - d0, d1, d2, d3, d4, d5, d6, d7, - d8, d9, d10, d11, d12, d13, d14, d15, - d16, d17, d18, d19, d20, d21, d22, d23, - d24, d25, d26, d27, d28, d29, d30, d31, - - // 32-bit floating-point registers - s0, s1, s2, s3, s4, s5, s6, s7, - s8, s9, s10, s11, s12, s13, s14, s15, - s16, s17, s18, s19, s20, s21, s22, s23, - s24, s25, s26, s27, s28, s29, s30, s31, - - // 16-bit floating-point registers - h0, h1, h2, h3, h4, h5, h6, h7, - h8, h9, h10, h11, h12, h13, h14, h15, - h16, h17, h18, h19, h20, h21, h22, h23, - h24, h25, h26, h27, h28, h29, h30, h31, - - // 8-bit floating-point registers - b0, b1, b2, b3, b4, b5, b6, b7, - b8, b9, b10, b11, b12, b13, b14, b15, - b16, b17, b18, b19, b20, b21, b22, b23, - b24, b25, b26, b27, b28, b29, b30, b31, - // zig fmt: on - - pub fn class(self: Register) RegisterClass { - return switch (@intFromEnum(self)) { - @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => .general_purpose, - @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => .general_purpose, - - @intFromEnum(Register.sp) => .stack_pointer, - @intFromEnum(Register.wsp) => .stack_pointer, - - @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => .floating_point, - @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => .floating_point, - @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => .floating_point, - @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => .floating_point, - @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => .floating_point, - else => unreachable, - }; - } - - pub fn id(self: Register) u6 { - return switch (@intFromEnum(self)) { - @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.x0))), - @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.w0))), - - @intFromEnum(Register.sp) => 32, - @intFromEnum(Register.wsp) => 32, - - @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.q0) + 33)), - @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.d0) + 33)), - @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.s0) + 33)), - @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.h0) + 33)), - @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.b0) + 33)), - else => unreachable, - }; - } - - pub fn enc(self: Register) u5 { - return switch (@intFromEnum(self)) { - @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.x0))), - @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.w0))), - - @intFromEnum(Register.sp) => 31, - @intFromEnum(Register.wsp) => 31, - - @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.q0))), - @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.d0))), - @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.s0))), - @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.h0))), - @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.b0))), - else => unreachable, - }; - } - - /// Returns the bit-width of the register. - pub fn size(self: Register) u8 { - return switch (@intFromEnum(self)) { - @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => 64, - @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => 32, - - @intFromEnum(Register.sp) => 64, - @intFromEnum(Register.wsp) => 32, - - @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => 128, - @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => 64, - @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => 32, - @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => 16, - @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => 8, - else => unreachable, - }; - } - - /// Convert from a general-purpose register to its 64 bit alias. - pub fn toX(self: Register) Register { - return switch (@intFromEnum(self)) { - @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.x0) + @intFromEnum(Register.x0)), - ), - @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.w0) + @intFromEnum(Register.x0)), - ), - else => unreachable, - }; - } - - /// Convert from a general-purpose register to its 32 bit alias. - pub fn toW(self: Register) Register { - return switch (@intFromEnum(self)) { - @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.x0) + @intFromEnum(Register.w0)), - ), - @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.w0) + @intFromEnum(Register.w0)), - ), - else => unreachable, - }; - } - - /// Convert from a floating-point register to its 128 bit alias. - pub fn toQ(self: Register) Register { - return switch (@intFromEnum(self)) { - @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.q0)), - ), - @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.q0)), - ), - @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.q0)), - ), - @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.q0)), - ), - @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.q0)), - ), - else => unreachable, - }; - } - - /// Convert from a floating-point register to its 64 bit alias. - pub fn toD(self: Register) Register { - return switch (@intFromEnum(self)) { - @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.d0)), - ), - @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.d0)), - ), - @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.d0)), - ), - @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.d0)), - ), - @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.d0)), - ), - else => unreachable, - }; - } - - /// Convert from a floating-point register to its 32 bit alias. - pub fn toS(self: Register) Register { - return switch (@intFromEnum(self)) { - @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.s0)), - ), - @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.s0)), - ), - @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.s0)), - ), - @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.s0)), - ), - @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.s0)), - ), - else => unreachable, - }; - } - - /// Convert from a floating-point register to its 16 bit alias. - pub fn toH(self: Register) Register { - return switch (@intFromEnum(self)) { - @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.h0)), - ), - @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.h0)), - ), - @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.h0)), - ), - @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.h0)), - ), - @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.h0)), - ), - else => unreachable, - }; - } - - /// Convert from a floating-point register to its 8 bit alias. - pub fn toB(self: Register) Register { - return switch (@intFromEnum(self)) { - @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.b0)), - ), - @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.b0)), - ), - @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.b0)), - ), - @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.b0)), - ), - @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as( - Register, - @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.b0)), - ), - else => unreachable, - }; - } - - pub fn dwarfNum(self: Register) u5 { - return self.enc(); - } -}; - -test "Register.enc" { - try testing.expectEqual(@as(u5, 0), Register.x0.enc()); - try testing.expectEqual(@as(u5, 0), Register.w0.enc()); - - try testing.expectEqual(@as(u5, 31), Register.xzr.enc()); - try testing.expectEqual(@as(u5, 31), Register.wzr.enc()); - - try testing.expectEqual(@as(u5, 31), Register.sp.enc()); - try testing.expectEqual(@as(u5, 31), Register.sp.enc()); -} - -test "Register.size" { - try testing.expectEqual(@as(u8, 64), Register.x19.size()); - try testing.expectEqual(@as(u8, 32), Register.w3.size()); -} - -test "Register.toX/toW" { - try testing.expectEqual(Register.x0, Register.w0.toX()); - try testing.expectEqual(Register.x0, Register.x0.toX()); - - try testing.expectEqual(Register.w3, Register.w3.toW()); - try testing.expectEqual(Register.w3, Register.x3.toW()); -} - -/// Represents an instruction in the AArch64 instruction set -pub const Instruction = union(enum) { - move_wide_immediate: packed struct { - rd: u5, - imm16: u16, - hw: u2, - fixed: u6 = 0b100101, - opc: u2, - sf: u1, - }, - pc_relative_address: packed struct { - rd: u5, - immhi: u19, - fixed: u5 = 0b10000, - immlo: u2, - op: u1, - }, - load_store_register: packed struct { - rt: u5, - rn: u5, - offset: u12, - opc: u2, - op1: u2, - v: u1, - fixed: u3 = 0b111, - size: u2, - }, - load_store_register_pair: packed struct { - rt1: u5, - rn: u5, - rt2: u5, - imm7: u7, - load: u1, - encoding: u2, - fixed: u5 = 0b101_0_0, - opc: u2, - }, - load_literal: packed struct { - rt: u5, - imm19: u19, - fixed: u6 = 0b011_0_00, - opc: u2, - }, - exception_generation: packed struct { - ll: u2, - op2: u3, - imm16: u16, - opc: u3, - fixed: u8 = 0b1101_0100, - }, - unconditional_branch_register: packed struct { - op4: u5, - rn: u5, - op3: u6, - op2: u5, - opc: u4, - fixed: u7 = 0b1101_011, - }, - unconditional_branch_immediate: packed struct { - imm26: u26, - fixed: u5 = 0b00101, - op: u1, - }, - no_operation: packed struct { - fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111, - }, - logical_shifted_register: packed struct { - rd: u5, - rn: u5, - imm6: u6, - rm: u5, - n: u1, - shift: u2, - fixed: u5 = 0b01010, - opc: u2, - sf: u1, - }, - add_subtract_immediate: packed struct { - rd: u5, - rn: u5, - imm12: u12, - sh: u1, - fixed: u6 = 0b100010, - s: u1, - op: u1, - sf: u1, - }, - logical_immediate: packed struct { - rd: u5, - rn: u5, - imms: u6, - immr: u6, - n: u1, - fixed: u6 = 0b100100, - opc: u2, - sf: u1, - }, - bitfield: packed struct { - rd: u5, - rn: u5, - imms: u6, - immr: u6, - n: u1, - fixed: u6 = 0b100110, - opc: u2, - sf: u1, - }, - add_subtract_shifted_register: packed struct { - rd: u5, - rn: u5, - imm6: u6, - rm: u5, - fixed_1: u1 = 0b0, - shift: u2, - fixed_2: u5 = 0b01011, - s: u1, - op: u1, - sf: u1, - }, - add_subtract_extended_register: packed struct { - rd: u5, - rn: u5, - imm3: u3, - option: u3, - rm: u5, - fixed: u8 = 0b01011_00_1, - s: u1, - op: u1, - sf: u1, - }, - conditional_branch: struct { - cond: u4, - o0: u1, - imm19: u19, - o1: u1, - fixed: u7 = 0b0101010, - }, - compare_and_branch: struct { - rt: u5, - imm19: u19, - op: u1, - fixed: u6 = 0b011010, - sf: u1, - }, - conditional_select: struct { - rd: u5, - rn: u5, - op2: u2, - cond: u4, - rm: u5, - fixed: u8 = 0b11010100, - s: u1, - op: u1, - sf: u1, - }, - data_processing_3_source: packed struct { - rd: u5, - rn: u5, - ra: u5, - o0: u1, - rm: u5, - op31: u3, - fixed: u5 = 0b11011, - op54: u2, - sf: u1, - }, - data_processing_2_source: packed struct { - rd: u5, - rn: u5, - opcode: u6, - rm: u5, - fixed_1: u8 = 0b11010110, - s: u1, - fixed_2: u1 = 0b0, - sf: u1, - }, - - pub const Condition = enum(u4) { - /// Integer: Equal - /// Floating point: Equal - eq, - /// Integer: Not equal - /// Floating point: Not equal or unordered - ne, - /// Integer: Carry set - /// Floating point: Greater than, equal, or unordered - cs, - /// Integer: Carry clear - /// Floating point: Less than - cc, - /// Integer: Minus, negative - /// Floating point: Less than - mi, - /// Integer: Plus, positive or zero - /// Floating point: Greater than, equal, or unordered - pl, - /// Integer: Overflow - /// Floating point: Unordered - vs, - /// Integer: No overflow - /// Floating point: Ordered - vc, - /// Integer: Unsigned higher - /// Floating point: Greater than, or unordered - hi, - /// Integer: Unsigned lower or same - /// Floating point: Less than or equal - ls, - /// Integer: Signed greater than or equal - /// Floating point: Greater than or equal - ge, - /// Integer: Signed less than - /// Floating point: Less than, or unordered - lt, - /// Integer: Signed greater than - /// Floating point: Greater than - gt, - /// Integer: Signed less than or equal - /// Floating point: Less than, equal, or unordered - le, - /// Integer: Always - /// Floating point: Always - al, - /// Integer: Always - /// Floating point: Always - nv, - - /// Converts a std.math.CompareOperator into a condition flag, - /// i.e. returns the condition that is true iff the result of the - /// comparison is true. Assumes signed comparison - pub fn fromCompareOperatorSigned(op: std.math.CompareOperator) Condition { - return switch (op) { - .gte => .ge, - .gt => .gt, - .neq => .ne, - .lt => .lt, - .lte => .le, - .eq => .eq, - }; - } - - /// Converts a std.math.CompareOperator into a condition flag, - /// i.e. returns the condition that is true iff the result of the - /// comparison is true. Assumes unsigned comparison - pub fn fromCompareOperatorUnsigned(op: std.math.CompareOperator) Condition { - return switch (op) { - .gte => .cs, - .gt => .hi, - .neq => .ne, - .lt => .cc, - .lte => .ls, - .eq => .eq, - }; - } - - /// Returns the condition which is true iff the given condition is - /// false (if such a condition exists) - pub fn negate(cond: Condition) Condition { - return switch (cond) { - .eq => .ne, - .ne => .eq, - .cs => .cc, - .cc => .cs, - .mi => .pl, - .pl => .mi, - .vs => .vc, - .vc => .vs, - .hi => .ls, - .ls => .hi, - .ge => .lt, - .lt => .ge, - .gt => .le, - .le => .gt, - .al => unreachable, - .nv => unreachable, - }; - } - }; - - pub fn toU32(self: Instruction) u32 { - return switch (self) { - .move_wide_immediate => |v| @as(u32, @bitCast(v)), - .pc_relative_address => |v| @as(u32, @bitCast(v)), - .load_store_register => |v| @as(u32, @bitCast(v)), - .load_store_register_pair => |v| @as(u32, @bitCast(v)), - .load_literal => |v| @as(u32, @bitCast(v)), - .exception_generation => |v| @as(u32, @bitCast(v)), - .unconditional_branch_register => |v| @as(u32, @bitCast(v)), - .unconditional_branch_immediate => |v| @as(u32, @bitCast(v)), - .no_operation => |v| @as(u32, @bitCast(v)), - .logical_shifted_register => |v| @as(u32, @bitCast(v)), - .add_subtract_immediate => |v| @as(u32, @bitCast(v)), - .logical_immediate => |v| @as(u32, @bitCast(v)), - .bitfield => |v| @as(u32, @bitCast(v)), - .add_subtract_shifted_register => |v| @as(u32, @bitCast(v)), - .add_subtract_extended_register => |v| @as(u32, @bitCast(v)), - // TODO once packed structs work, this can be refactored - .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25), - .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31), - .conditional_select => |v| @as(u32, v.rd) | @as(u32, v.rn) << 5 | @as(u32, v.op2) << 10 | @as(u32, v.cond) << 12 | @as(u32, v.rm) << 16 | @as(u32, v.fixed) << 21 | @as(u32, v.s) << 29 | @as(u32, v.op) << 30 | @as(u32, v.sf) << 31, - .data_processing_3_source => |v| @as(u32, @bitCast(v)), - .data_processing_2_source => |v| @as(u32, @bitCast(v)), - }; - } - - fn moveWideImmediate( - opc: u2, - rd: Register, - imm16: u16, - shift: u6, - ) Instruction { - assert(shift % 16 == 0); - assert(!(rd.size() == 32 and shift > 16)); - assert(!(rd.size() == 64 and shift > 48)); - - return Instruction{ - .move_wide_immediate = .{ - .rd = rd.enc(), - .imm16 = imm16, - .hw = @as(u2, @intCast(shift / 16)), - .opc = opc, - .sf = switch (rd.size()) { - 32 => 0, - 64 => 1, - else => unreachable, // unexpected register size - }, - }, - }; - } - - fn pcRelativeAddress(rd: Register, imm21: i21, op: u1) Instruction { - assert(rd.size() == 64); - const imm21_u = @as(u21, @bitCast(imm21)); - return Instruction{ - .pc_relative_address = .{ - .rd = rd.enc(), - .immlo = @as(u2, @truncate(imm21_u)), - .immhi = @as(u19, @truncate(imm21_u >> 2)), - .op = op, - }, - }; - } - - pub const LoadStoreOffsetImmediate = union(enum) { - post_index: i9, - pre_index: i9, - unsigned: u12, - }; - - pub const LoadStoreOffsetRegister = struct { - rm: u5, - shift: union(enum) { - uxtw: u2, - lsl: u2, - sxtw: u2, - sxtx: u2, - }, - }; - - /// Represents the offset operand of a load or store instruction. - /// Data can be loaded from memory with either an immediate offset - /// or an offset that is stored in some register. - pub const LoadStoreOffset = union(enum) { - immediate: LoadStoreOffsetImmediate, - register: LoadStoreOffsetRegister, - - pub const none = LoadStoreOffset{ - .immediate = .{ .unsigned = 0 }, - }; - - pub fn toU12(self: LoadStoreOffset) u12 { - return switch (self) { - .immediate => |imm_type| switch (imm_type) { - .post_index => |v| (@as(u12, @intCast(@as(u9, @bitCast(v)))) << 2) + 1, - .pre_index => |v| (@as(u12, @intCast(@as(u9, @bitCast(v)))) << 2) + 3, - .unsigned => |v| v, - }, - .register => |r| switch (r.shift) { - .uxtw => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 16 + 2050, - .lsl => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 24 + 2050, - .sxtw => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 48 + 2050, - .sxtx => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 56 + 2050, - }, - }; - } - - pub fn imm(offset: u12) LoadStoreOffset { - return .{ - .immediate = .{ .unsigned = offset }, - }; - } - - pub fn imm_post_index(offset: i9) LoadStoreOffset { - return .{ - .immediate = .{ .post_index = offset }, - }; - } - - pub fn imm_pre_index(offset: i9) LoadStoreOffset { - return .{ - .immediate = .{ .pre_index = offset }, - }; - } - - pub fn reg(rm: Register) LoadStoreOffset { - return .{ - .register = .{ - .rm = rm.enc(), - .shift = .{ - .lsl = 0, - }, - }, - }; - } - - pub fn reg_uxtw(rm: Register, shift: u2) LoadStoreOffset { - assert(rm.size() == 32 and (shift == 0 or shift == 2)); - return .{ - .register = .{ - .rm = rm.enc(), - .shift = .{ - .uxtw = shift, - }, - }, - }; - } - - pub fn reg_lsl(rm: Register, shift: u2) LoadStoreOffset { - assert(rm.size() == 64 and (shift == 0 or shift == 3)); - return .{ - .register = .{ - .rm = rm.enc(), - .shift = .{ - .lsl = shift, - }, - }, - }; - } - - pub fn reg_sxtw(rm: Register, shift: u2) LoadStoreOffset { - assert(rm.size() == 32 and (shift == 0 or shift == 2)); - return .{ - .register = .{ - .rm = rm.enc(), - .shift = .{ - .sxtw = shift, - }, - }, - }; - } - - pub fn reg_sxtx(rm: Register, shift: u2) LoadStoreOffset { - assert(rm.size() == 64 and (shift == 0 or shift == 3)); - return .{ - .register = .{ - .rm = rm.enc(), - .shift = .{ - .sxtx = shift, - }, - }, - }; - } - }; - - /// Which kind of load/store to perform - const LoadStoreVariant = enum { - /// 32 bits or 64 bits - str, - /// 8 bits, zero-extended - strb, - /// 16 bits, zero-extended - strh, - /// 32 bits or 64 bits - ldr, - /// 8 bits, zero-extended - ldrb, - /// 16 bits, zero-extended - ldrh, - /// 8 bits, sign extended - ldrsb, - /// 16 bits, sign extended - ldrsh, - /// 32 bits, sign extended - ldrsw, - }; - - fn loadStoreRegister( - rt: Register, - rn: Register, - offset: LoadStoreOffset, - variant: LoadStoreVariant, - ) Instruction { - assert(rn.size() == 64); - assert(rn.id() != Register.xzr.id()); - - const off = offset.toU12(); - - const op1: u2 = blk: { - switch (offset) { - .immediate => |imm| switch (imm) { - .unsigned => break :blk 0b01, - else => {}, - }, - else => {}, - } - break :blk 0b00; - }; - - const opc: u2 = blk: { - switch (variant) { - .ldr, .ldrh, .ldrb => break :blk 0b01, - .str, .strh, .strb => break :blk 0b00, - .ldrsb, - .ldrsh, - => switch (rt.size()) { - 32 => break :blk 0b11, - 64 => break :blk 0b10, - else => unreachable, // unexpected register size - }, - .ldrsw => break :blk 0b10, - } - }; - - const size: u2 = blk: { - switch (variant) { - .ldr, .str => switch (rt.size()) { - 32 => break :blk 0b10, - 64 => break :blk 0b11, - else => unreachable, // unexpected register size - }, - .ldrsw => break :blk 0b10, - .ldrh, .ldrsh, .strh => break :blk 0b01, - .ldrb, .ldrsb, .strb => break :blk 0b00, - } - }; - - return Instruction{ - .load_store_register = .{ - .rt = rt.enc(), - .rn = rn.enc(), - .offset = off, - .opc = opc, - .op1 = op1, - .v = 0, - .size = size, - }, - }; - } - - fn loadStoreRegisterPair( - rt1: Register, - rt2: Register, - rn: Register, - offset: i9, - encoding: u2, - load: bool, - ) Instruction { - assert(rn.size() == 64); - assert(rn.id() != Register.xzr.id()); - - switch (rt1.size()) { - 32 => { - assert(-256 <= offset and offset <= 252); - const imm7 = @as(u7, @truncate(@as(u9, @bitCast(offset >> 2)))); - return Instruction{ - .load_store_register_pair = .{ - .rt1 = rt1.enc(), - .rn = rn.enc(), - .rt2 = rt2.enc(), - .imm7 = imm7, - .load = @intFromBool(load), - .encoding = encoding, - .opc = 0b00, - }, - }; - }, - 64 => { - assert(-512 <= offset and offset <= 504); - const imm7 = @as(u7, @truncate(@as(u9, @bitCast(offset >> 3)))); - return Instruction{ - .load_store_register_pair = .{ - .rt1 = rt1.enc(), - .rn = rn.enc(), - .rt2 = rt2.enc(), - .imm7 = imm7, - .load = @intFromBool(load), - .encoding = encoding, - .opc = 0b10, - }, - }; - }, - else => unreachable, // unexpected register size - } - } - - fn loadLiteral(rt: Register, imm19: u19) Instruction { - return Instruction{ - .load_literal = .{ - .rt = rt.enc(), - .imm19 = imm19, - .opc = switch (rt.size()) { - 32 => 0b00, - 64 => 0b01, - else => unreachable, // unexpected register size - }, - }, - }; - } - - fn exceptionGeneration( - opc: u3, - op2: u3, - ll: u2, - imm16: u16, - ) Instruction { - return Instruction{ - .exception_generation = .{ - .ll = ll, - .op2 = op2, - .imm16 = imm16, - .opc = opc, - }, - }; - } - - fn unconditionalBranchRegister( - opc: u4, - op2: u5, - op3: u6, - rn: Register, - op4: u5, - ) Instruction { - assert(rn.size() == 64); - - return Instruction{ - .unconditional_branch_register = .{ - .op4 = op4, - .rn = rn.enc(), - .op3 = op3, - .op2 = op2, - .opc = opc, - }, - }; - } - - fn unconditionalBranchImmediate( - op: u1, - offset: i28, - ) Instruction { - return Instruction{ - .unconditional_branch_immediate = .{ - .imm26 = @as(u26, @bitCast(@as(i26, @intCast(offset >> 2)))), - .op = op, - }, - }; - } - - pub const LogicalShiftedRegisterShift = enum(u2) { lsl, lsr, asr, ror }; - - fn logicalShiftedRegister( - opc: u2, - n: u1, - rd: Register, - rn: Register, - rm: Register, - shift: LogicalShiftedRegisterShift, - amount: u6, - ) Instruction { - assert(rd.size() == rn.size()); - assert(rd.size() == rm.size()); - if (rd.size() == 32) assert(amount < 32); - - return Instruction{ - .logical_shifted_register = .{ - .rd = rd.enc(), - .rn = rn.enc(), - .imm6 = amount, - .rm = rm.enc(), - .n = n, - .shift = @intFromEnum(shift), - .opc = opc, - .sf = switch (rd.size()) { - 32 => 0b0, - 64 => 0b1, - else => unreachable, - }, - }, - }; - } - - fn addSubtractImmediate( - op: u1, - s: u1, - rd: Register, - rn: Register, - imm12: u12, - shift: bool, - ) Instruction { - assert(rd.size() == rn.size()); - assert(rn.id() != Register.xzr.id()); - - return Instruction{ - .add_subtract_immediate = .{ - .rd = rd.enc(), - .rn = rn.enc(), - .imm12 = imm12, - .sh = @intFromBool(shift), - .s = s, - .op = op, - .sf = switch (rd.size()) { - 32 => 0b0, - 64 => 0b1, - else => unreachable, // unexpected register size - }, - }, - }; - } - - fn logicalImmediate( - opc: u2, - rd: Register, - rn: Register, - imms: u6, - immr: u6, - n: u1, - ) Instruction { - assert(rd.size() == rn.size()); - assert(!(rd.size() == 32 and n != 0)); - - return Instruction{ - .logical_immediate = .{ - .rd = rd.enc(), - .rn = rn.enc(), - .imms = imms, - .immr = immr, - .n = n, - .opc = opc, - .sf = switch (rd.size()) { - 32 => 0b0, - 64 => 0b1, - else => unreachable, // unexpected register size - }, - }, - }; - } - - fn initBitfield( - opc: u2, - n: u1, - rd: Register, - rn: Register, - immr: u6, - imms: u6, - ) Instruction { - assert(rd.size() == rn.size()); - assert(!(rd.size() == 64 and n != 1)); - assert(!(rd.size() == 32 and (n != 0 or immr >> 5 != 0 or immr >> 5 != 0))); - - return Instruction{ - .bitfield = .{ - .rd = rd.enc(), - .rn = rn.enc(), - .imms = imms, - .immr = immr, - .n = n, - .opc = opc, - .sf = switch (rd.size()) { - 32 => 0b0, - 64 => 0b1, - else => unreachable, // unexpected register size - }, - }, - }; - } - - pub const AddSubtractShiftedRegisterShift = enum(u2) { lsl, lsr, asr, _ }; - - fn addSubtractShiftedRegister( - op: u1, - s: u1, - shift: AddSubtractShiftedRegisterShift, - rd: Register, - rn: Register, - rm: Register, - imm6: u6, - ) Instruction { - assert(rd.size() == rn.size()); - assert(rd.size() == rm.size()); - - return Instruction{ - .add_subtract_shifted_register = .{ - .rd = rd.enc(), - .rn = rn.enc(), - .imm6 = imm6, - .rm = rm.enc(), - .shift = @intFromEnum(shift), - .s = s, - .op = op, - .sf = switch (rd.size()) { - 32 => 0b0, - 64 => 0b1, - else => unreachable, // unexpected register size - }, - }, - }; - } - - pub const AddSubtractExtendedRegisterOption = enum(u3) { - uxtb, - uxth, - uxtw, - uxtx, // serves also as lsl - sxtb, - sxth, - sxtw, - sxtx, - }; - - fn addSubtractExtendedRegister( - op: u1, - s: u1, - rd: Register, - rn: Register, - rm: Register, - extend: AddSubtractExtendedRegisterOption, - imm3: u3, - ) Instruction { - return Instruction{ - .add_subtract_extended_register = .{ - .rd = rd.enc(), - .rn = rn.enc(), - .imm3 = imm3, - .option = @intFromEnum(extend), - .rm = rm.enc(), - .s = s, - .op = op, - .sf = switch (rd.size()) { - 32 => 0b0, - 64 => 0b1, - else => unreachable, // unexpected register size - }, - }, - }; - } - - fn conditionalBranch( - o0: u1, - o1: u1, - cond: Condition, - offset: i21, - ) Instruction { - assert(offset & 0b11 == 0b00); - - return Instruction{ - .conditional_branch = .{ - .cond = @intFromEnum(cond), - .o0 = o0, - .imm19 = @as(u19, @bitCast(@as(i19, @intCast(offset >> 2)))), - .o1 = o1, - }, - }; - } - - fn compareAndBranch( - op: u1, - rt: Register, - offset: i21, - ) Instruction { - assert(offset & 0b11 == 0b00); - - return Instruction{ - .compare_and_branch = .{ - .rt = rt.enc(), - .imm19 = @as(u19, @bitCast(@as(i19, @intCast(offset >> 2)))), - .op = op, - .sf = switch (rt.size()) { - 32 => 0b0, - 64 => 0b1, - else => unreachable, // unexpected register size - }, - }, - }; - } - - fn conditionalSelect( - op2: u2, - op: u1, - s: u1, - rd: Register, - rn: Register, - rm: Register, - cond: Condition, - ) Instruction { - assert(rd.size() == rn.size()); - assert(rd.size() == rm.size()); - - return Instruction{ - .conditional_select = .{ - .rd = rd.enc(), - .rn = rn.enc(), - .op2 = op2, - .cond = @intFromEnum(cond), - .rm = rm.enc(), - .s = s, - .op = op, - .sf = switch (rd.size()) { - 32 => 0b0, - 64 => 0b1, - else => unreachable, // unexpected register size - }, - }, - }; - } - - fn dataProcessing3Source( - op54: u2, - op31: u3, - o0: u1, - rd: Register, - rn: Register, - rm: Register, - ra: Register, - ) Instruction { - return Instruction{ - .data_processing_3_source = .{ - .rd = rd.enc(), - .rn = rn.enc(), - .ra = ra.enc(), - .o0 = o0, - .rm = rm.enc(), - .op31 = op31, - .op54 = op54, - .sf = switch (rd.size()) { - 32 => 0b0, - 64 => 0b1, - else => unreachable, // unexpected register size - }, - }, - }; - } - - fn dataProcessing2Source( - s: u1, - opcode: u6, - rd: Register, - rn: Register, - rm: Register, - ) Instruction { - assert(rd.size() == rn.size()); - assert(rd.size() == rm.size()); - - return Instruction{ - .data_processing_2_source = .{ - .rd = rd.enc(), - .rn = rn.enc(), - .opcode = opcode, - .rm = rm.enc(), - .s = s, - .sf = switch (rd.size()) { - 32 => 0b0, - 64 => 0b1, - else => unreachable, // unexpected register size - }, - }, - }; - } - - // Helper functions for assembly syntax functions - - // Move wide (immediate) - - pub fn movn(rd: Register, imm16: u16, shift: u6) Instruction { - return moveWideImmediate(0b00, rd, imm16, shift); - } - - pub fn movz(rd: Register, imm16: u16, shift: u6) Instruction { - return moveWideImmediate(0b10, rd, imm16, shift); - } - - pub fn movk(rd: Register, imm16: u16, shift: u6) Instruction { - return moveWideImmediate(0b11, rd, imm16, shift); - } - - // PC relative address - - pub fn adr(rd: Register, imm21: i21) Instruction { - return pcRelativeAddress(rd, imm21, 0b0); - } - - pub fn adrp(rd: Register, imm21: i21) Instruction { - return pcRelativeAddress(rd, imm21, 0b1); - } - - // Load or store register - - pub fn ldrLiteral(rt: Register, literal: u19) Instruction { - return loadLiteral(rt, literal); - } - - pub fn ldr(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { - return loadStoreRegister(rt, rn, offset, .ldr); - } - - pub fn ldrh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { - return loadStoreRegister(rt, rn, offset, .ldrh); - } - - pub fn ldrb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { - return loadStoreRegister(rt, rn, offset, .ldrb); - } - - pub fn ldrsb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { - return loadStoreRegister(rt, rn, offset, .ldrsb); - } - - pub fn ldrsh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { - return loadStoreRegister(rt, rn, offset, .ldrsh); - } - - pub fn ldrsw(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { - return loadStoreRegister(rt, rn, offset, .ldrsw); - } - - pub fn str(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { - return loadStoreRegister(rt, rn, offset, .str); - } - - pub fn strh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { - return loadStoreRegister(rt, rn, offset, .strh); - } - - pub fn strb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { - return loadStoreRegister(rt, rn, offset, .strb); - } - - // Load or store pair of registers - - pub const LoadStorePairOffset = struct { - encoding: enum(u2) { - post_index = 0b01, - signed = 0b10, - pre_index = 0b11, - }, - offset: i9, - - pub fn none() LoadStorePairOffset { - return .{ .encoding = .signed, .offset = 0 }; - } - - pub fn post_index(imm: i9) LoadStorePairOffset { - return .{ .encoding = .post_index, .offset = imm }; - } - - pub fn pre_index(imm: i9) LoadStorePairOffset { - return .{ .encoding = .pre_index, .offset = imm }; - } - - pub fn signed(imm: i9) LoadStorePairOffset { - return .{ .encoding = .signed, .offset = imm }; - } - }; - - pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction { - return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @intFromEnum(offset.encoding), true); - } - - pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction { - return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, true); - } - - pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction { - return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @intFromEnum(offset.encoding), false); - } - - pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction { - return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, false); - } - - // Exception generation - - pub fn svc(imm16: u16) Instruction { - return exceptionGeneration(0b000, 0b000, 0b01, imm16); - } - - pub fn hvc(imm16: u16) Instruction { - return exceptionGeneration(0b000, 0b000, 0b10, imm16); - } - - pub fn smc(imm16: u16) Instruction { - return exceptionGeneration(0b000, 0b000, 0b11, imm16); - } - - pub fn brk(imm16: u16) Instruction { - return exceptionGeneration(0b001, 0b000, 0b00, imm16); - } - - pub fn hlt(imm16: u16) Instruction { - return exceptionGeneration(0b010, 0b000, 0b00, imm16); - } - - // Unconditional branch (register) - - pub fn br(rn: Register) Instruction { - return unconditionalBranchRegister(0b0000, 0b11111, 0b000000, rn, 0b00000); - } - - pub fn blr(rn: Register) Instruction { - return unconditionalBranchRegister(0b0001, 0b11111, 0b000000, rn, 0b00000); - } - - pub fn ret(rn: ?Register) Instruction { - return unconditionalBranchRegister(0b0010, 0b11111, 0b000000, rn orelse .x30, 0b00000); - } - - // Unconditional branch (immediate) - - pub fn b(offset: i28) Instruction { - return unconditionalBranchImmediate(0, offset); - } - - pub fn bl(offset: i28) Instruction { - return unconditionalBranchImmediate(1, offset); - } - - // Nop - - pub fn nop() Instruction { - return Instruction{ .no_operation = .{} }; - } - - // Logical (shifted register) - - pub fn andShiftedRegister( - rd: Register, - rn: Register, - rm: Register, - shift: LogicalShiftedRegisterShift, - amount: u6, - ) Instruction { - return logicalShiftedRegister(0b00, 0b0, rd, rn, rm, shift, amount); - } - - pub fn bicShiftedRegister( - rd: Register, - rn: Register, - rm: Register, - shift: LogicalShiftedRegisterShift, - amount: u6, - ) Instruction { - return logicalShiftedRegister(0b00, 0b1, rd, rn, rm, shift, amount); - } - - pub fn orrShiftedRegister( - rd: Register, - rn: Register, - rm: Register, - shift: LogicalShiftedRegisterShift, - amount: u6, - ) Instruction { - return logicalShiftedRegister(0b01, 0b0, rd, rn, rm, shift, amount); - } - - pub fn ornShiftedRegister( - rd: Register, - rn: Register, - rm: Register, - shift: LogicalShiftedRegisterShift, - amount: u6, - ) Instruction { - return logicalShiftedRegister(0b01, 0b1, rd, rn, rm, shift, amount); - } - - pub fn eorShiftedRegister( - rd: Register, - rn: Register, - rm: Register, - shift: LogicalShiftedRegisterShift, - amount: u6, - ) Instruction { - return logicalShiftedRegister(0b10, 0b0, rd, rn, rm, shift, amount); - } - - pub fn eonShiftedRegister( - rd: Register, - rn: Register, - rm: Register, - shift: LogicalShiftedRegisterShift, - amount: u6, - ) Instruction { - return logicalShiftedRegister(0b10, 0b1, rd, rn, rm, shift, amount); - } - - pub fn andsShiftedRegister( - rd: Register, - rn: Register, - rm: Register, - shift: LogicalShiftedRegisterShift, - amount: u6, - ) Instruction { - return logicalShiftedRegister(0b11, 0b0, rd, rn, rm, shift, amount); - } - - pub fn bicsShiftedRegister( - rd: Register, - rn: Register, - rm: Register, - shift: LogicalShiftedRegisterShift, - amount: u6, - ) Instruction { - return logicalShiftedRegister(0b11, 0b1, rd, rn, rm, shift, amount); - } - - // Add/subtract (immediate) - - pub fn add(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { - return addSubtractImmediate(0b0, 0b0, rd, rn, imm, shift); - } - - pub fn adds(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { - return addSubtractImmediate(0b0, 0b1, rd, rn, imm, shift); - } - - pub fn sub(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { - return addSubtractImmediate(0b1, 0b0, rd, rn, imm, shift); - } - - pub fn subs(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { - return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift); - } - - // Logical (immediate) - - pub fn andImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction { - return logicalImmediate(0b00, rd, rn, imms, immr, n); - } - - pub fn orrImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction { - return logicalImmediate(0b01, rd, rn, imms, immr, n); - } - - pub fn eorImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction { - return logicalImmediate(0b10, rd, rn, imms, immr, n); - } - - pub fn andsImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction { - return logicalImmediate(0b11, rd, rn, imms, immr, n); - } - - // Bitfield - - pub fn sbfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction { - const n: u1 = switch (rd.size()) { - 32 => 0b0, - 64 => 0b1, - else => unreachable, // unexpected register size - }; - return initBitfield(0b00, n, rd, rn, immr, imms); - } - - pub fn bfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction { - const n: u1 = switch (rd.size()) { - 32 => 0b0, - 64 => 0b1, - else => unreachable, // unexpected register size - }; - return initBitfield(0b01, n, rd, rn, immr, imms); - } - - pub fn ubfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction { - const n: u1 = switch (rd.size()) { - 32 => 0b0, - 64 => 0b1, - else => unreachable, // unexpected register size - }; - return initBitfield(0b10, n, rd, rn, immr, imms); - } - - pub fn asrImmediate(rd: Register, rn: Register, shift: u6) Instruction { - const imms = @as(u6, @intCast(rd.size() - 1)); - return sbfm(rd, rn, shift, imms); - } - - pub fn sbfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction { - return sbfm(rd, rn, lsb, @as(u6, @intCast(lsb + width - 1))); - } - - pub fn sxtb(rd: Register, rn: Register) Instruction { - return sbfm(rd, rn, 0, 7); - } - - pub fn sxth(rd: Register, rn: Register) Instruction { - return sbfm(rd, rn, 0, 15); - } - - pub fn sxtw(rd: Register, rn: Register) Instruction { - assert(rd.size() == 64); - return sbfm(rd, rn, 0, 31); - } - - pub fn lslImmediate(rd: Register, rn: Register, shift: u6) Instruction { - const size = @as(u6, @intCast(rd.size() - 1)); - return ubfm(rd, rn, size - shift + 1, size - shift); - } - - pub fn lsrImmediate(rd: Register, rn: Register, shift: u6) Instruction { - const imms = @as(u6, @intCast(rd.size() - 1)); - return ubfm(rd, rn, shift, imms); - } - - pub fn ubfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction { - return ubfm(rd, rn, lsb, @as(u6, @intCast(lsb + width - 1))); - } - - pub fn uxtb(rd: Register, rn: Register) Instruction { - return ubfm(rd, rn, 0, 7); - } - - pub fn uxth(rd: Register, rn: Register) Instruction { - return ubfm(rd, rn, 0, 15); - } - - // Add/subtract (shifted register) - - pub fn addShiftedRegister( - rd: Register, - rn: Register, - rm: Register, - shift: AddSubtractShiftedRegisterShift, - imm6: u6, - ) Instruction { - return addSubtractShiftedRegister(0b0, 0b0, shift, rd, rn, rm, imm6); - } - - pub fn addsShiftedRegister( - rd: Register, - rn: Register, - rm: Register, - shift: AddSubtractShiftedRegisterShift, - imm6: u6, - ) Instruction { - return addSubtractShiftedRegister(0b0, 0b1, shift, rd, rn, rm, imm6); - } - - pub fn subShiftedRegister( - rd: Register, - rn: Register, - rm: Register, - shift: AddSubtractShiftedRegisterShift, - imm6: u6, - ) Instruction { - return addSubtractShiftedRegister(0b1, 0b0, shift, rd, rn, rm, imm6); - } - - pub fn subsShiftedRegister( - rd: Register, - rn: Register, - rm: Register, - shift: AddSubtractShiftedRegisterShift, - imm6: u6, - ) Instruction { - return addSubtractShiftedRegister(0b1, 0b1, shift, rd, rn, rm, imm6); - } - - // Add/subtract (extended register) - - pub fn addExtendedRegister( - rd: Register, - rn: Register, - rm: Register, - extend: AddSubtractExtendedRegisterOption, - imm3: u3, - ) Instruction { - return addSubtractExtendedRegister(0b0, 0b0, rd, rn, rm, extend, imm3); - } - - pub fn addsExtendedRegister( - rd: Register, - rn: Register, - rm: Register, - extend: AddSubtractExtendedRegisterOption, - imm3: u3, - ) Instruction { - return addSubtractExtendedRegister(0b0, 0b1, rd, rn, rm, extend, imm3); - } - - pub fn subExtendedRegister( - rd: Register, - rn: Register, - rm: Register, - extend: AddSubtractExtendedRegisterOption, - imm3: u3, - ) Instruction { - return addSubtractExtendedRegister(0b1, 0b0, rd, rn, rm, extend, imm3); - } - - pub fn subsExtendedRegister( - rd: Register, - rn: Register, - rm: Register, - extend: AddSubtractExtendedRegisterOption, - imm3: u3, - ) Instruction { - return addSubtractExtendedRegister(0b1, 0b1, rd, rn, rm, extend, imm3); - } - - // Conditional branch - - pub fn bCond(cond: Condition, offset: i21) Instruction { - return conditionalBranch(0b0, 0b0, cond, offset); - } - - // Compare and branch - - pub fn cbz(rt: Register, offset: i21) Instruction { - return compareAndBranch(0b0, rt, offset); - } - - pub fn cbnz(rt: Register, offset: i21) Instruction { - return compareAndBranch(0b1, rt, offset); - } - - // Conditional select - - pub fn csel(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction { - return conditionalSelect(0b00, 0b0, 0b0, rd, rn, rm, cond); - } - - pub fn csinc(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction { - return conditionalSelect(0b01, 0b0, 0b0, rd, rn, rm, cond); - } - - pub fn csinv(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction { - return conditionalSelect(0b00, 0b1, 0b0, rd, rn, rm, cond); - } - - pub fn csneg(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction { - return conditionalSelect(0b01, 0b1, 0b0, rd, rn, rm, cond); - } - - // Data processing (3 source) - - pub fn madd(rd: Register, rn: Register, rm: Register, ra: Register) Instruction { - return dataProcessing3Source(0b00, 0b000, 0b0, rd, rn, rm, ra); - } - - pub fn smaddl(rd: Register, rn: Register, rm: Register, ra: Register) Instruction { - assert(rd.size() == 64 and rn.size() == 32 and rm.size() == 32 and ra.size() == 64); - return dataProcessing3Source(0b00, 0b001, 0b0, rd, rn, rm, ra); - } - - pub fn umaddl(rd: Register, rn: Register, rm: Register, ra: Register) Instruction { - assert(rd.size() == 64 and rn.size() == 32 and rm.size() == 32 and ra.size() == 64); - return dataProcessing3Source(0b00, 0b101, 0b0, rd, rn, rm, ra); - } - - pub fn msub(rd: Register, rn: Register, rm: Register, ra: Register) Instruction { - return dataProcessing3Source(0b00, 0b000, 0b1, rd, rn, rm, ra); - } - - pub fn mul(rd: Register, rn: Register, rm: Register) Instruction { - return madd(rd, rn, rm, .xzr); - } - - pub fn smull(rd: Register, rn: Register, rm: Register) Instruction { - return smaddl(rd, rn, rm, .xzr); - } - - pub fn smulh(rd: Register, rn: Register, rm: Register) Instruction { - assert(rd.size() == 64); - return dataProcessing3Source(0b00, 0b010, 0b0, rd, rn, rm, .xzr); - } - - pub fn umull(rd: Register, rn: Register, rm: Register) Instruction { - return umaddl(rd, rn, rm, .xzr); - } - - pub fn umulh(rd: Register, rn: Register, rm: Register) Instruction { - assert(rd.size() == 64); - return dataProcessing3Source(0b00, 0b110, 0b0, rd, rn, rm, .xzr); - } - - pub fn mneg(rd: Register, rn: Register, rm: Register) Instruction { - return msub(rd, rn, rm, .xzr); - } - - // Data processing (2 source) - - pub fn udiv(rd: Register, rn: Register, rm: Register) Instruction { - return dataProcessing2Source(0b0, 0b000010, rd, rn, rm); - } - - pub fn sdiv(rd: Register, rn: Register, rm: Register) Instruction { - return dataProcessing2Source(0b0, 0b000011, rd, rn, rm); - } - - pub fn lslv(rd: Register, rn: Register, rm: Register) Instruction { - return dataProcessing2Source(0b0, 0b001000, rd, rn, rm); - } - - pub fn lsrv(rd: Register, rn: Register, rm: Register) Instruction { - return dataProcessing2Source(0b0, 0b001001, rd, rn, rm); - } - - pub fn asrv(rd: Register, rn: Register, rm: Register) Instruction { - return dataProcessing2Source(0b0, 0b001010, rd, rn, rm); - } - - pub const asrRegister = asrv; - pub const lslRegister = lslv; - pub const lsrRegister = lsrv; -}; - -test { - testing.refAllDecls(@This()); -} - -test "serialize instructions" { - const Testcase = struct { - inst: Instruction, - expected: u32, - }; - - const testcases = [_]Testcase{ - .{ // orr x0, xzr, x1 - .inst = Instruction.orrShiftedRegister(.x0, .xzr, .x1, .lsl, 0), - .expected = 0b1_01_01010_00_0_00001_000000_11111_00000, - }, - .{ // orn x0, xzr, x1 - .inst = Instruction.ornShiftedRegister(.x0, .xzr, .x1, .lsl, 0), - .expected = 0b1_01_01010_00_1_00001_000000_11111_00000, - }, - .{ // movz x1, #4 - .inst = Instruction.movz(.x1, 4, 0), - .expected = 0b1_10_100101_00_0000000000000100_00001, - }, - .{ // movz x1, #4, lsl 16 - .inst = Instruction.movz(.x1, 4, 16), - .expected = 0b1_10_100101_01_0000000000000100_00001, - }, - .{ // movz x1, #4, lsl 32 - .inst = Instruction.movz(.x1, 4, 32), - .expected = 0b1_10_100101_10_0000000000000100_00001, - }, - .{ // movz x1, #4, lsl 48 - .inst = Instruction.movz(.x1, 4, 48), - .expected = 0b1_10_100101_11_0000000000000100_00001, - }, - .{ // movz w1, #4 - .inst = Instruction.movz(.w1, 4, 0), - .expected = 0b0_10_100101_00_0000000000000100_00001, - }, - .{ // movz w1, #4, lsl 16 - .inst = Instruction.movz(.w1, 4, 16), - .expected = 0b0_10_100101_01_0000000000000100_00001, - }, - .{ // svc #0 - .inst = Instruction.svc(0), - .expected = 0b1101_0100_000_0000000000000000_00001, - }, - .{ // svc #0x80 ; typical on Darwin - .inst = Instruction.svc(0x80), - .expected = 0b1101_0100_000_0000000010000000_00001, - }, - .{ // ret - .inst = Instruction.ret(null), - .expected = 0b1101_011_00_10_11111_0000_00_11110_00000, - }, - .{ // bl #0x10 - .inst = Instruction.bl(0x10), - .expected = 0b1_00101_00_0000_0000_0000_0000_0000_0100, - }, - .{ // ldr x2, [x1] - .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.none), - .expected = 0b11_111_0_01_01_000000000000_00001_00010, - }, - .{ // ldr x2, [x1, #1]! - .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.imm_pre_index(1)), - .expected = 0b11_111_0_00_01_0_000000001_11_00001_00010, - }, - .{ // ldr x2, [x1], #-1 - .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.imm_post_index(-1)), - .expected = 0b11_111_0_00_01_0_111111111_01_00001_00010, - }, - .{ // ldr x2, [x1], (x3) - .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.reg(.x3)), - .expected = 0b11_111_0_00_01_1_00011_011_0_10_00001_00010, - }, - .{ // ldr x2, label - .inst = Instruction.ldrLiteral(.x2, 0x1), - .expected = 0b01_011_0_00_0000000000000000001_00010, - }, - .{ // ldrh x7, [x4], #0xaa - .inst = Instruction.ldrh(.x7, .x4, Instruction.LoadStoreOffset.imm_post_index(0xaa)), - .expected = 0b01_111_0_00_01_0_010101010_01_00100_00111, - }, - .{ // ldrb x9, [x15, #0xff]! - .inst = Instruction.ldrb(.x9, .x15, Instruction.LoadStoreOffset.imm_pre_index(0xff)), - .expected = 0b00_111_0_00_01_0_011111111_11_01111_01001, - }, - .{ // str x2, [x1] - .inst = Instruction.str(.x2, .x1, Instruction.LoadStoreOffset.none), - .expected = 0b11_111_0_01_00_000000000000_00001_00010, - }, - .{ // str x2, [x1], (x3) - .inst = Instruction.str(.x2, .x1, Instruction.LoadStoreOffset.reg(.x3)), - .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010, - }, - .{ // strh w0, [x1] - .inst = Instruction.strh(.w0, .x1, Instruction.LoadStoreOffset.none), - .expected = 0b01_111_0_01_00_000000000000_00001_00000, - }, - .{ // strb w8, [x9] - .inst = Instruction.strb(.w8, .x9, Instruction.LoadStoreOffset.none), - .expected = 0b00_111_0_01_00_000000000000_01001_01000, - }, - .{ // adr x2, #0x8 - .inst = Instruction.adr(.x2, 0x8), - .expected = 0b0_00_10000_0000000000000000010_00010, - }, - .{ // adr x2, -#0x8 - .inst = Instruction.adr(.x2, -0x8), - .expected = 0b0_00_10000_1111111111111111110_00010, - }, - .{ // adrp x2, #0x8 - .inst = Instruction.adrp(.x2, 0x8), - .expected = 0b1_00_10000_0000000000000000010_00010, - }, - .{ // adrp x2, -#0x8 - .inst = Instruction.adrp(.x2, -0x8), - .expected = 0b1_00_10000_1111111111111111110_00010, - }, - .{ // stp x1, x2, [sp, #8] - .inst = Instruction.stp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.signed(8)), - .expected = 0b10_101_0_010_0_0000001_00010_11111_00001, - }, - .{ // ldp x1, x2, [sp, #8] - .inst = Instruction.ldp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.signed(8)), - .expected = 0b10_101_0_010_1_0000001_00010_11111_00001, - }, - .{ // stp x1, x2, [sp, #-16]! - .inst = Instruction.stp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.pre_index(-16)), - .expected = 0b10_101_0_011_0_1111110_00010_11111_00001, - }, - .{ // ldp x1, x2, [sp], #16 - .inst = Instruction.ldp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.post_index(16)), - .expected = 0b10_101_0_001_1_0000010_00010_11111_00001, - }, - .{ // and x0, x4, x2 - .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0), - .expected = 0b1_00_01010_00_0_00010_000000_00100_00000, - }, - .{ // and x0, x4, x2, lsl #0x8 - .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0x8), - .expected = 0b1_00_01010_00_0_00010_001000_00100_00000, - }, - .{ // add x0, x10, #10 - .inst = Instruction.add(.x0, .x10, 10, false), - .expected = 0b1_0_0_100010_0_0000_0000_1010_01010_00000, - }, - .{ // subs x0, x5, #11, lsl #12 - .inst = Instruction.subs(.x0, .x5, 11, true), - .expected = 0b1_1_1_100010_1_0000_0000_1011_00101_00000, - }, - .{ // b.hi #-4 - .inst = Instruction.bCond(.hi, -4), - .expected = 0b0101010_0_1111111111111111111_0_1000, - }, - .{ // cbz x10, #40 - .inst = Instruction.cbz(.x10, 40), - .expected = 0b1_011010_0_0000000000000001010_01010, - }, - .{ // add x0, x1, x2, lsl #5 - .inst = Instruction.addShiftedRegister(.x0, .x1, .x2, .lsl, 5), - .expected = 0b1_0_0_01011_00_0_00010_000101_00001_00000, - }, - .{ // csinc x1, x2, x4, eq - .inst = Instruction.csinc(.x1, .x2, .x4, .eq), - .expected = 0b1_0_0_11010100_00100_0000_0_1_00010_00001, - }, - .{ // mul x1, x4, x9 - .inst = Instruction.mul(.x1, .x4, .x9), - .expected = 0b1_00_11011_000_01001_0_11111_00100_00001, - }, - .{ // eor x3, x5, #1 - .inst = Instruction.eorImmediate(.x3, .x5, 0b000000, 0b000000, 0b1), - .expected = 0b1_10_100100_1_000000_000000_00101_00011, - }, - .{ // lslv x6, x9, x10 - .inst = Instruction.lslv(.x6, .x9, .x10), - .expected = 0b1_0_0_11010110_01010_0010_00_01001_00110, - }, - .{ // lsl x4, x2, #42 - .inst = Instruction.lslImmediate(.x4, .x2, 42), - .expected = 0b1_10_100110_1_010110_010101_00010_00100, - }, - .{ // lsl x4, x2, #63 - .inst = Instruction.lslImmediate(.x4, .x2, 63), - .expected = 0b1_10_100110_1_000001_000000_00010_00100, - }, - .{ // lsr x4, x2, #42 - .inst = Instruction.lsrImmediate(.x4, .x2, 42), - .expected = 0b1_10_100110_1_101010_111111_00010_00100, - }, - .{ // lsr x4, x2, #63 - .inst = Instruction.lsrImmediate(.x4, .x2, 63), - .expected = 0b1_10_100110_1_111111_111111_00010_00100, - }, - .{ // umull x0, w0, w1 - .inst = Instruction.umull(.x0, .w0, .w1), - .expected = 0b1_00_11011_1_01_00001_0_11111_00000_00000, - }, - .{ // smull x0, w0, w1 - .inst = Instruction.smull(.x0, .w0, .w1), - .expected = 0b1_00_11011_0_01_00001_0_11111_00000_00000, - }, - .{ // tst x0, #0xffffffff00000000 - .inst = Instruction.andsImmediate(.xzr, .x0, 0b011111, 0b100000, 0b1), - .expected = 0b1_11_100100_1_100000_011111_00000_11111, - }, - .{ // umulh x0, x1, x2 - .inst = Instruction.umulh(.x0, .x1, .x2), - .expected = 0b1_00_11011_1_10_00010_0_11111_00001_00000, - }, - .{ // smulh x0, x1, x2 - .inst = Instruction.smulh(.x0, .x1, .x2), - .expected = 0b1_00_11011_0_10_00010_0_11111_00001_00000, - }, - .{ // adds x0, x1, x2, sxtx - .inst = Instruction.addsExtendedRegister(.x0, .x1, .x2, .sxtx, 0), - .expected = 0b1_0_1_01011_00_1_00010_111_000_00001_00000, - }, - }; - - for (testcases) |case| { - const actual = case.inst.toU32(); - try testing.expectEqual(case.expected, actual); - } -} diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 0753cc5d16..ffff65d4d1 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -744,7 +744,7 @@ pub fn generate( src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, air: *const Air, - liveness: *const Air.Liveness, + liveness: *const ?Air.Liveness, ) CodeGenError!Mir { const zcu = pt.zcu; const gpa = zcu.gpa; @@ -767,7 +767,7 @@ pub fn generate( .pt = pt, .mod = mod, .bin_file = bin_file, - .liveness = liveness.*, + .liveness = liveness.*.?, .target = &mod.resolved_target.result, .owner = .{ .nav_index = func.owner_nav }, .args = undefined, // populated after `resolveCallingConventionValues` @@ -4584,7 +4584,7 @@ fn structFieldPtr(func: *Func, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde const field_offset: i32 = switch (container_ty.containerLayout(zcu)) { .auto, .@"extern" => @intCast(container_ty.structFieldOffset(index, zcu)), .@"packed" => @divExact(@as(i32, ptr_container_ty.ptrInfo(zcu).packed_offset.bit_offset) + - (if (zcu.typeToStruct(container_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, index) else 0) - + (if (zcu.typeToStruct(container_ty)) |struct_obj| zcu.structPackedFieldBitOffset(struct_obj, index) else 0) - ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8), }; @@ -4615,7 +4615,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void { const field_off: u32 = switch (struct_ty.containerLayout(zcu)) { .auto, .@"extern" => @intCast(struct_ty.structFieldOffset(index, zcu) * 8), .@"packed" => if (zcu.typeToStruct(struct_ty)) |struct_type| - pt.structPackedFieldBitOffset(struct_type, index) + zcu.structPackedFieldBitOffset(struct_type, index) else 0, }; @@ -8059,7 +8059,7 @@ fn airAggregateInit(func: *Func, inst: Air.Inst.Index) !void { const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu)); const elem_abi_bits = elem_abi_size * 8; - const elem_off = pt.structPackedFieldBitOffset(struct_obj, elem_i); + const elem_off = zcu.structPackedFieldBitOffset(struct_obj, elem_i); const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size); const elem_bit_off = elem_off % elem_abi_bits; const elem_mcv = try func.resolveInst(elem); diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 31a7f39d69..6ab5dea4ec 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -267,7 +267,7 @@ pub fn generate( src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, air: *const Air, - liveness: *const Air.Liveness, + liveness: *const ?Air.Liveness, ) CodeGenError!Mir { const zcu = pt.zcu; const gpa = zcu.gpa; @@ -288,7 +288,7 @@ pub fn generate( .gpa = gpa, .pt = pt, .air = air.*, - .liveness = liveness.*, + .liveness = liveness.*.?, .target = target, .bin_file = lf, .func_index = func_index, diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 50d104a7bc..fca32627b9 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1173,7 +1173,7 @@ pub fn generate( src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, air: *const Air, - liveness: *const Air.Liveness, + liveness: *const ?Air.Liveness, ) Error!Mir { _ = src_loc; _ = bin_file; @@ -1194,7 +1194,7 @@ pub fn generate( .gpa = gpa, .pt = pt, .air = air.*, - .liveness = liveness.*, + .liveness = liveness.*.?, .owner_nav = cg.owner_nav, .target = target, .ptr_size = switch (target.cpu.arch) { @@ -3776,7 +3776,7 @@ fn structFieldPtr( break :offset @as(u32, 0); } const struct_type = zcu.typeToStruct(struct_ty).?; - break :offset @divExact(pt.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8); + break :offset @divExact(zcu.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8); }, .@"union" => 0, else => unreachable, @@ -3812,7 +3812,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { .@"packed" => switch (struct_ty.zigTypeTag(zcu)) { .@"struct" => result: { const packed_struct = zcu.typeToPackedStruct(struct_ty).?; - const offset = pt.structPackedFieldBitOffset(packed_struct, field_index); + const offset = zcu.structPackedFieldBitOffset(packed_struct, field_index); const backing_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip)); const host_bits = backing_ty.intInfo(zcu).bits; @@ -5696,7 +5696,7 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { .auto, .@"extern" => parent_ty.structFieldOffset(field_index, zcu), .@"packed" => offset: { const parent_ptr_offset = parent_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset; - const field_offset = if (zcu.typeToStruct(parent_ty)) |loaded_struct| pt.structPackedFieldBitOffset(loaded_struct, field_index) else 0; + const field_offset = if (zcu.typeToStruct(parent_ty)) |loaded_struct| zcu.structPackedFieldBitOffset(loaded_struct, field_index) else 0; const field_ptr_offset = field_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset; break :offset @divExact(parent_ptr_offset + field_offset - field_ptr_offset, 8); }, diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 6341f7e3d2..89a23d3514 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -878,7 +878,7 @@ pub fn generate( src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, air: *const Air, - liveness: *const Air.Liveness, + liveness: *const ?Air.Liveness, ) codegen.CodeGenError!Mir { _ = bin_file; const zcu = pt.zcu; @@ -894,7 +894,7 @@ pub fn generate( .gpa = gpa, .pt = pt, .air = air.*, - .liveness = liveness.*, + .liveness = liveness.*.?, .target = &mod.resolved_target.result, .mod = mod, .owner = .{ .nav_index = func.owner_nav }, @@ -100674,11 +100674,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data; var ops = try cg.tempsFromOperands(inst, .{struct_field.struct_operand}); - try ops[0].toOffset(cg.fieldOffset( + try ops[0].toOffset(@intCast(codegen.fieldOffset( cg.typeOf(struct_field.struct_operand), ty_pl.ty.toType(), struct_field.field_index, - ), cg); + zcu, + )), cg); try ops[0].finish(inst, &.{struct_field.struct_operand}, &ops, cg); }, .struct_field_ptr_index_0, @@ -100688,7 +100689,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { => |air_tag| { const ty_op = air_datas[@intFromEnum(inst)].ty_op; var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); - try ops[0].toOffset(cg.fieldOffset( + try ops[0].toOffset(@intCast(codegen.fieldOffset( cg.typeOf(ty_op.operand), ty_op.ty.toType(), switch (air_tag) { @@ -100698,7 +100699,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .struct_field_ptr_index_2 => 2, .struct_field_ptr_index_3 => 3, }, - ), cg); + zcu, + )), cg); try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg); }, .struct_field_val => { @@ -168108,11 +168110,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; const field_parent_ptr = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; var ops = try cg.tempsFromOperands(inst, .{field_parent_ptr.field_ptr}); - try ops[0].toOffset(-cg.fieldOffset( + try ops[0].toOffset(-@as(i32, @intCast(codegen.fieldOffset( ty_pl.ty.toType(), cg.typeOf(field_parent_ptr.field_ptr), field_parent_ptr.field_index, - ), cg); + zcu, + ))), cg); try ops[0].finish(inst, &.{field_parent_ptr.field_ptr}, &ops, cg); }, .wasm_memory_size, .wasm_memory_grow => unreachable, @@ -174809,18 +174812,6 @@ fn airStore(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none }); } -fn fieldOffset(self: *CodeGen, ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32) i32 { - const pt = self.pt; - const zcu = pt.zcu; - const agg_ty = ptr_agg_ty.childType(zcu); - return switch (agg_ty.containerLayout(zcu)) { - .auto, .@"extern" => @intCast(agg_ty.structFieldOffset(field_index, zcu)), - .@"packed" => @divExact(@as(i32, ptr_agg_ty.ptrInfo(zcu).packed_offset.bit_offset) + - (if (zcu.typeToStruct(agg_ty)) |loaded_struct| pt.structPackedFieldBitOffset(loaded_struct, field_index) else 0) - - ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8), - }; -} - fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue { const pt = self.pt; const zcu = pt.zcu; @@ -184575,7 +184566,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void { } const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu)); const elem_abi_bits = elem_abi_size * 8; - const elem_off = pt.structPackedFieldBitOffset(loaded_struct, elem_i); + const elem_off = zcu.structPackedFieldBitOffset(loaded_struct, elem_i); const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size); const elem_bit_off = elem_off % elem_abi_bits; const elem_mcv = try self.resolveInst(elem); @@ -185625,21 +185616,19 @@ fn resolveCallingConventionValues( fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { @branchHint(.cold); const zcu = cg.pt.zcu; - switch (cg.owner) { - .nav_index => |i| return zcu.codegenFail(i, format, args), - .lazy_sym => |s| return zcu.codegenFailType(s.ty, format, args), - } - return error.CodegenFail; + return switch (cg.owner) { + .nav_index => |i| zcu.codegenFail(i, format, args), + .lazy_sym => |s| zcu.codegenFailType(s.ty, format, args), + }; } fn failMsg(cg: *CodeGen, msg: *Zcu.ErrorMsg) error{ OutOfMemory, CodegenFail } { @branchHint(.cold); const zcu = cg.pt.zcu; - switch (cg.owner) { - .nav_index => |i| return zcu.codegenFailMsg(i, msg), - .lazy_sym => |s| return zcu.codegenFailTypeMsg(s.ty, msg), - } - return error.CodegenFail; + return switch (cg.owner) { + .nav_index => |i| zcu.codegenFailMsg(i, msg), + .lazy_sym => |s| zcu.codegenFailTypeMsg(s.ty, msg), + }; } fn parseRegName(name: []const u8) ?Register { diff --git a/src/codegen.zig b/src/codegen.zig index 9bddc51963..d509234148 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -22,6 +22,8 @@ const Zir = std.zig.Zir; const Alignment = InternPool.Alignment; const dev = @import("dev.zig"); +pub const aarch64 = @import("codegen/aarch64.zig"); + pub const CodeGenError = GenerateSymbolError || error{ /// Indicates the error is already stored in Zcu `failed_codegen`. CodegenFail, @@ -48,7 +50,7 @@ fn devFeatureForBackend(backend: std.builtin.CompilerBackend) dev.Feature { fn importBackend(comptime backend: std.builtin.CompilerBackend) type { return switch (backend) { .other, .stage1 => unreachable, - .stage2_aarch64 => unreachable, + .stage2_aarch64 => aarch64, .stage2_arm => unreachable, .stage2_c => @import("codegen/c.zig"), .stage2_llvm => @import("codegen/llvm.zig"), @@ -71,6 +73,7 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co .stage2_c, .stage2_wasm, .stage2_x86_64, + .stage2_aarch64, .stage2_x86, .stage2_riscv64, .stage2_sparc64, @@ -82,10 +85,20 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co } } +pub fn wantsLiveness(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) bool { + const zcu = pt.zcu; + const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; + return switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) { + else => true, + .stage2_aarch64 => false, + }; +} + /// Every code generation backend has a different MIR representation. However, we want to pass /// MIR from codegen to the linker *regardless* of which backend is in use. So, we use this: a /// union of all MIR types. The active tag is known from the backend in use; see `AnyMir.tag`. pub const AnyMir = union { + aarch64: @import("codegen/aarch64/Mir.zig"), riscv64: @import("arch/riscv64/Mir.zig"), sparc64: @import("arch/sparc64/Mir.zig"), x86_64: @import("arch/x86_64/Mir.zig"), @@ -95,7 +108,6 @@ pub const AnyMir = union { pub inline fn tag(comptime backend: std.builtin.CompilerBackend) []const u8 { return switch (backend) { .stage2_aarch64 => "aarch64", - .stage2_arm => "arm", .stage2_riscv64 => "riscv64", .stage2_sparc64 => "sparc64", .stage2_x86_64 => "x86_64", @@ -110,7 +122,8 @@ pub const AnyMir = union { const backend = target_util.zigBackend(&zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm); switch (backend) { else => unreachable, - inline .stage2_riscv64, + inline .stage2_aarch64, + .stage2_riscv64, .stage2_sparc64, .stage2_x86_64, .stage2_wasm, @@ -131,14 +144,15 @@ pub fn generateFunction( src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, air: *const Air, - liveness: *const Air.Liveness, + liveness: *const ?Air.Liveness, ) CodeGenError!AnyMir { const zcu = pt.zcu; const func = zcu.funcInfo(func_index); const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result; switch (target_util.zigBackend(target, false)) { else => unreachable, - inline .stage2_riscv64, + inline .stage2_aarch64, + .stage2_riscv64, .stage2_sparc64, .stage2_x86_64, .stage2_wasm, @@ -173,7 +187,8 @@ pub fn emitFunction( const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result; switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) { else => unreachable, - inline .stage2_riscv64, + inline .stage2_aarch64, + .stage2_riscv64, .stage2_sparc64, .stage2_x86_64, => |backend| { @@ -420,7 +435,7 @@ pub fn generateSymbol( const int_tag_ty = ty.intTagType(zcu); try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, reloc_parent); }, - .float => |float| switch (float.storage) { + .float => |float| storage: switch (float.storage) { .f16 => |f16_val| writeFloat(f16, f16_val, target, endian, try code.addManyAsArray(gpa, 2)), .f32 => |f32_val| writeFloat(f32, f32_val, target, endian, try code.addManyAsArray(gpa, 4)), .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(gpa, 8)), @@ -429,7 +444,13 @@ pub fn generateSymbol( const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; try code.appendNTimes(gpa, 0, abi_size - 10); }, - .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)), + .f128 => |f128_val| switch (Type.fromInterned(float.ty).floatBits(target)) { + else => unreachable, + 16 => continue :storage .{ .f16 = @floatCast(f128_val) }, + 32 => continue :storage .{ .f32 = @floatCast(f128_val) }, + 64 => continue :storage .{ .f64 = @floatCast(f128_val) }, + 128 => writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)), + }, }, .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), code, reloc_parent, 0), .slice => |slice| { @@ -1218,3 +1239,17 @@ pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Zcu) u64 { return 0; } } + +pub fn fieldOffset(ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32, zcu: *Zcu) u64 { + const agg_ty = ptr_agg_ty.childType(zcu); + return switch (agg_ty.containerLayout(zcu)) { + .auto, .@"extern" => agg_ty.structFieldOffset(field_index, zcu), + .@"packed" => @divExact(@as(u64, ptr_agg_ty.ptrInfo(zcu).packed_offset.bit_offset) + + (if (zcu.typeToPackedStruct(agg_ty)) |loaded_struct| zcu.structPackedFieldBitOffset(loaded_struct, field_index) else 0) - + ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8), + }; +} + +test { + _ = aarch64; +} diff --git a/src/codegen/aarch64.zig b/src/codegen/aarch64.zig new file mode 100644 index 0000000000..6f95fff58e --- /dev/null +++ b/src/codegen/aarch64.zig @@ -0,0 +1,194 @@ +pub const abi = @import("aarch64/abi.zig"); +pub const Assemble = @import("aarch64/Assemble.zig"); +pub const Disassemble = @import("aarch64/Disassemble.zig"); +pub const encoding = @import("aarch64/encoding.zig"); +pub const Mir = @import("aarch64/Mir.zig"); +pub const Select = @import("aarch64/Select.zig"); + +pub fn legalizeFeatures(_: *const std.Target) ?*Air.Legalize.Features { + return null; +} + +pub fn generate( + _: *link.File, + pt: Zcu.PerThread, + _: Zcu.LazySrcLoc, + func_index: InternPool.Index, + air: *const Air, + liveness: *const ?Air.Liveness, +) !Mir { + const zcu = pt.zcu; + const gpa = zcu.gpa; + const func = zcu.funcInfo(func_index); + const func_type = zcu.intern_pool.indexToKey(func.ty).func_type; + assert(liveness.* == null); + + const mod = zcu.navFileScope(func.owner_nav).mod.?; + var isel: Select = .{ + .pt = pt, + .target = &mod.resolved_target.result, + .air = air.*, + .nav_index = zcu.funcInfo(func_index).owner_nav, + + .def_order = .empty, + .blocks = .empty, + .loops = .empty, + .active_loops = .empty, + .loop_live = .{ + .set = .empty, + .list = .empty, + }, + .dom_start = 0, + .dom_len = 0, + .dom = .empty, + + .saved_registers = comptime .initEmpty(), + .instructions = .empty, + .literals = .empty, + .nav_relocs = .empty, + .uav_relocs = .empty, + .global_relocs = .empty, + .literal_relocs = .empty, + + .returns = false, + .va_list = undefined, + .stack_size = 0, + .stack_align = .@"16", + + .live_registers = comptime .initFill(.free), + .live_values = .empty, + .values = .empty, + }; + defer isel.deinit(); + + const air_main_body = air.getMainBody(); + var param_it: Select.CallAbiIterator = .init; + const air_args = for (air_main_body, 0..) |air_inst_index, body_index| { + if (air.instructions.items(.tag)[@intFromEnum(air_inst_index)] != .arg) break air_main_body[0..body_index]; + const param_ty = air.instructions.items(.data)[@intFromEnum(air_inst_index)].arg.ty.toType(); + const param_vi = try param_it.param(&isel, param_ty); + tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(param_vi.?), @intFromEnum(air_inst_index) }); + try isel.live_values.putNoClobber(gpa, air_inst_index, param_vi.?); + } else unreachable; + + const saved_gra_start = if (mod.strip) param_it.ngrn else Select.CallAbiIterator.ngrn_start; + const saved_gra_end = if (func_type.is_var_args) Select.CallAbiIterator.ngrn_end else param_it.ngrn; + const saved_gra_len = @intFromEnum(saved_gra_end) - @intFromEnum(saved_gra_start); + + const saved_vra_start = if (mod.strip) param_it.nsrn else Select.CallAbiIterator.nsrn_start; + const saved_vra_end = if (func_type.is_var_args) Select.CallAbiIterator.nsrn_end else param_it.nsrn; + const saved_vra_len = @intFromEnum(saved_vra_end) - @intFromEnum(saved_vra_start); + + const frame_record = 2; + const named_stack_args: Select.Value.Indirect = .{ + .base = .fp, + .offset = 8 * std.mem.alignForward(u7, frame_record + saved_gra_len, 2), + }; + isel.va_list = .{ + .__stack = named_stack_args.withOffset(param_it.nsaa), + .__gr_top = named_stack_args, + .__vr_top = .{ .base = .fp, .offset = 0 }, + }; + + // translate arg locations from caller-based to callee-based + for (air_args) |air_inst_index| { + assert(air.instructions.items(.tag)[@intFromEnum(air_inst_index)] == .arg); + const arg_vi = isel.live_values.get(air_inst_index).?; + const passed_vi = switch (arg_vi.parent(&isel)) { + .unallocated, .stack_slot => arg_vi, + .value, .constant => unreachable, + .address => |address_vi| address_vi, + }; + switch (passed_vi.parent(&isel)) { + .unallocated => if (!mod.strip) { + var part_it = arg_vi.parts(&isel); + const first_passed_part_vi = part_it.next() orelse passed_vi; + const hint_ra = first_passed_part_vi.hint(&isel).?; + passed_vi.setParent(&isel, .{ .stack_slot = if (hint_ra.isVector()) + isel.va_list.__vr_top.withOffset(@as(i8, -16) * + (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra))) + else + isel.va_list.__gr_top.withOffset(@as(i8, -8) * + (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) }); + }, + .stack_slot => |stack_slot| { + assert(stack_slot.base == .sp); + passed_vi.setParent(&isel, .{ + .stack_slot = named_stack_args.withOffset(stack_slot.offset), + }); + }, + .address, .value, .constant => unreachable, + } + } + + ret: { + var ret_it: Select.CallAbiIterator = .init; + const ret_vi = try ret_it.ret(&isel, .fromInterned(func_type.return_type)) orelse break :ret; + tracking_log.debug("${d} <- %main", .{@intFromEnum(ret_vi)}); + try isel.live_values.putNoClobber(gpa, Select.Block.main, ret_vi); + } + + assert(!(try isel.blocks.getOrPut(gpa, Select.Block.main)).found_existing); + try isel.analyze(air_main_body); + try isel.finishAnalysis(); + isel.verify(false); + + isel.blocks.values()[0] = .{ + .live_registers = isel.live_registers, + .target_label = @intCast(isel.instructions.items.len), + }; + try isel.body(air_main_body); + if (isel.live_values.fetchRemove(Select.Block.main)) |ret_vi| { + switch (ret_vi.value.parent(&isel)) { + .unallocated, .stack_slot => {}, + .value, .constant => unreachable, + .address => |address_vi| try address_vi.liveIn( + &isel, + address_vi.hint(&isel).?, + comptime &.initFill(.free), + ), + } + ret_vi.value.deref(&isel); + } + isel.verify(true); + + const prologue = isel.instructions.items.len; + const epilogue = try isel.layout( + param_it, + func_type.is_var_args, + saved_gra_len, + saved_vra_len, + mod, + ); + + const instructions = try isel.instructions.toOwnedSlice(gpa); + var mir: Mir = .{ + .prologue = instructions[prologue..epilogue], + .body = instructions[0..prologue], + .epilogue = instructions[epilogue..], + .literals = &.{}, + .nav_relocs = &.{}, + .uav_relocs = &.{}, + .global_relocs = &.{}, + .literal_relocs = &.{}, + }; + errdefer mir.deinit(gpa); + mir.literals = try isel.literals.toOwnedSlice(gpa); + mir.nav_relocs = try isel.nav_relocs.toOwnedSlice(gpa); + mir.uav_relocs = try isel.uav_relocs.toOwnedSlice(gpa); + mir.global_relocs = try isel.global_relocs.toOwnedSlice(gpa); + mir.literal_relocs = try isel.literal_relocs.toOwnedSlice(gpa); + return mir; +} + +test { + _ = Assemble; +} + +const Air = @import("../Air.zig"); +const assert = std.debug.assert; +const InternPool = @import("../InternPool.zig"); +const link = @import("../link.zig"); +const std = @import("std"); +const tracking_log = std.log.scoped(.tracking); +const Zcu = @import("../Zcu.zig"); diff --git a/src/codegen/aarch64/Assemble.zig b/src/codegen/aarch64/Assemble.zig new file mode 100644 index 0000000000..235c445411 --- /dev/null +++ b/src/codegen/aarch64/Assemble.zig @@ -0,0 +1,1653 @@ +source: [*:0]const u8, +operands: std.StringHashMapUnmanaged(Operand), + +pub const Operand = union(enum) { + register: aarch64.encoding.Register, +}; + +pub fn nextInstruction(as: *Assemble) !?Instruction { + @setEvalBranchQuota(37_000); + comptime var ct_token_buf: [token_buf_len]u8 = undefined; + var token_buf: [token_buf_len]u8 = undefined; + const original_source = while (true) { + const original_source = as.source; + const source_token = try as.nextToken(&token_buf, .{}); + if (source_token.len == 0) return null; + if (source_token[0] != '\n') break original_source; + }; + log.debug( + \\. + \\========================= + \\= Assembling "{f}" + \\========================= + \\ + , .{std.zig.fmtString(std.mem.span(original_source))}); + inline for (instructions) |instruction| { + next_pattern: { + as.source = original_source; + var symbols: Symbols: { + const symbols = @typeInfo(@TypeOf(instruction.symbols)).@"struct".fields; + var symbol_fields: [symbols.len]std.builtin.Type.StructField = undefined; + for (&symbol_fields, symbols) |*symbol_field, symbol| symbol_field.* = .{ + .name = symbol.name, + .type = zonCast(SymbolSpec, @field(instruction.symbols, symbol.name), .{}).Storage(), + .default_value_ptr = null, + .is_comptime = false, + .alignment = 0, + }; + break :Symbols @Type(.{ .@"struct" = .{ + .layout = .auto, + .fields = &symbol_fields, + .decls = &.{}, + .is_tuple = false, + } }); + } = undefined; + comptime var pattern_as: Assemble = .{ .source = instruction.pattern, .operands = undefined }; + inline while (true) { + const pattern_token = comptime pattern_as.nextToken(&ct_token_buf, .{ .placeholders = true }) catch |err| + @compileError(@errorName(err) ++ " while parsing '" ++ instruction.pattern ++ "'"); + const source_token = try as.nextToken(&token_buf, .{ .operands = true }); + log.debug("\"{f}\" -> \"{f}\"", .{ + std.zig.fmtString(pattern_token), + std.zig.fmtString(source_token), + }); + if (pattern_token.len == 0) { + if (source_token.len > 0 and source_token[0] != '\n') break :next_pattern; + const encode = @field(Instruction, @tagName(instruction.encode[0])); + const Encode = @TypeOf(encode); + var args: std.meta.ArgsTuple(Encode) = undefined; + inline for (&args, @typeInfo(Encode).@"fn".params, 1..instruction.encode.len) |*arg, param, encode_index| + arg.* = zonCast(param.type.?, instruction.encode[encode_index], symbols); + return @call(.auto, encode, args); + } else if (pattern_token[0] == '<') { + const symbol_name = comptime pattern_token[1 .. std.mem.indexOfScalarPos(u8, pattern_token, 1, '|') orelse + pattern_token.len - 1]; + const symbol = &@field(symbols, symbol_name); + symbol.* = zonCast(SymbolSpec, @field(instruction.symbols, symbol_name), .{}).parse(source_token) orelse break :next_pattern; + log.debug("{s} = {any}", .{ symbol_name, symbol.* }); + } else if (!std.ascii.eqlIgnoreCase(pattern_token, source_token)) break :next_pattern; + } + } + log.debug("'{s}' not matched...", .{instruction.pattern}); + } + as.source = original_source; + log.debug("Nothing matched!\n", .{}); + return error.InvalidSyntax; +} + +fn zonCast(comptime Result: type, zon_value: anytype, symbols: anytype) Result { + const ZonValue = @TypeOf(zon_value); + const Symbols = @TypeOf(symbols); + switch (@typeInfo(ZonValue)) { + .void, .bool, .int, .float, .pointer, .comptime_float, .comptime_int, .@"enum" => return zon_value, + .@"struct" => |zon_struct| switch (@typeInfo(Result)) { + .@"struct" => |result_struct| { + comptime var used_zon_fields = 0; + var result: Result = undefined; + inline for (result_struct.fields) |result_field| @field(result, result_field.name) = if (@hasField(ZonValue, result_field.name)) result: { + used_zon_fields += 1; + break :result zonCast(@FieldType(Result, result_field.name), @field(zon_value, result_field.name), symbols); + } else result_field.defaultValue() orelse @compileError(std.fmt.comptimePrint("missing zon field '{s}': {} <- {any}", .{ result_field.name, Result, zon_value })); + if (used_zon_fields != zon_struct.fields.len) @compileError(std.fmt.comptimePrint("unused zon field: {} <- {any}", .{ Result, zon_value })); + return result; + }, + .@"union" => { + if (zon_struct.fields.len != 1) @compileError(std.fmt.comptimePrint("{} <- {any}", .{ Result, zon_value })); + const field_name = zon_struct.fields[0].name; + return @unionInit( + Result, + field_name, + zonCast(@FieldType(Result, field_name), @field(zon_value, field_name), symbols), + ); + }, + else => @compileError(std.fmt.comptimePrint("unsupported zon type: {} <- {any}", .{ Result, zon_value })), + }, + .enum_literal => if (@hasField(Symbols, @tagName(zon_value))) { + const symbol = @field(symbols, @tagName(zon_value)); + const Symbol = @TypeOf(symbol); + switch (@typeInfo(Result)) { + .@"enum" => switch (@typeInfo(Symbol)) { + .int => |symbol_int| { + var buf: [ + std.fmt.count("{d}", .{switch (symbol_int.signedness) { + .signed => std.math.minInt(Symbol), + .unsigned => std.math.maxInt(Symbol), + }}) + ]u8 = undefined; + return std.meta.stringToEnum(Result, std.fmt.bufPrint(&buf, "{d}", .{symbol}) catch unreachable).?; + }, + else => return symbol, + }, + else => return symbol, + } + } else return if (@hasDecl(Result, @tagName(zon_value))) @field(Result, @tagName(zon_value)) else zon_value, + else => @compileError(std.fmt.comptimePrint("unsupported zon type: {} <- {any}", .{ Result, zon_value })), + } +} + +const token_buf_len = "v31.b[15]".len; +fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct { + operands: bool = false, + placeholders: bool = false, +}) ![]const u8 { + const invalid_syntax: u8 = 1; + while (true) c: switch (as.source[0]) { + 0 => return as.source[0..0], + '\t', '\n' + 1...'\r', ' ' => as.source = as.source[1..], + '\n', '!', '#', ',', '[', ']' => { + defer as.source = as.source[1..]; + return as.source[0..1]; + }, + '%' => if (opts.operands) { + if (as.source[1] != '[') continue :c invalid_syntax; + const name_start: usize = 2; + var index = name_start; + while (switch (as.source[index]) { + else => true, + ':', ']' => false, + }) index += 1; + const operand = as.operands.get(as.source[name_start..index]) orelse continue :c invalid_syntax; + const modifier = modifier: switch (as.source[index]) { + else => unreachable, + ':' => { + index += 1; + const modifier_start = index; + while (switch (as.source[index]) { + else => true, + ']' => false, + }) index += 1; + break :modifier as.source[modifier_start..index]; + }, + ']' => "", + }; + assert(as.source[index] == ']'); + const modified_operand: Operand = if (std.mem.eql(u8, modifier, "")) + operand + else if (std.mem.eql(u8, modifier, "w")) switch (operand) { + .register => |reg| .{ .register = reg.alias.w() }, + } else if (std.mem.eql(u8, modifier, "x")) switch (operand) { + .register => |reg| .{ .register = reg.alias.x() }, + } else if (std.mem.eql(u8, modifier, "b")) switch (operand) { + .register => |reg| .{ .register = reg.alias.b() }, + } else if (std.mem.eql(u8, modifier, "h")) switch (operand) { + .register => |reg| .{ .register = reg.alias.h() }, + } else if (std.mem.eql(u8, modifier, "s")) switch (operand) { + .register => |reg| .{ .register = reg.alias.s() }, + } else if (std.mem.eql(u8, modifier, "d")) switch (operand) { + .register => |reg| .{ .register = reg.alias.d() }, + } else if (std.mem.eql(u8, modifier, "q")) switch (operand) { + .register => |reg| .{ .register = reg.alias.q() }, + } else if (std.mem.eql(u8, modifier, "Z")) switch (operand) { + .register => |reg| .{ .register = reg.alias.z() }, + } else continue :c invalid_syntax; + switch (modified_operand) { + .register => |reg| { + as.source = as.source[index + 1 ..]; + return std.fmt.bufPrint(buf, "{f}", .{reg.fmt()}) catch unreachable; + }, + } + } else continue :c invalid_syntax, + '-', '0'...'9', 'A'...'Z', '_', 'a'...'z' => { + var index: usize = 1; + while (switch (as.source[index]) { + '0'...'9', 'A'...'Z', '_', 'a'...'z' => true, + else => false, + }) index += 1; + defer as.source = as.source[index..]; + return as.source[0..index]; + }, + '<' => if (opts.placeholders) { + var index: usize = 1; + while (switch (as.source[index]) { + 0 => return error.UnterminatedPlaceholder, + '>' => false, + else => true, + }) index += 1; + defer as.source = as.source[index + 1 ..]; + return as.source[0 .. index + 1]; + } else continue :c invalid_syntax, + else => { + if (!@inComptime()) log.debug("invalid token \"{f}\"", .{std.zig.fmtString(std.mem.span(as.source))}); + return error.InvalidSyntax; + }, + }; +} + +const SymbolSpec = union(enum) { + reg: struct { format: aarch64.encoding.Register.Format, allow_sp: bool = false }, + imm: struct { + type: std.builtin.Type.Int, + multiple_of: comptime_int = 1, + max_valid: ?comptime_int = null, + }, + extend: struct { size: aarch64.encoding.Register.IntegerSize }, + shift: struct { allow_ror: bool = true }, + barrier: struct { only_sy: bool = false }, + + fn Storage(comptime spec: SymbolSpec) type { + return switch (spec) { + .reg => aarch64.encoding.Register, + .imm => |imm| @Type(.{ .int = imm.type }), + .extend => Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option, + .shift => Instruction.DataProcessingRegister.Shift.Op, + .barrier => Instruction.BranchExceptionGeneratingSystem.Barriers.Option, + }; + } + + fn parse(comptime spec: SymbolSpec, token: []const u8) ?Storage(spec) { + const Result = Storage(spec); + switch (spec) { + .reg => |reg_spec| { + var buf: [token_buf_len]u8 = undefined; + const reg = Result.parse(std.ascii.lowerString(&buf, token[0..@min(token.len, buf.len)])) orelse { + log.debug("invalid register: \"{f}\"", .{std.zig.fmtString(token)}); + return null; + }; + if (reg.format.integer != reg_spec.format.integer) { + log.debug("invalid register size: \"{f}\"", .{std.zig.fmtString(token)}); + return null; + } + if (reg.alias == if (reg_spec.allow_sp) .zr else .sp) { + log.debug("invalid register usage: \"{f}\"", .{std.zig.fmtString(token)}); + return null; + } + return reg; + }, + .imm => |imm_spec| { + const imm = std.fmt.parseInt(Result, token, 0) catch { + log.debug("invalid immediate: \"{f}\"", .{std.zig.fmtString(token)}); + return null; + }; + if (@rem(imm, imm_spec.multiple_of) != 0) { + log.debug("invalid immediate usage: \"{f}\"", .{std.zig.fmtString(token)}); + return null; + } + if (imm_spec.max_valid) |max_valid| if (imm > max_valid) { + log.debug("out of range immediate: \"{f}\"", .{std.zig.fmtString(token)}); + return null; + }; + return imm; + }, + .extend => |extend_spec| { + const Option = Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option; + var buf: [ + max_len: { + var max_len = 0; + for (@typeInfo(Option).@"enum".fields) |field| max_len = @max(max_len, field.name.len); + break :max_len max_len; + } + 1 + ]u8 = undefined; + const extend = std.meta.stringToEnum(Option, std.ascii.lowerString( + &buf, + token[0..@min(token.len, buf.len)], + )) orelse { + log.debug("invalid extend: \"{f}\"", .{std.zig.fmtString(token)}); + return null; + }; + if (extend.sf() != extend_spec.size) { + log.debug("invalid extend: \"{f}\"", .{std.zig.fmtString(token)}); + return null; + } + return extend; + }, + .shift => |shift_spec| { + const ShiftOp = Instruction.DataProcessingRegister.Shift.Op; + var buf: [ + max_len: { + var max_len = 0; + for (@typeInfo(ShiftOp).@"enum".fields) |field| max_len = @max(max_len, field.name.len); + break :max_len max_len; + } + 1 + ]u8 = undefined; + const shift = std.meta.stringToEnum(ShiftOp, std.ascii.lowerString( + &buf, + token[0..@min(token.len, buf.len)], + )) orelse { + log.debug("invalid shift: \"{f}\"", .{std.zig.fmtString(token)}); + return null; + }; + if (!shift_spec.allow_ror and shift == .ror) { + log.debug("invalid shift usage: \"{f}\"", .{std.zig.fmtString(token)}); + return null; + } + return shift; + }, + .barrier => |barrier_spec| { + const Option = Instruction.BranchExceptionGeneratingSystem.Barriers.Option; + var buf: [ + max_len: { + var max_len = 0; + for (@typeInfo(Option).@"enum".fields) |field| max_len = @max(max_len, field.name.len); + break :max_len max_len; + } + 1 + ]u8 = undefined; + const barrier = std.meta.stringToEnum(Option, std.ascii.lowerString( + &buf, + token[0..@min(token.len, buf.len)], + )) orelse { + log.debug("invalid barrier: \"{f}\"", .{std.zig.fmtString(token)}); + return null; + }; + if (barrier_spec.only_sy and barrier != .sy) { + log.debug("invalid barrier: \"{f}\"", .{std.zig.fmtString(token)}); + return null; + } + return barrier; + }, + } + } +}; + +test "add sub" { + var as: Assemble = .{ + .source = + \\ add w0, w0, w1 + \\ add w2, w3, w4 + \\ add wsp, w5, w6 + \\ add w7, wsp, w8 + \\ add wsp, wsp, w9 + \\ add w10, w10, wzr + \\ add w11, w12, wzr + \\ add wsp, w13, wzr + \\ add w14, wsp, wzr + \\ add wsp, wsp, wzr + \\ + \\ add x0, x0, x1 + \\ add x2, x3, x4 + \\ add sp, x5, x6 + \\ add x7, sp, x8 + \\ add sp, sp, x9 + \\ add x10, x10, xzr + \\ add x11, x12, xzr + \\ add sp, x13, xzr + \\ add x14, sp, xzr + \\ add sp, sp, xzr + \\ + \\ add w0, w0, w1 + \\ add w2, w3, w4, uxtb #0 + \\ add wsp, w5, w6, uxth #1 + \\ add w7, wsp, w8, uxtw #0 + \\ add wsp, wsp, w9, uxtw #2 + \\ add w10, w10, wzr, uxtw #3 + \\ add w11, w12, wzr, sxtb #4 + \\ add wsp, w13, wzr, sxth #0 + \\ add w14, wsp, wzr, sxtw #1 + \\ add wsp, wsp, wzr, sxtw #2 + \\ + \\ add x0, x0, x1 + \\ add x2, x3, w4, uxtb #0 + \\ add sp, x5, w6, uxth #1 + \\ add x7, sp, w8, uxtw #2 + \\ add sp, sp, x9, uxtx #0 + \\ add x10, x10, xzr, uxtx #3 + \\ add x11, x12, wzr, sxtb #4 + \\ add sp, x13, wzr, sxth #0 + \\ add x14, sp, wzr, sxtw #1 + \\ add sp, sp, xzr, sxtx #2 + \\ + \\ add w0, w0, #0 + \\ add w0, w1, #1, lsl #0 + \\ add wsp, w2, #2, lsl #12 + \\ add w3, wsp, #3, lsl #0 + \\ add wsp, wsp, #4095, lsl #12 + \\ add w0, w1, #0 + \\ add w2, w3, #0, lsl #0 + \\ add w4, wsp, #0 + \\ add w5, wsp, #0, lsl #0 + \\ add wsp, w6, #0 + \\ add wsp, w7, #0, lsl #0 + \\ add wsp, wsp, #0 + \\ add wsp, wsp, #0, lsl #0 + \\ + \\ add x0, x0, #0 + \\ add x0, x1, #1, lsl #0 + \\ add sp, x2, #2, lsl #12 + \\ add x3, sp, #3, lsl #0 + \\ add sp, sp, #4095, lsl #12 + \\ add x0, x1, #0 + \\ add x2, x3, #0, lsl #0 + \\ add x4, sp, #0 + \\ add x5, sp, #0, lsl #0 + \\ add sp, x6, #0 + \\ add sp, x7, #0, lsl #0 + \\ add sp, sp, #0 + \\ add sp, sp, #0, lsl #0 + \\ + \\ add w0, w0, w0 + \\ add w1, w1, w2, lsl #0 + \\ add w3, w4, w5, lsl #1 + \\ add w6, w6, wzr, lsl #31 + \\ add w7, wzr, w8, lsr #0 + \\ add w9, wzr, wzr, lsr #30 + \\ add wzr, w10, w11, lsr #31 + \\ add wzr, w12, wzr, asr #0x0 + \\ add wzr, wzr, w13, asr #0x10 + \\ add wzr, wzr, wzr, asr #0x1f + \\ + \\ add x0, x0, x0 + \\ add x1, x1, x2, lsl #0 + \\ add x3, x4, x5, lsl #1 + \\ add x6, x6, xzr, lsl #63 + \\ add x7, xzr, x8, lsr #0 + \\ add x9, xzr, xzr, lsr #62 + \\ add xzr, x10, x11, lsr #63 + \\ add xzr, x12, xzr, asr #0x0 + \\ add xzr, xzr, x13, asr #0x1F + \\ add xzr, xzr, xzr, asr #0x3f + \\ + \\ sub w0, w0, w1 + \\ sub w2, w3, w4 + \\ sub wsp, w5, w6 + \\ sub w7, wsp, w8 + \\ sub wsp, wsp, w9 + \\ sub w10, w10, wzr + \\ sub w11, w12, wzr + \\ sub wsp, w13, wzr + \\ sub w14, wsp, wzr + \\ sub wsp, wsp, wzr + \\ + \\ sub x0, x0, x1 + \\ sub x2, x3, x4 + \\ sub sp, x5, x6 + \\ sub x7, sp, x8 + \\ sub sp, sp, x9 + \\ sub x10, x10, xzr + \\ sub x11, x12, xzr + \\ sub sp, x13, xzr + \\ sub x14, sp, xzr + \\ sub sp, sp, xzr + \\ + \\ sub w0, w0, w1 + \\ sub w2, w3, w4, uxtb #0 + \\ sub wsp, w5, w6, uxth #1 + \\ sub w7, wsp, w8, uxtw #0 + \\ sub wsp, wsp, w9, uxtw #2 + \\ sub w10, w10, wzr, uxtw #3 + \\ sub w11, w12, wzr, sxtb #4 + \\ sub wsp, w13, wzr, sxth #0 + \\ sub w14, wsp, wzr, sxtw #1 + \\ sub wsp, wsp, wzr, sxtw #2 + \\ + \\ sub x0, x0, x1 + \\ sub x2, x3, w4, uxtb #0 + \\ sub sp, x5, w6, uxth #1 + \\ sub x7, sp, w8, uxtw #2 + \\ sub sp, sp, x9, uxtx #0 + \\ sub x10, x10, xzr, uxtx #3 + \\ sub x11, x12, wzr, sxtb #4 + \\ sub sp, x13, wzr, sxth #0 + \\ sub x14, sp, wzr, sxtw #1 + \\ sub sp, sp, xzr, sxtx #2 + \\ + \\ sub w0, w0, #0 + \\ sub w0, w1, #1, lsl #0 + \\ sub wsp, w2, #2, lsl #12 + \\ sub w3, wsp, #3, lsl #0 + \\ sub wsp, wsp, #4095, lsl #12 + \\ sub w0, w1, #0 + \\ sub w2, w3, #0, lsl #0 + \\ sub w4, wsp, #0 + \\ sub w5, wsp, #0, lsl #0 + \\ sub wsp, w6, #0 + \\ sub wsp, w7, #0, lsl #0 + \\ sub wsp, wsp, #0 + \\ sub wsp, wsp, #0, lsl #0 + \\ + \\ sub x0, x0, #0 + \\ sub x0, x1, #1, lsl #0 + \\ sub sp, x2, #2, lsl #12 + \\ sub x3, sp, #3, lsl #0 + \\ sub sp, sp, #4095, lsl #12 + \\ sub x0, x1, #0 + \\ sub x2, x3, #0, lsl #0 + \\ sub x4, sp, #0 + \\ sub x5, sp, #0, lsl #0 + \\ sub sp, x6, #0 + \\ sub sp, x7, #0, lsl #0 + \\ sub sp, sp, #0 + \\ sub sp, sp, #0, lsl #0 + \\ + \\ sub w0, w0, w0 + \\ sub w1, w1, w2, lsl #0 + \\ sub w3, w4, w5, lsl #1 + \\ sub w6, w6, wzr, lsl #31 + \\ sub w7, wzr, w8, lsr #0 + \\ sub w9, wzr, wzr, lsr #30 + \\ sub wzr, w10, w11, lsr #31 + \\ sub wzr, w12, wzr, asr #0x0 + \\ sub wzr, wzr, w13, asr #0x10 + \\ sub wzr, wzr, wzr, asr #0x1f + \\ + \\ sub x0, x0, x0 + \\ sub x1, x1, x2, lsl #0 + \\ sub x3, x4, x5, lsl #1 + \\ sub x6, x6, xzr, lsl #63 + \\ sub x7, xzr, x8, lsr #0 + \\ sub x9, xzr, xzr, lsr #62 + \\ sub xzr, x10, x11, lsr #63 + \\ sub xzr, x12, xzr, asr #0x0 + \\ sub xzr, xzr, x13, asr #0x1F + \\ sub xzr, xzr, xzr, asr #0x3f + \\ + \\ neg w0, w0 + \\ neg w1, w2, lsl #0 + \\ neg w3, wzr, lsl #7 + \\ neg wzr, w4, lsr #14 + \\ neg wzr, wzr, asr #21 + \\ + \\ neg x0, x0 + \\ neg x1, x2, lsl #0 + \\ neg x3, xzr, lsl #11 + \\ neg xzr, x4, lsr #22 + \\ neg xzr, xzr, asr #33 + , + .operands = .empty, + }; + + try std.testing.expectFmt("add w0, w0, w1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w2, w3, w4", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wsp, w5, w6", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wsp, wsp, w9", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w10, w10, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w11, w12, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wsp, w13, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w14, wsp, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wsp, wsp, wzr", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("add x0, x0, x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x2, x3, x4", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add sp, x5, x6", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x7, sp, x8", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add sp, sp, x9", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x10, x10, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x11, x12, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add sp, x13, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x14, sp, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add sp, sp, xzr", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("add w0, w0, w1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w2, w3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wsp, w5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wsp, wsp, w9, uxtw #2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w10, w10, wzr, uxtw #3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w11, w12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wsp, w13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w14, wsp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wsp, wsp, wzr, sxtw #2", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("add x0, x0, x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x2, x3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add sp, x5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x7, sp, w8, uxtw #2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add sp, sp, x9", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x10, x10, xzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x11, x12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add sp, x13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x14, sp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add sp, sp, xzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("add w0, w0, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w0, w1, #0x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wsp, w2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w3, wsp, #0x3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wsp, wsp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w0, w1, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w2, w3, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov w4, wsp", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov w5, wsp", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wsp, w6", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wsp, w7", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wsp, wsp", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wsp, wsp", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("add x0, x0, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x0, x1, #0x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add sp, x2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x3, sp, #0x3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add sp, sp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x0, x1, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x2, x3, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x4, sp", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x5, sp", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov sp, x6", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov sp, x7", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov sp, sp", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov sp, sp", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("add w0, w0, w0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w1, w1, w2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("add x0, x0, x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x1, x1, x2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("add xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("sub w0, w0, w1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w2, w3, w4", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, w5, w6", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, wsp, w9", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w10, w10, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w11, w12, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, w13, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w14, wsp, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, wsp, wzr", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("sub x0, x0, x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x2, x3, x4", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, x5, x6", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x7, sp, x8", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, sp, x9", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x10, x10, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x11, x12, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, x13, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x14, sp, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, sp, xzr", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("sub w0, w0, w1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w2, w3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, w5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, wsp, w9, uxtw #2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w10, w10, wzr, uxtw #3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w11, w12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, w13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w14, wsp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, wsp, wzr, sxtw #2", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("sub x0, x0, x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x2, x3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, x5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x7, sp, w8, uxtw #2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, sp, x9", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x10, x10, xzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x11, x12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, x13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x14, sp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, sp, xzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("sub w0, w0, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w0, w1, #0x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, w2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w3, wsp, #0x3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, wsp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w0, w1, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w2, w3, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w4, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w5, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, w6, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, w7, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wsp, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("sub x0, x0, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x0, x1, #0x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, x2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x3, sp, #0x3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, sp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x0, x1, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x2, x3, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x4, sp, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x5, sp, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, x6, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, x7, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, sp, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub sp, sp, #0x0", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("sub w0, w0, w0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w1, w1, w2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg w7, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg w9, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("sub x0, x0, x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x1, x1, x2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg x7, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg x9, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sub xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("neg w0, w0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg w1, w2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg w3, wzr, lsl #7", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg wzr, w4, lsr #14", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg wzr, wzr, asr #21", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("neg x0, x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg x1, x2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg x3, xzr, lsl #11", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg xzr, x4, lsr #22", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("neg xzr, xzr, asr #33", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expect(null == try as.nextInstruction()); +} +test "bitfield" { + var as: Assemble = .{ + .source = + \\sbfm w0, w0, #0, #31 + \\sbfm w0, w0, #31, #0 + \\ + \\sbfm x0, x0, #0, #63 + \\sbfm x0, x0, #63, #0 + \\ + \\bfm w0, w0, #0, #31 + \\bfm w0, w0, #31, #0 + \\ + \\bfm x0, x0, #0, #63 + \\bfm x0, x0, #63, #0 + \\ + \\ubfm w0, w0, #0, #31 + \\ubfm w0, w0, #31, #0 + \\ + \\ubfm x0, x0, #0, #63 + \\ubfm x0, x0, #63, #0 + , + .operands = .empty, + }; + + try std.testing.expectFmt("sbfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sbfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("sbfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sbfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("bfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("bfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("bfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("bfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("ubfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ubfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("ubfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ubfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expect(null == try as.nextInstruction()); +} +test "branch register" { + var as: Assemble = .{ + .source = + \\ret + \\br x30 + \\blr x30 + \\ret x30 + \\br x29 + \\blr x29 + \\ret x29 + \\br x2 + \\blr x1 + \\ret x0 + , + .operands = .empty, + }; + + try std.testing.expectFmt("ret", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("br x30", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("blr x30", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ret", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("br x29", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("blr x29", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ret x29", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("br x2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("blr x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ret x0", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expect(null == try as.nextInstruction()); +} +test "exception generating" { + var as: Assemble = .{ + .source = + \\SVC #0 + \\HVC #0x1 + \\SMC #0o15 + \\BRK #42 + \\HLT #0x42 + \\TCANCEL #123 + \\DCPS1 #1234 + \\DCPS2 #12345 + \\DCPS3 #65535 + \\DCPS3 #0x0 + \\DCPS2 #0 + \\DCPS1 + , + .operands = .empty, + }; + + try std.testing.expectFmt("svc #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("hvc #0x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("smc #0xd", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("brk #0x2a", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("hlt #0x42", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tcancel #0x7b", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("dcps1 #0x4d2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("dcps2 #0x3039", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("dcps3 #0xffff", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("dcps3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("dcps2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("dcps1", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expect(null == try as.nextInstruction()); +} +test "extract" { + var as: Assemble = .{ + .source = + \\extr W0, W1, W2, #0 + \\extr W3, W3, W4, #1 + \\extr W5, W5, W5, #31 + \\ + \\extr X0, X1, X2, #0 + \\extr X3, X3, X4, #1 + \\extr X5, X5, X5, #63 + , + .operands = .empty, + }; + + try std.testing.expectFmt("extr w0, w1, w2, #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("extr w3, w3, w4, #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("extr w5, w5, w5, #31", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("extr x0, x1, x2, #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("extr x3, x3, x4, #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("extr x5, x5, x5, #63", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expect(null == try as.nextInstruction()); +} +test "hints" { + var as: Assemble = .{ + .source = + \\NOP + \\hint #0 + \\YiElD + \\Hint #0x1 + \\WfE + \\hInt #02 + \\wFi + \\hiNt #0b11 + \\sEv + \\hinT #4 + \\sevl + \\HINT #0b101 + \\hint #0x7F + , + .operands = .empty, + }; + + try std.testing.expectFmt("nop", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("nop", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("yield", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("yield", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("wfe", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("wfe", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("wfi", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("wfi", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sev", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sev", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sevl", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("sevl", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("hint #0x7f", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expect(null == try as.nextInstruction()); +} +test "load store" { + var as: Assemble = .{ + .source = + \\ LDP w0, w1, [x2], #-256 + \\ LDP w3, w4, [x5], #0 + \\ LDP w6, w7, [sp], #252 + \\ LDP w0, w1, [x2, #-0x100]! + \\ LDP w3, w4, [x5, #0]! + \\ LDP w6, w7, [sp, #0xfc]! + \\ LDP w0, w1, [x2, #-256] + \\ LDP w3, w4, [x5] + \\ LDP w6, w7, [x8, #0] + \\ LDP w9, w10, [sp, #252] + \\ + \\ LDP x0, x1, [x2], #-512 + \\ LDP x3, x4, [x5], #0 + \\ LDP x6, x7, [sp], #504 + \\ LDP x0, x1, [x2, #-0x200]! + \\ LDP x3, x4, [x5, #0]! + \\ LDP x6, x7, [sp, #0x1f8]! + \\ LDP x0, x1, [x2, #-512] + \\ LDP x3, x4, [x5] + \\ LDP x6, x7, [x8, #0] + \\ LDP x9, x10, [sp, #504] + \\ + \\ LDR w0, [x1], #-256 + \\ LDR w2, [x3], #0 + \\ LDR w4, [sp], #255 + \\ LDR w0, [x1, #-0x100]! + \\ LDR w2, [x3, #0]! + \\ LDR w4, [sp, #0xff]! + \\ LDR w0, [x1, #0] + \\ LDR w2, [x3] + \\ LDR w4, [sp, #16380] + \\ + \\ LDR x0, [x1], #-256 + \\ LDR x2, [x3], #0 + \\ LDR x4, [sp], #255 + \\ LDR x0, [x1, #-0x100]! + \\ LDR x2, [x3, #0]! + \\ LDR x4, [sp, #0xff]! + \\ LDR x0, [x1, #0] + \\ LDR x2, [x3] + \\ LDR x4, [sp, #32760] + \\ + \\ STP w0, w1, [x2], #-256 + \\ STP w3, w4, [x5], #0 + \\ STP w6, w7, [sp], #252 + \\ STP w0, w1, [x2, #-0x100]! + \\ STP w3, w4, [x5, #0]! + \\ STP w6, w7, [sp, #0xfc]! + \\ STP w0, w1, [x2, #-256] + \\ STP w3, w4, [x5] + \\ STP w6, w7, [x8, #0] + \\ STP w9, w10, [sp, #252] + \\ + \\ STP x0, x1, [x2], #-512 + \\ STP x3, x4, [x5], #0 + \\ STP x6, x7, [sp], #504 + \\ STP x0, x1, [x2, #-0x200]! + \\ STP x3, x4, [x5, #0]! + \\ STP x6, x7, [sp, #0x1f8]! + \\ STP x0, x1, [x2, #-512] + \\ STP x3, x4, [x5] + \\ STP x6, x7, [x8, #0] + \\ STP x9, x10, [sp, #504] + \\ + \\ STR w0, [x1], #-256 + \\ STR w2, [x3], #0 + \\ STR w4, [sp], #255 + \\ STR w0, [x1, #-0x100]! + \\ STR w2, [x3, #0]! + \\ STR w4, [sp, #0xff]! + \\ STR w0, [x1, #0] + \\ STR w2, [x3] + \\ STR w4, [sp, #16380] + \\ + \\ STR x0, [x1], #-256 + \\ STR x2, [x3], #0 + \\ STR x4, [sp], #255 + \\ STR x0, [x1, #-0x100]! + \\ STR x2, [x3, #0]! + \\ STR x4, [sp, #0xff]! + \\ STR x0, [x1, #0] + \\ STR x2, [x3] + \\ STR x4, [sp, #32760] + , + .operands = .empty, + }; + + try std.testing.expectFmt("ldp w0, w1, [x2], #-0x100", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp w3, w4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp w6, w7, [sp], #0xfc", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp w0, w1, [x2, #-0x100]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp w3, w4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp w6, w7, [sp, #0xfc]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp w0, w1, [x2, #-0x100]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp w3, w4, [x5]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp w6, w7, [x8]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp w9, w10, [sp, #0xfc]", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("ldp x0, x1, [x2], #-0x200", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp x3, x4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp x6, x7, [sp], #0x1f8", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp x0, x1, [x2, #-0x200]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp x3, x4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp x6, x7, [sp, #0x1f8]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp x0, x1, [x2, #-0x200]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp x3, x4, [x5]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp x6, x7, [x8]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldp x9, x10, [sp, #0x1f8]", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("ldr w0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr w2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr w4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr w0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr w2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr w4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr w0, [x1]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr w2, [x3]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr w4, [sp, #0x3ffc]", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("ldr x0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr x2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr x4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr x0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr x2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr x4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr x0, [x1]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr x2, [x3]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ldr x4, [sp, #0x7ff8]", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("stp w0, w1, [x2], #-0x100", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp w3, w4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp w6, w7, [sp], #0xfc", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp w0, w1, [x2, #-0x100]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp w3, w4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp w6, w7, [sp, #0xfc]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp w0, w1, [x2, #-0x100]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp w3, w4, [x5]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp w6, w7, [x8]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp w9, w10, [sp, #0xfc]", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("stp x0, x1, [x2], #-0x200", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp x3, x4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp x6, x7, [sp], #0x1f8", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp x0, x1, [x2, #-0x200]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp x3, x4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp x6, x7, [sp, #0x1f8]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp x0, x1, [x2, #-0x200]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp x3, x4, [x5]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp x6, x7, [x8]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("stp x9, x10, [sp, #0x1f8]", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("str w0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str w2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str w4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str w0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str w2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str w4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str w0, [x1]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str w2, [x3]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str w4, [sp, #0x3ffc]", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("str x0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str x2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str x4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str x0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str x2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str x4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str x0, [x1]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str x2, [x3]", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("str x4, [sp, #0x7ff8]", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expect(null == try as.nextInstruction()); +} +test "logical" { + var as: Assemble = .{ + .source = + \\ and w0, w0, w0 + \\ and w1, w1, w2, lsl #0 + \\ and w3, w4, w5, lsl #1 + \\ and w6, w6, wzr, lsl #31 + \\ and w7, wzr, w8, lsr #0 + \\ and w9, wzr, wzr, lsr #30 + \\ and wzr, w10, w11, lsr #31 + \\ and wzr, w12, wzr, asr #0x0 + \\ and wzr, wzr, w13, asr #0x10 + \\ and wzr, wzr, wzr, asr #0x1f + \\ and w0, w0, wzr + \\ and w1, w2, wzr, lsl #0 + \\ and w3, wzr, w3 + \\ and w4, wzr, w5, lsl #0 + \\ and w6, wzr, wzr + \\ and w7, wzr, wzr, lsl #0 + \\ and wzr, w8, wzr + \\ and wzr, w9, wzr, lsl #0 + \\ and wzr, wzr, w10 + \\ and wzr, wzr, w11, lsl #0 + \\ and wzr, wzr, wzr + \\ and wzr, wzr, wzr, lsl #0 + \\ + \\ and x0, x0, x0 + \\ and x1, x1, x2, lsl #0 + \\ and x3, x4, x5, lsl #1 + \\ and x6, x6, xzr, lsl #63 + \\ and x7, xzr, x8, lsr #0 + \\ and x9, xzr, xzr, lsr #62 + \\ and xzr, x10, x11, lsr #63 + \\ and xzr, x12, xzr, asr #0x0 + \\ and xzr, xzr, x13, asr #0x1F + \\ and xzr, xzr, xzr, asr #0x3f + \\ and x0, x0, xzr + \\ and x1, x2, xzr, lsl #0 + \\ and x3, xzr, x3 + \\ and x4, xzr, x5, lsl #0 + \\ and x6, xzr, xzr + \\ and x7, xzr, xzr, lsl #0 + \\ and xzr, x8, xzr + \\ and xzr, x9, xzr, lsl #0 + \\ and xzr, xzr, x10 + \\ and xzr, xzr, x11, lsl #0 + \\ and xzr, xzr, xzr + \\ and xzr, xzr, xzr, lsl #0 + \\ + \\ orr w0, w0, w0 + \\ orr w1, w1, w2, lsl #0 + \\ orr w3, w4, w5, lsl #1 + \\ orr w6, w6, wzr, lsl #31 + \\ orr w7, wzr, w8, lsr #0 + \\ orr w9, wzr, wzr, lsr #30 + \\ orr wzr, w10, w11, lsr #31 + \\ orr wzr, w12, wzr, asr #0x0 + \\ orr wzr, wzr, w13, asr #0x10 + \\ orr wzr, wzr, wzr, asr #0x1f + \\ orr w0, w0, wzr + \\ orr w1, w2, wzr, lsl #0 + \\ orr w3, wzr, w3 + \\ orr w4, wzr, w5, lsl #0 + \\ orr w6, wzr, wzr + \\ orr w7, wzr, wzr, lsl #0 + \\ orr wzr, w8, wzr + \\ orr wzr, w9, wzr, lsl #0 + \\ orr wzr, wzr, w10 + \\ orr wzr, wzr, w11, lsl #0 + \\ orr wzr, wzr, wzr + \\ orr wzr, wzr, wzr, lsl #0 + \\ + \\ orr x0, x0, x0 + \\ orr x1, x1, x2, lsl #0 + \\ orr x3, x4, x5, lsl #1 + \\ orr x6, x6, xzr, lsl #63 + \\ orr x7, xzr, x8, lsr #0 + \\ orr x9, xzr, xzr, lsr #62 + \\ orr xzr, x10, x11, lsr #63 + \\ orr xzr, x12, xzr, asr #0x0 + \\ orr xzr, xzr, x13, asr #0x1F + \\ orr xzr, xzr, xzr, asr #0x3f + \\ orr x0, x0, xzr + \\ orr x1, x2, xzr, lsl #0 + \\ orr x3, xzr, x3 + \\ orr x4, xzr, x5, lsl #0 + \\ orr x6, xzr, xzr + \\ orr x7, xzr, xzr, lsl #0 + \\ orr xzr, x8, xzr + \\ orr xzr, x9, xzr, lsl #0 + \\ orr xzr, xzr, x10 + \\ orr xzr, xzr, x11, lsl #0 + \\ orr xzr, xzr, xzr + \\ orr xzr, xzr, xzr, lsl #0 + \\ + \\ eor w0, w0, w0 + \\ eor w1, w1, w2, lsl #0 + \\ eor w3, w4, w5, lsl #1 + \\ eor w6, w6, wzr, lsl #31 + \\ eor w7, wzr, w8, lsr #0 + \\ eor w9, wzr, wzr, lsr #30 + \\ eor wzr, w10, w11, lsr #31 + \\ eor wzr, w12, wzr, asr #0x0 + \\ eor wzr, wzr, w13, asr #0x10 + \\ eor wzr, wzr, wzr, asr #0x1f + \\ eor w0, w0, wzr + \\ eor w1, w2, wzr, lsl #0 + \\ eor w3, wzr, w3 + \\ eor w4, wzr, w5, lsl #0 + \\ eor w6, wzr, wzr + \\ eor w7, wzr, wzr, lsl #0 + \\ eor wzr, w8, wzr + \\ eor wzr, w9, wzr, lsl #0 + \\ eor wzr, wzr, w10 + \\ eor wzr, wzr, w11, lsl #0 + \\ eor wzr, wzr, wzr + \\ eor wzr, wzr, wzr, lsl #0 + \\ + \\ eor x0, x0, x0 + \\ eor x1, x1, x2, lsl #0 + \\ eor x3, x4, x5, lsl #1 + \\ eor x6, x6, xzr, lsl #63 + \\ eor x7, xzr, x8, lsr #0 + \\ eor x9, xzr, xzr, lsr #62 + \\ eor xzr, x10, x11, lsr #63 + \\ eor xzr, x12, xzr, asr #0x0 + \\ eor xzr, xzr, x13, asr #0x1F + \\ eor xzr, xzr, xzr, asr #0x3f + \\ eor x0, x0, xzr + \\ eor x1, x2, xzr, lsl #0 + \\ eor x3, xzr, x3 + \\ eor x4, xzr, x5, lsl #0 + \\ eor x6, xzr, xzr + \\ eor x7, xzr, xzr, lsl #0 + \\ eor xzr, x8, xzr + \\ eor xzr, x9, xzr, lsl #0 + \\ eor xzr, xzr, x10 + \\ eor xzr, xzr, x11, lsl #0 + \\ eor xzr, xzr, xzr + \\ eor xzr, xzr, xzr, lsl #0 + \\ + \\ ands w0, w0, w0 + \\ ands w1, w1, w2, lsl #0 + \\ ands w3, w4, w5, lsl #1 + \\ ands w6, w6, wzr, lsl #31 + \\ ands w7, wzr, w8, lsr #0 + \\ ands w9, wzr, wzr, lsr #30 + \\ ands wzr, w10, w11, lsr #31 + \\ ands wzr, w12, wzr, asr #0x0 + \\ ands wzr, wzr, w13, asr #0x10 + \\ ands wzr, wzr, wzr, asr #0x1f + \\ ands w0, w0, wzr + \\ ands w1, w2, wzr, lsl #0 + \\ ands w3, wzr, w3 + \\ ands w4, wzr, w5, lsl #0 + \\ ands w6, wzr, wzr + \\ ands w7, wzr, wzr, lsl #0 + \\ ands wzr, w8, wzr + \\ ands wzr, w9, wzr, lsl #0 + \\ ands wzr, wzr, w10 + \\ ands wzr, wzr, w11, lsl #0 + \\ ands wzr, wzr, wzr + \\ ands wzr, wzr, wzr, lsl #0 + \\ + \\ ands x0, x0, x0 + \\ ands x1, x1, x2, lsl #0 + \\ ands x3, x4, x5, lsl #1 + \\ ands x6, x6, xzr, lsl #63 + \\ ands x7, xzr, x8, lsr #0 + \\ ands x9, xzr, xzr, lsr #62 + \\ ands xzr, x10, x11, lsr #63 + \\ ands xzr, x12, xzr, asr #0x0 + \\ ands xzr, xzr, x13, asr #0x1F + \\ ands xzr, xzr, xzr, asr #0x3f + \\ ands x0, x0, xzr + \\ ands x1, x2, xzr, lsl #0 + \\ ands x3, xzr, x3 + \\ ands x4, xzr, x5, lsl #0 + \\ ands x6, xzr, xzr + \\ ands x7, xzr, xzr, lsl #0 + \\ ands xzr, x8, xzr + \\ ands xzr, x9, xzr, lsl #0 + \\ ands xzr, xzr, x10 + \\ ands xzr, xzr, x11, lsl #0 + \\ ands xzr, xzr, xzr + \\ ands xzr, xzr, xzr, lsl #0 + , + .operands = .empty, + }; + + try std.testing.expectFmt("and w0, w0, w0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and w1, w1, w2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and w3, wzr, w3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and w4, wzr, w5", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and w6, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and w7, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and wzr, w8, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and wzr, w9, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and wzr, wzr, w10", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and wzr, wzr, w11", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("and x0, x0, x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and x1, x1, x2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and x3, xzr, x3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and x4, xzr, x5", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and x6, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and x7, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and xzr, x8, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and xzr, x9, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and xzr, xzr, x10", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and xzr, xzr, x11", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("and xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("orr w0, w0, w0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr w1, w1, w2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov w3, w3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov w4, w5", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov w6, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov w7, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr wzr, w8, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr wzr, w9, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wzr, w10", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wzr, w11", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("orr x0, x0, x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr x1, x1, x2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x3, x3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x4, x5", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x6, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x7, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr xzr, x8, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("orr xzr, x9, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, x10", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, x11", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("eor w0, w0, w0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor w1, w1, w2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor w3, wzr, w3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor w4, wzr, w5", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor w6, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor w7, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor wzr, w8, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor wzr, w9, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor wzr, wzr, w10", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor wzr, wzr, w11", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("eor x0, x0, x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor x1, x1, x2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor x3, xzr, x3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor x4, xzr, x5", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor x6, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor x7, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor xzr, x8, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor xzr, x9, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor xzr, xzr, x10", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor xzr, xzr, x11", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("eor xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("ands w0, w0, w0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands w1, w1, w2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands w3, wzr, w3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands w4, wzr, w5", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands w6, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands w7, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst w8, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst w9, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst wzr, w10", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst wzr, w11", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("ands x0, x0, x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands x1, x1, x2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands x3, xzr, x3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands x4, xzr, x5", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands x6, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("ands x7, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst x8, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst x9, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst xzr, x10", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst xzr, x11", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("tst xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expect(null == try as.nextInstruction()); +} +test "mov" { + var as: Assemble = .{ + .source = + \\MOV W0, #0 + \\MOV WZR, #0xffff + \\ + \\MOV X0, #0 + \\MOV XZR, #0xffff + \\ + \\MOV W0, WSP + \\MOV WSP, W1 + \\MOV WSP, WSP + \\MOV X0, SP + \\MOV SP, X1 + \\MOV SP, SP + \\ + \\MOV W0, W0 + \\MOV W1, W2 + \\MOV W3, WZR + \\MOV WZR, W4 + \\MOV WZR, WZR + \\MOV X0, X0 + \\MOV X1, X2 + \\MOV X3, XZR + \\MOV XZR, X4 + \\MOV XZR, XZR + \\ + \\MOVK W0, #0 + \\MOVK W1, #1, lsl #0 + \\MOVK W2, #2, lsl #16 + \\MOVK X3, #3 + \\MOVK X4, #4, lsl #0x00 + \\MOVK X5, #5, lsl #0x10 + \\MOVK X6, #6, lsl #0x20 + \\MOVK X7, #7, lsl #0x30 + \\ + \\MOVN W0, #8 + \\MOVN W1, #9, lsl #0 + \\MOVN W2, #10, lsl #16 + \\MOVN X3, #11 + \\MOVN X4, #12, lsl #0x00 + \\MOVN X5, #13, lsl #0x10 + \\MOVN X6, #14, lsl #0x20 + \\MOVN X7, #15, lsl #0x30 + \\ + \\MOVN WZR, #0, lsl #0 + \\MOVN WZR, #0, lsl #16 + \\MOVN XZR, #0, lsl #0 + \\MOVN XZR, #0, lsl #16 + \\MOVN XZR, #0, lsl #32 + \\MOVN XZR, #0, lsl #48 + \\ + \\MOVN WZR, #0xffff, lsl #0 + \\MOVN WZR, #0xffff, lsl #16 + \\MOVN XZR, #0xffff, lsl #0 + \\MOVN XZR, #0xffff, lsl #16 + \\MOVN XZR, #0xffff, lsl #32 + \\MOVN XZR, #0xffff, lsl #48 + \\ + \\MOVZ W0, #16 + \\MOVZ W1, #17, lsl #0 + \\MOVZ W2, #18, lsl #16 + \\MOVZ X3, #19 + \\MOVZ X4, #20, lsl #0x00 + \\MOVZ X5, #21, lsl #0x10 + \\MOVZ X6, #22, lsl #0x20 + \\MOVZ X7, #23, lsl #0x30 + \\ + \\MOVZ WZR, #0, lsl #0 + \\MOVZ WZR, #0, lsl #16 + \\MOVZ XZR, #0, lsl #0 + \\MOVZ XZR, #0, lsl #16 + \\MOVZ XZR, #0, lsl #32 + \\MOVZ XZR, #0, lsl #48 + \\ + \\MOVZ WZR, #0xffff, lsl #0 + \\MOVZ WZR, #0xffff, lsl #16 + \\MOVZ XZR, #0xffff, lsl #0 + \\MOVZ XZR, #0xffff, lsl #16 + \\MOVZ XZR, #0xffff, lsl #32 + \\MOVZ XZR, #0xffff, lsl #48 + , + .operands = .empty, + }; + + try std.testing.expectFmt("mov w0, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wzr, #0xffff", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x0, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, #0xffff", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("mov w0, wsp", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wsp, w1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wsp, wsp", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x0, sp", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov sp, x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov sp, sp", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("mov w0, w0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov w1, w2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov w3, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wzr, w4", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x0, x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x1, x2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x3, xzr", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, x4", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("movk w0, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movk w1, #0x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movk w2, #0x2, lsl #16", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movk x3, #0x3", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movk x4, #0x4", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movk x5, #0x5, lsl #16", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movk x6, #0x6, lsl #32", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movk x7, #0x7, lsl #48", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("mov w0, #-0x9", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov w1, #-0xa", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov w2, #-0xa0001", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x3, #-0xc", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x4, #-0xd", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x5, #-0xd0001", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x6, #-0xe00000001", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x7, #-0xf000000000001", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("mov wzr, #-0x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movn wzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, #-0x1", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movn xzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movn xzr, #0x0, lsl #32", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movn xzr, #0x0, lsl #48", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("movn wzr, #0xffff", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movn wzr, #0xffff, lsl #16", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, #-0x10000", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, #-0xffff0001", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, #-0xffff00000001", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, #0xffffffffffff", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("mov w0, #0x10", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov w1, #0x11", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov w2, #0x120000", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x3, #0x13", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x4, #0x14", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x5, #0x150000", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x6, #0x1600000000", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov x7, #0x17000000000000", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("mov wzr, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movz wzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movz xzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movz xzr, #0x0, lsl #32", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("movz xzr, #0x0, lsl #48", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expectFmt("mov wzr, #0xffff", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov wzr, #-0x10000", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, #0xffff", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, #0xffff0000", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, #0xffff00000000", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("mov xzr, #-0x1000000000000", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expect(null == try as.nextInstruction()); +} +test "reserved" { + var as: Assemble = .{ + .source = "\n\nudf #0x0\n\t\n\tudf\t#01234\n \nudf#65535", + .operands = .empty, + }; + + try std.testing.expectFmt("udf #0x0", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("udf #0x4d2", "{f}", .{(try as.nextInstruction()).?}); + try std.testing.expectFmt("udf #0xffff", "{f}", .{(try as.nextInstruction()).?}); + + try std.testing.expect(null == try as.nextInstruction()); +} + +const aarch64 = @import("../aarch64.zig"); +const Assemble = @This(); +const assert = std.debug.assert; +const Instruction = aarch64.encoding.Instruction; +const instructions = @import("instructions.zon"); +const std = @import("std"); +const log = std.log.scoped(.@"asm"); diff --git a/src/codegen/aarch64/Disassemble.zig b/src/codegen/aarch64/Disassemble.zig new file mode 100644 index 0000000000..e3b4df93d4 --- /dev/null +++ b/src/codegen/aarch64/Disassemble.zig @@ -0,0 +1,905 @@ +case: Case = .lower, +mnemonic_operands_separator: []const u8 = " ", +operands_separator: []const u8 = ", ", +enable_aliases: bool = true, + +pub const Case = enum { lower, upper }; + +pub fn printInstruction(dis: Disassemble, inst: Instruction, writer: *std.Io.Writer) std.Io.Writer.Error!void { + unallocated: switch (inst.decode()) { + .unallocated => break :unallocated, + .reserved => |reserved| switch (reserved.decode()) { + .unallocated => break :unallocated, + .udf => |udf| return writer.print("{f}{s}#0x{x}", .{ + fmtCase(.udf, dis.case), + dis.mnemonic_operands_separator, + udf.imm16, + }), + }, + .sme => {}, + .sve => {}, + .data_processing_immediate => |data_processing_immediate| switch (data_processing_immediate.decode()) { + .unallocated => break :unallocated, + .pc_relative_addressing => |pc_relative_addressing| { + const group = pc_relative_addressing.group; + const imm = (@as(i33, group.immhi) << 2 | @as(i33, group.immlo) << 0) + @as(i33, switch (group.op) { + .adr => Instruction.size, + .adrp => 0, + }); + return writer.print("{f}{s}{f}{s}.{c}0x{x}", .{ + fmtCase(group.op, dis.case), + dis.mnemonic_operands_separator, + group.Rd.decodeInteger(.doubleword, .{}).fmtCase(dis.case), + dis.operands_separator, + @as(u8, if (imm < 0) '-' else '+'), + switch (group.op) { + .adr => @abs(imm), + .adrp => @abs(imm) << 12, + }, + }); + }, + .add_subtract_immediate => |add_subtract_immediate| { + const group = add_subtract_immediate.group; + const op = group.op; + const S = group.S; + const sf = group.sf; + const sh = group.sh; + const imm12 = group.imm12; + const Rn = group.Rn.decodeInteger(sf, .{ .sp = true }); + const Rd = group.Rd.decodeInteger(sf, .{ .sp = !S }); + const elide_shift = sh == .@"0"; + if (dis.enable_aliases and op == .add and S == false and elide_shift and imm12 == 0 and + (Rn.alias == .sp or Rd.alias == .sp)) try writer.print("{f}{s}{f}{s}{f}", .{ + fmtCase(.mov, dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + Rn.fmtCase(dis.case), + }) else try writer.print("{f}{s}{s}{f}{s}{f}{s}#0x{x}", .{ + fmtCase(op, dis.case), + if (S) "s" else "", + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + Rn.fmtCase(dis.case), + dis.operands_separator, + imm12, + }); + return if (!elide_shift) writer.print("{s}{f} #{s}", .{ + dis.operands_separator, + fmtCase(.lsl, dis.case), + @tagName(sh), + }); + }, + .add_subtract_immediate_with_tags => {}, + .logical_immediate => |logical_immediate| { + const decoded = logical_immediate.decode(); + if (decoded == .unallocated) break :unallocated; + const group = logical_immediate.group; + const sf = group.sf; + const decoded_imm = group.imm.decodeImmediate(sf); + const imm = switch (sf) { + .word => @as(i32, @bitCast(@as(u32, @intCast(decoded_imm)))), + .doubleword => @as(i64, @bitCast(decoded_imm)), + }; + const Rn = group.Rn.decodeInteger(sf, .{}); + const Rd = group.Rd.decodeInteger(sf, .{ .sp = decoded != .ands }); + return if (dis.enable_aliases and decoded == .orr and Rn.alias == .zr and !group.imm.moveWidePreferred(sf)) writer.print("{f}{s}{f}{s}#{s}0x{x}", .{ + fmtCase(.mov, dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + if (imm < 0) "-" else "", + @abs(imm), + }) else if (dis.enable_aliases and decoded == .ands and Rd.alias == .zr) writer.print("{f}{s}{f}{s}#{s}0x{x}", .{ + fmtCase(.tst, dis.case), + dis.mnemonic_operands_separator, + Rn.fmtCase(dis.case), + dis.operands_separator, + if (imm < 0) "-" else "", + @abs(imm), + }) else writer.print("{f}{s}{f}{s}{f}{s}#0x{x}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + Rn.fmtCase(dis.case), + dis.operands_separator, + decoded_imm, + }); + }, + .move_wide_immediate => |move_wide_immediate| { + const decoded = move_wide_immediate.decode(); + if (decoded == .unallocated) break :unallocated; + const group = move_wide_immediate.group; + const sf = group.sf; + const hw = group.hw; + const imm16 = group.imm16; + const Rd = group.Rd.decodeInteger(sf, .{}); + const elide_shift = hw == .@"0"; + if (dis.enable_aliases and switch (decoded) { + .unallocated => unreachable, + .movz => elide_shift or group.imm16 != 0, + .movn => (elide_shift or group.imm16 != 0) and switch (sf) { + .word => group.imm16 != std.math.maxInt(u16), + .doubleword => true, + }, + .movk => false, + }) { + const decoded_imm = switch (sf) { + .word => @as(i32, @bitCast(@as(u32, group.imm16) << @intCast(hw.int()))), + .doubleword => @as(i64, @bitCast(@as(u64, group.imm16) << hw.int())), + }; + const imm = switch (decoded) { + .unallocated => unreachable, + .movz => decoded_imm, + .movn => ~decoded_imm, + .movk => unreachable, + }; + return writer.print("{f}{s}{f}{s}#{s}0x{x}", .{ + fmtCase(.mov, dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + if (imm < 0) "-" else "", + @abs(imm), + }); + } + try writer.print("{f}{s}{f}{s}#0x{x}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + imm16, + }); + return if (!elide_shift) writer.print("{s}{f} #{s}", .{ + dis.operands_separator, + fmtCase(.lsl, dis.case), + @tagName(hw), + }); + }, + .bitfield => |bitfield| { + const decoded = bitfield.decode(); + if (decoded == .unallocated) break :unallocated; + const group = bitfield.group; + const sf = group.sf; + return writer.print("{f}{s}{f}{s}{f}{s}#{d}{s}#{d}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.imm.immr, + dis.operands_separator, + group.imm.imms, + }); + }, + .extract => |extract| { + const decoded = extract.decode(); + if (decoded == .unallocated) break :unallocated; + const group = extract.group; + const sf = group.sf; + return writer.print("{f}{s}{f}{s}{f}{s}{f}{s}#{d}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rm.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.imms, + }); + }, + }, + .branch_exception_generating_system => |branch_exception_generating_system| switch (branch_exception_generating_system.decode()) { + .unallocated => break :unallocated, + .conditional_branch_immediate => |conditional_branch_immediate| { + const decoded = conditional_branch_immediate.decode(); + if (decoded == .unallocated) break :unallocated; + const group = conditional_branch_immediate.group; + const imm = @as(i21, group.imm19); + return writer.print("{f}.{f}{s}.{c}0x{x}", .{ + fmtCase(decoded, dis.case), + fmtCase(group.cond, dis.case), + dis.mnemonic_operands_separator, + @as(u8, if (imm < 0) '-' else '+'), + @abs(imm) << 2, + }); + }, + .exception_generating => |exception_generating| { + const decoded = exception_generating.decode(); + switch (decoded) { + .unallocated => break :unallocated, + .svc, .hvc, .smc, .brk, .hlt, .tcancel => {}, + .dcps1, .dcps2, .dcps3 => switch (exception_generating.group.imm16) { + 0 => return writer.print("{f}", .{fmtCase(decoded, dis.case)}), + else => {}, + }, + } + return switch (exception_generating.group.imm16) { + 0 => writer.print("{f}{s}#0", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + }), + else => writer.print("{f}{s}#0x{x}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + exception_generating.group.imm16, + }), + }; + }, + .system_register_argument => {}, + .hints => |hints| switch (hints.decode()) { + .hint => |hint| return writer.print("{f}{s}#0x{x}", .{ + fmtCase(.hint, dis.case), + dis.mnemonic_operands_separator, + @as(u7, hint.CRm) << 3 | @as(u7, hint.op2) << 0, + }), + else => |decoded| return writer.print("{f}", .{fmtCase(decoded, dis.case)}), + }, + .barriers => {}, + .pstate => {}, + .system_result => {}, + .system => {}, + .system_register_move => {}, + .unconditional_branch_register => |unconditional_branch_register| { + const decoded = unconditional_branch_register.decode(); + if (decoded == .unallocated) break :unallocated; + const group = unconditional_branch_register.group; + const Rn = group.Rn.decodeInteger(.doubleword, .{}); + try writer.print("{f}", .{fmtCase(decoded, dis.case)}); + return if (decoded != .ret or Rn.alias != .r30) try writer.print("{s}{f}", .{ + dis.mnemonic_operands_separator, + Rn.fmtCase(dis.case), + }); + }, + .unconditional_branch_immediate => |unconditional_branch_immediate| { + const group = unconditional_branch_immediate.group; + const imm = @as(i28, group.imm26); + return writer.print("{f}{s}.{c}0x{x}", .{ + fmtCase(group.op, dis.case), + dis.mnemonic_operands_separator, + @as(u8, if (imm < 0) '-' else '+'), + @abs(imm) << 2, + }); + }, + .compare_branch_immediate => |compare_branch_immediate| { + const group = compare_branch_immediate.group; + const imm = @as(i21, group.imm19); + return writer.print("{f}{s}{f}{s}.{c}0x{x}", .{ + fmtCase(group.op, dis.case), + dis.mnemonic_operands_separator, + group.Rt.decodeInteger(group.sf, .{}).fmtCase(dis.case), + dis.operands_separator, + @as(u8, if (imm < 0) '-' else '+'), + @abs(imm) << 2, + }); + }, + .test_branch_immediate => |test_branch_immediate| { + const group = test_branch_immediate.group; + const imm = @as(i16, group.imm14); + return writer.print("{f}{s}{f}{s}#0x{d}{s}.{c}0x{x}", .{ + fmtCase(group.op, dis.case), + dis.mnemonic_operands_separator, + group.Rt.decodeInteger(@enumFromInt(group.b5), .{}).fmtCase(dis.case), + dis.operands_separator, + @as(u6, group.b5) << 5 | + @as(u6, group.b40) << 0, + dis.operands_separator, + @as(u8, if (imm < 0) '-' else '+'), + @abs(imm) << 2, + }); + }, + }, + .load_store => |load_store| switch (load_store.decode()) { + .unallocated => break :unallocated, + .register_literal => {}, + .memory => {}, + .no_allocate_pair_offset => {}, + .register_pair_post_indexed => |register_pair_post_indexed| switch (register_pair_post_indexed.decode()) { + .integer => |integer| { + const decoded = integer.decode(); + if (decoded == .unallocated) break :unallocated; + const group = integer.group; + const sf: aarch64.encoding.Register.IntegerSize = @enumFromInt(group.opc >> 1); + return writer.print("{f}{s}{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rt2.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), + dis.operands_separator, + if (group.imm7 < 0) "-" else "", + @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)), + }); + }, + .vector => |vector| { + const decoded = vector.decode(); + if (decoded == .unallocated) break :unallocated; + const group = vector.group; + const vs = group.opc.decode(); + return writer.print("{f}{s}{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rt.decodeVector(vs).fmtCase(dis.case), + dis.operands_separator, + group.Rt2.decodeVector(vs).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), + dis.operands_separator, + if (group.imm7 < 0) "-" else "", + @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)), + }); + }, + }, + .register_pair_offset => |register_pair_offset| switch (register_pair_offset.decode()) { + .integer => |integer| { + const decoded = integer.decode(); + if (decoded == .unallocated) break :unallocated; + const group = integer.group; + const sf: aarch64.encoding.Register.IntegerSize = @enumFromInt(group.opc >> 1); + try writer.print("{f}{s}{f}{s}{f}{s}[{f}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rt2.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), + }); + if (group.imm7 != 0) try writer.print("{s}#{s}0x{x}", .{ + dis.operands_separator, + if (group.imm7 < 0) "-" else "", + @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)), + }); + return writer.writeByte(']'); + }, + .vector => |vector| { + const decoded = vector.decode(); + if (decoded == .unallocated) break :unallocated; + const group = vector.group; + const vs = group.opc.decode(); + try writer.print("{f}{s}{f}{s}{f}{s}[{f}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rt.decodeVector(vs).fmtCase(dis.case), + dis.operands_separator, + group.Rt2.decodeVector(vs).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), + }); + if (group.imm7 != 0) try writer.print("{s}#{s}0x{x}", .{ + dis.operands_separator, + if (group.imm7 < 0) "-" else "", + @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)), + }); + return writer.writeByte(']'); + }, + }, + .register_pair_pre_indexed => |register_pair_pre_indexed| switch (register_pair_pre_indexed.decode()) { + .integer => |integer| { + const decoded = integer.decode(); + if (decoded == .unallocated) break :unallocated; + const group = integer.group; + const sf: aarch64.encoding.Register.IntegerSize = @enumFromInt(group.opc >> 1); + return writer.print("{f}{s}{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rt2.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), + dis.operands_separator, + if (group.imm7 < 0) "-" else "", + @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)), + }); + }, + .vector => |vector| { + const decoded = vector.decode(); + if (decoded == .unallocated) break :unallocated; + const group = vector.group; + const vs = group.opc.decode(); + return writer.print("{f}{s}{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rt.decodeVector(vs).fmtCase(dis.case), + dis.operands_separator, + group.Rt2.decodeVector(vs).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), + dis.operands_separator, + if (group.imm7 < 0) "-" else "", + @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)), + }); + }, + }, + .register_unscaled_immediate => {}, + .register_immediate_post_indexed => |register_immediate_post_indexed| switch (register_immediate_post_indexed.decode()) { + .integer => |integer| { + const decoded = integer.decode(); + const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) { + .unallocated => break :unallocated, + .strb, .ldrb, .strh, .ldrh => .word, + inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) { + 0b0 => .doubleword, + 0b1 => .word, + }, + .ldrsw => .doubleword, + inline .str, .ldr => |encoded| encoded.sf, + }; + const group = integer.group; + return writer.print("{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), + dis.operands_separator, + if (group.imm9 < 0) "-" else "", + @abs(group.imm9), + }); + }, + .vector => {}, + }, + .register_unprivileged => {}, + .register_immediate_pre_indexed => |register_immediate_pre_indexed| switch (register_immediate_pre_indexed.decode()) { + .integer => |integer| { + const decoded = integer.decode(); + const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) { + .unallocated => break :unallocated, + inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) { + 0b0 => .doubleword, + 0b1 => .word, + }, + .strb, .ldrb, .strh, .ldrh => .word, + .ldrsw => .doubleword, + inline .str, .ldr => |encoded| encoded.sf, + }; + const group = integer.group; + return writer.print("{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), + dis.operands_separator, + if (group.imm9 < 0) "-" else "", + @abs(group.imm9), + }); + }, + .vector => |vector| { + const decoded = vector.decode(); + if (decoded == .unallocated) break :unallocated; + const group = vector.group; + return writer.print("{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rt.decodeVector(group.opc1.decode(group.size)).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), + dis.operands_separator, + if (group.imm9 < 0) "-" else "", + @abs(group.imm9), + }); + }, + }, + .register_register_offset => |register_register_offset| switch (register_register_offset.decode()) { + .integer => |integer| { + const decoded = integer.decode(); + const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) { + .unallocated, .prfm => break :unallocated, + .strb, .ldrb, .strh, .ldrh => .word, + inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) { + 0b0 => .doubleword, + 0b1 => .word, + }, + .ldrsw => .doubleword, + inline .str, .ldr => |encoded| encoded.sf, + }; + const group = integer.group; + try writer.print("{f}{s}{f}{s}[{f}{s}{f}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), + dis.operands_separator, + group.Rm.decodeInteger(group.option.sf(), .{}).fmtCase(dis.case), + }); + if (group.option != .lsl or group.S) { + try writer.print("{s}{f}", .{ + dis.operands_separator, + fmtCase(group.option, dis.case), + }); + if (group.S) try writer.print(" #{d}", .{ + @intFromEnum(group.size), + }); + } + return writer.writeByte(']'); + }, + .vector => {}, + }, + .register_unsigned_immediate => |register_unsigned_immediate| switch (register_unsigned_immediate.decode()) { + .integer => |integer| { + const decoded = integer.decode(); + const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) { + .unallocated, .prfm => break :unallocated, + .strb, .ldrb, .strh, .ldrh => .word, + inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) { + 0b0 => .doubleword, + 0b1 => .word, + }, + .ldrsw => .doubleword, + inline .str, .ldr => |encoded| encoded.sf, + }; + const group = integer.group; + try writer.print("{f}{s}{f}{s}[{f}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), + }); + if (group.imm12 > 0) try writer.print("{s}#0x{x}", .{ + dis.operands_separator, + @as(u15, group.imm12) << @intFromEnum(group.size), + }); + return writer.writeByte(']'); + }, + .vector => {}, + }, + }, + .data_processing_register => |data_processing_register| switch (data_processing_register.decode()) { + .unallocated => break :unallocated, + .data_processing_two_source => |data_processing_two_source| { + const decoded = data_processing_two_source.decode(); + if (decoded == .unallocated) break :unallocated; + const group = data_processing_two_source.group; + const sf = group.sf; + return writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rm.decodeInteger(sf, .{}).fmtCase(dis.case), + }); + }, + .data_processing_one_source => |data_processing_one_source| { + const decoded = data_processing_one_source.decode(); + if (decoded == .unallocated) break :unallocated; + const group = data_processing_one_source.group; + const sf = group.sf; + return writer.print("{f}{s}{f}{s}{f}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case), + }); + }, + .logical_shifted_register => |logical_shifted_register| { + const decoded = logical_shifted_register.decode(); + if (decoded == .unallocated) break :unallocated; + const group = logical_shifted_register.group; + const sf = group.sf; + const shift = group.shift; + const Rm = group.Rm.decodeInteger(sf, .{}); + const amount = group.imm6; + const Rn = group.Rn.decodeInteger(sf, .{}); + const Rd = group.Rd.decodeInteger(sf, .{}); + const elide_shift = shift == .lsl and amount == 0; + if (dis.enable_aliases and switch (decoded) { + else => false, + .orr => elide_shift, + .orn => true, + } and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{ + fmtCase(@as(enum { mov, mvn }, switch (decoded) { + else => unreachable, + .orr => .mov, + .orn => .mvn, + }), dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + Rm.fmtCase(dis.case), + }) else if (dis.enable_aliases and decoded == .ands and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{ + fmtCase(.tst, dis.case), + dis.mnemonic_operands_separator, + Rn.fmtCase(dis.case), + dis.operands_separator, + Rm.fmtCase(dis.case), + }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + Rn.fmtCase(dis.case), + dis.operands_separator, + Rm.fmtCase(dis.case), + }); + return if (!elide_shift) writer.print("{s}{f} #{d}", .{ + dis.operands_separator, + fmtCase(shift, dis.case), + amount, + }); + }, + .add_subtract_shifted_register => |add_subtract_shifted_register| { + const decoded = add_subtract_shifted_register.decode(); + if (decoded == .unallocated) break :unallocated; + const group = add_subtract_shifted_register.group; + const sf = group.sf; + const shift = group.shift; + const Rm = group.Rm.decodeInteger(sf, .{}); + const imm6 = group.imm6; + const Rn = group.Rn.decodeInteger(sf, .{}); + const Rd = group.Rd.decodeInteger(sf, .{}); + if (dis.enable_aliases and group.S and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{ + fmtCase(@as(enum { cmn, cmp }, switch (group.op) { + .add => .cmn, + .sub => .cmp, + }), dis.case), + dis.mnemonic_operands_separator, + Rn.fmtCase(dis.case), + dis.operands_separator, + Rm.fmtCase(dis.case), + }) else if (dis.enable_aliases and group.op == .sub and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{ + fmtCase(@as(enum { neg, negs }, switch (group.S) { + false => .neg, + true => .negs, + }), dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + Rm.fmtCase(dis.case), + }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + Rn.fmtCase(dis.case), + dis.operands_separator, + Rm.fmtCase(dis.case), + }); + return if (shift != .lsl or imm6 != 0) return writer.print("{s}{f} #{d}", .{ + dis.operands_separator, + fmtCase(shift, dis.case), + imm6, + }); + }, + .add_subtract_extended_register => |add_subtract_extended_register| { + const decoded = add_subtract_extended_register.decode(); + if (decoded == .unallocated) break :unallocated; + const group = add_subtract_extended_register.group; + const sf = group.sf; + const Rm = group.Rm.decodeInteger(group.option.sf(), .{}); + const Rn = group.Rn.decodeInteger(sf, .{ .sp = true }); + const Rd = group.Rd.decodeInteger(sf, .{ .sp = true }); + if (dis.enable_aliases and group.S and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{ + fmtCase(@as(enum { cmn, cmp }, switch (group.op) { + .add => .cmn, + .sub => .cmp, + }), dis.case), + dis.mnemonic_operands_separator, + Rn.fmtCase(dis.case), + dis.operands_separator, + Rm.fmtCase(dis.case), + }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + Rn.fmtCase(dis.case), + dis.operands_separator, + Rm.fmtCase(dis.case), + }); + return if (group.option != @as(Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option, switch (sf) { + .word => .uxtw, + .doubleword => .uxtx, + }) or group.imm3 != 0) writer.print("{s}{f} #{d}", .{ + dis.operands_separator, + fmtCase(group.option, dis.case), + group.imm3, + }); + }, + .add_subtract_with_carry => |add_subtract_with_carry| { + const decoded = add_subtract_with_carry.decode(); + const group = add_subtract_with_carry.group; + const sf = group.sf; + const Rm = group.Rm.decodeInteger(sf, .{}); + const Rn = group.Rn.decodeInteger(sf, .{}); + const Rd = group.Rd.decodeInteger(sf, .{}); + return if (dis.enable_aliases and group.op == .sbc and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{ + fmtCase(@as(enum { ngc, ngcs }, switch (group.S) { + false => .ngc, + true => .ngcs, + }), dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + Rm.fmtCase(dis.case), + }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + Rn.fmtCase(dis.case), + dis.operands_separator, + Rm.fmtCase(dis.case), + }); + }, + .rotate_right_into_flags => {}, + .evaluate_into_flags => {}, + .conditional_compare_register => {}, + .conditional_compare_immediate => {}, + .conditional_select => |conditional_select| { + const decoded = conditional_select.decode(); + if (decoded == .unallocated) break :unallocated; + const group = conditional_select.group; + const sf = group.sf; + const Rm = group.Rm.decodeInteger(sf, .{}); + const cond = group.cond; + const Rn = group.Rn.decodeInteger(sf, .{}); + const Rd = group.Rd.decodeInteger(sf, .{}); + return if (dis.enable_aliases and group.op != group.op2 and Rm.alias == .zr and cond != .al and cond != .nv and Rn.alias == Rm.alias) writer.print("{f}{s}{f}{s}{f}", .{ + fmtCase(@as(enum { cset, csetm }, switch (decoded) { + else => unreachable, + .csinc => .cset, + .csinv => .csetm, + }), dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + fmtCase(cond.invert(), dis.case), + }) else if (dis.enable_aliases and decoded != .csel and cond != .al and cond != .nv and Rn.alias == Rm.alias) writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ + fmtCase(@as(enum { cinc, cinv, cneg }, switch (decoded) { + else => unreachable, + .csinc => .cinc, + .csinv => .cinv, + .csneg => .cneg, + }), dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + Rn.fmtCase(dis.case), + dis.operands_separator, + fmtCase(cond.invert(), dis.case), + }) else writer.print("{f}{s}{f}{s}{f}{s}{f}{s}{f}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + Rd.fmtCase(dis.case), + dis.operands_separator, + Rn.fmtCase(dis.case), + dis.operands_separator, + Rm.fmtCase(dis.case), + dis.operands_separator, + fmtCase(cond, dis.case), + }); + }, + .data_processing_three_source => |data_processing_three_source| { + const decoded = data_processing_three_source.decode(); + if (decoded == .unallocated) break :unallocated; + const group = data_processing_three_source.group; + const sf = group.sf; + try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ + fmtCase(decoded, dis.case), + dis.mnemonic_operands_separator, + group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case), + dis.operands_separator, + group.Rm.decodeInteger(sf, .{}).fmtCase(dis.case), + }); + return switch (decoded) { + .unallocated => unreachable, + .madd, .msub, .smaddl, .smsubl, .umaddl, .umsubl => writer.print("{s}{f}", .{ + dis.operands_separator, + group.Ra.decodeInteger(sf, .{}).fmtCase(dis.case), + }), + .smulh, .umulh => {}, + }; + }, + }, + .data_processing_vector => {}, + } + return writer.print(".{f}{s}0x{x:0>8}", .{ + fmtCase(.word, dis.case), + dis.mnemonic_operands_separator, + @as(Instruction.Backing, @bitCast(inst)), + }); +} + +fn fmtCase(tag: anytype, case: Case) struct { + tag: []const u8, + case: Case, + pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { + for (data.tag) |c| try writer.writeByte(switch (data.case) { + .lower => std.ascii.toLower(c), + .upper => std.ascii.toUpper(c), + }); + } +} { + return .{ .tag = @tagName(tag), .case = case }; +} + +pub const RegisterFormatter = struct { + reg: aarch64.encoding.Register, + case: Case, + pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { + switch (data.reg.format) { + .alias => try writer.print("{f}", .{fmtCase(data.reg.alias, data.case)}), + .integer => |size| switch (data.reg.alias) { + .r0, + .r1, + .r2, + .r3, + .r4, + .r5, + .r6, + .r7, + .r8, + .r9, + .r10, + .r11, + .r12, + .r13, + .r14, + .r15, + .r16, + .r17, + .r18, + .r19, + .r20, + .r21, + .r22, + .r23, + .r24, + .r25, + .r26, + .r27, + .r28, + .r29, + .r30, + => |alias| try writer.print("{c}{d}", .{ + size.prefix(), + @intFromEnum(alias.encode(.{})), + }), + .zr => try writer.print("{c}{f}", .{ + size.prefix(), + fmtCase(data.reg.alias, data.case), + }), + else => try writer.print("{s}{f}", .{ + switch (size) { + .word => "w", + .doubleword => "", + }, + fmtCase(data.reg.alias, data.case), + }), + }, + .scalar => |size| try writer.print("{c}{d}", .{ + size.prefix(), + @intFromEnum(data.reg.alias.encode(.{ .V = true })), + }), + .vector => |arrangement| try writer.print("{f}.{f}", .{ + fmtCase(data.reg.alias, data.case), + fmtCase(arrangement, data.case), + }), + .element => |element| try writer.print("{f}.{c}[{d}]", .{ + fmtCase(data.reg.alias, data.case), + element.size.prefix(), + element.index, + }), + } + } +}; + +const aarch64 = @import("../aarch64.zig"); +const Disassemble = @This(); +const Instruction = aarch64.encoding.Instruction; +const std = @import("std"); diff --git a/src/codegen/aarch64/Mir.zig b/src/codegen/aarch64/Mir.zig new file mode 100644 index 0000000000..1446238888 --- /dev/null +++ b/src/codegen/aarch64/Mir.zig @@ -0,0 +1,275 @@ +prologue: []const Instruction, +body: []const Instruction, +epilogue: []const Instruction, +literals: []const u32, +nav_relocs: []const Reloc.Nav, +uav_relocs: []const Reloc.Uav, +global_relocs: []const Reloc.Global, +literal_relocs: []const Reloc.Literal, + +pub const Reloc = struct { + label: u32, + addend: u64 align(@alignOf(u32)) = 0, + + pub const Nav = struct { + nav: InternPool.Nav.Index, + reloc: Reloc, + }; + + pub const Uav = struct { + uav: InternPool.Key.Ptr.BaseAddr.Uav, + reloc: Reloc, + }; + + pub const Global = struct { + global: [*:0]const u8, + reloc: Reloc, + }; + + pub const Literal = struct { + label: u32, + }; +}; + +pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { + assert(mir.body.ptr + mir.body.len == mir.prologue.ptr); + assert(mir.prologue.ptr + mir.prologue.len == mir.epilogue.ptr); + gpa.free(mir.body.ptr[0 .. mir.body.len + mir.prologue.len + mir.epilogue.len]); + gpa.free(mir.literals); + gpa.free(mir.nav_relocs); + gpa.free(mir.uav_relocs); + gpa.free(mir.global_relocs); + gpa.free(mir.literal_relocs); + mir.* = undefined; +} + +pub fn emit( + mir: Mir, + lf: *link.File, + pt: Zcu.PerThread, + src_loc: Zcu.LazySrcLoc, + func_index: InternPool.Index, + code: *std.ArrayListUnmanaged(u8), + debug_output: link.File.DebugInfoOutput, +) !void { + _ = debug_output; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; + const gpa = zcu.gpa; + const func = zcu.funcInfo(func_index); + const nav = ip.getNav(func.owner_nav); + const mod = zcu.navFileScope(func.owner_nav).mod.?; + const target = &mod.resolved_target.result; + mir_log.debug("{f}:", .{nav.fqn.fmt(ip)}); + + const func_align = switch (nav.status.fully_resolved.alignment) { + .none => switch (mod.optimize_mode) { + .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), + .ReleaseSmall => target_util.minFunctionAlignment(target), + }, + else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), + }; + const code_len = mir.prologue.len + mir.body.len + mir.epilogue.len; + const literals_align_gap = -%code_len & (@divExact( + @as(u5, @intCast(func_align.minStrict(.@"16").toByteUnits().?)), + Instruction.size, + ) - 1); + try code.ensureUnusedCapacity(gpa, Instruction.size * + (code_len + literals_align_gap + mir.literals.len)); + emitInstructionsForward(code, mir.prologue); + emitInstructionsBackward(code, mir.body); + const body_end: u32 = @intCast(code.items.len); + emitInstructionsBackward(code, mir.epilogue); + code.appendNTimesAssumeCapacity(0, Instruction.size * literals_align_gap); + code.appendSliceAssumeCapacity(@ptrCast(mir.literals)); + mir_log.debug("", .{}); + + for (mir.nav_relocs) |nav_reloc| try emitReloc( + lf, + zcu, + func.owner_nav, + switch (try @import("../../codegen.zig").genNavRef( + lf, + pt, + src_loc, + nav_reloc.nav, + &mod.resolved_target.result, + )) { + .sym_index => |sym_index| sym_index, + .fail => |em| return zcu.codegenFailMsg(func.owner_nav, em), + }, + mir.body[nav_reloc.reloc.label], + body_end - Instruction.size * (1 + nav_reloc.reloc.label), + nav_reloc.reloc.addend, + ); + for (mir.uav_relocs) |uav_reloc| try emitReloc( + lf, + zcu, + func.owner_nav, + switch (try lf.lowerUav( + pt, + uav_reloc.uav.val, + ZigType.fromInterned(uav_reloc.uav.orig_ty).ptrAlignment(zcu), + src_loc, + )) { + .sym_index => |sym_index| sym_index, + .fail => |em| return zcu.codegenFailMsg(func.owner_nav, em), + }, + mir.body[uav_reloc.reloc.label], + body_end - Instruction.size * (1 + uav_reloc.reloc.label), + uav_reloc.reloc.addend, + ); + for (mir.global_relocs) |global_reloc| try emitReloc( + lf, + zcu, + func.owner_nav, + if (lf.cast(.elf)) |ef| + try ef.getGlobalSymbol(std.mem.span(global_reloc.global), null) + else if (lf.cast(.macho)) |mf| + try mf.getGlobalSymbol(std.mem.span(global_reloc.global), null) + else if (lf.cast(.coff)) |cf| + try cf.getGlobalSymbol(std.mem.span(global_reloc.global), "compiler_rt") + else + return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}), + mir.body[global_reloc.reloc.label], + body_end - Instruction.size * (1 + global_reloc.reloc.label), + global_reloc.reloc.addend, + ); + const literal_reloc_offset: i19 = @intCast(mir.epilogue.len + literals_align_gap); + for (mir.literal_relocs) |literal_reloc| { + var instruction = mir.body[literal_reloc.label]; + instruction.load_store.register_literal.group.imm19 += literal_reloc_offset; + instruction.write( + code.items[body_end - Instruction.size * (1 + literal_reloc.label) ..][0..Instruction.size], + ); + } +} + +fn emitInstructionsForward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void { + for (instructions) |instruction| emitInstruction(code, instruction); +} +fn emitInstructionsBackward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void { + var instruction_index = instructions.len; + while (instruction_index > 0) { + instruction_index -= 1; + emitInstruction(code, instructions[instruction_index]); + } +} +fn emitInstruction(code: *std.ArrayListUnmanaged(u8), instruction: Instruction) void { + mir_log.debug(" {f}", .{instruction}); + instruction.write(code.addManyAsArrayAssumeCapacity(Instruction.size)); +} + +fn emitReloc( + lf: *link.File, + zcu: *Zcu, + owner_nav: InternPool.Nav.Index, + sym_index: u32, + instruction: Instruction, + offset: u32, + addend: u64, +) !void { + const gpa = zcu.gpa; + switch (instruction.decode()) { + else => unreachable, + .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| { + const zo = ef.zigObjectPtr().?; + const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; + const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) { + .b => .JUMP26, + .bl => .CALL26, + }; + try atom.addReloc(gpa, .{ + .r_offset = offset, + .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type), + .r_addend = @bitCast(addend), + }, zo); + } else if (lf.cast(.macho)) |mf| { + const zo = mf.getZigObject().?; + const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; + try atom.addReloc(mf, .{ + .tag = .@"extern", + .offset = offset, + .target = sym_index, + .addend = @bitCast(addend), + .type = .branch, + .meta = .{ + .pcrel = true, + .has_subtractor = false, + .length = 2, + .symbolnum = @intCast(sym_index), + }, + }); + }, + .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| { + const zo = ef.zigObjectPtr().?; + const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; + const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) { + else => unreachable, + .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) { + .adr => .ADR_PREL_LO21, + .adrp => .ADR_PREL_PG_HI21, + }, + .add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) { + .add => .ADD_ABS_LO12_NC, + .sub => unreachable, + }, + }; + try atom.addReloc(gpa, .{ + .r_offset = offset, + .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type), + .r_addend = @bitCast(addend), + }, zo); + } else if (lf.cast(.macho)) |mf| { + const zo = mf.getZigObject().?; + const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; + switch (decoded.decode()) { + else => unreachable, + .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) { + .adr => unreachable, + .adrp => try atom.addReloc(mf, .{ + .tag = .@"extern", + .offset = offset, + .target = sym_index, + .addend = @bitCast(addend), + .type = .page, + .meta = .{ + .pcrel = true, + .has_subtractor = false, + .length = 2, + .symbolnum = @intCast(sym_index), + }, + }), + }, + .add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) { + .add => try atom.addReloc(mf, .{ + .tag = .@"extern", + .offset = offset, + .target = sym_index, + .addend = @bitCast(addend), + .type = .pageoff, + .meta = .{ + .pcrel = false, + .has_subtractor = false, + .length = 2, + .symbolnum = @intCast(sym_index), + }, + }), + .sub => unreachable, + }, + } + }, + } +} + +const Air = @import("../../Air.zig"); +const assert = std.debug.assert; +const mir_log = std.log.scoped(.mir); +const Instruction = @import("encoding.zig").Instruction; +const InternPool = @import("../../InternPool.zig"); +const link = @import("../../link.zig"); +const Mir = @This(); +const std = @import("std"); +const target_util = @import("../../target.zig"); +const Zcu = @import("../../Zcu.zig"); +const ZigType = @import("../../Type.zig"); diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig new file mode 100644 index 0000000000..10cf4f40c2 --- /dev/null +++ b/src/codegen/aarch64/Select.zig @@ -0,0 +1,10981 @@ +pt: Zcu.PerThread, +target: *const std.Target, +air: Air, +nav_index: InternPool.Nav.Index, + +// Blocks +def_order: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, void), +blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, Block), +loops: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, Loop), +active_loops: std.ArrayListUnmanaged(Loop.Index), +loop_live: struct { + set: std.AutoArrayHashMapUnmanaged(struct { Loop.Index, Air.Inst.Index }, void), + list: std.ArrayListUnmanaged(Air.Inst.Index), +}, +dom_start: u32, +dom_len: u32, +dom: std.ArrayListUnmanaged(DomInt), + +// Wip Mir +saved_registers: std.enums.EnumSet(Register.Alias), +instructions: std.ArrayListUnmanaged(codegen.aarch64.encoding.Instruction), +literals: std.ArrayListUnmanaged(u32), +nav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Nav), +uav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Uav), +global_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Global), +literal_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Literal), + +// Stack Frame +returns: bool, +va_list: struct { + __stack: Value.Indirect, + __gr_top: Value.Indirect, + __vr_top: Value.Indirect, +}, +stack_size: u24, +stack_align: InternPool.Alignment, + +// Value Tracking +live_registers: LiveRegisters, +live_values: std.AutoHashMapUnmanaged(Air.Inst.Index, Value.Index), +values: std.ArrayListUnmanaged(Value), + +pub const LiveRegisters = std.enums.EnumArray(Register.Alias, Value.Index); + +pub const Block = struct { + live_registers: LiveRegisters, + target_label: u32, + + pub const main: Air.Inst.Index = @enumFromInt( + std.math.maxInt(@typeInfo(Air.Inst.Index).@"enum".tag_type), + ); + + fn branch(block: *const Block, isel: *Select) !void { + if (isel.instructions.items.len > block.target_label) { + try isel.emit(.b(@intCast((isel.instructions.items.len + 1 - block.target_label) << 2))); + } + try isel.merge(&block.live_registers, .{}); + } +}; + +pub const Loop = struct { + def_order: u32, + dom: u32, + depth: u32, + live: u32, + live_registers: LiveRegisters, + repeat_list: u32, + + pub const invalid: Air.Inst.Index = @enumFromInt( + std.math.maxInt(@typeInfo(Air.Inst.Index).@"enum".tag_type), + ); + + pub const Index = enum(u32) { + _, + + fn inst(li: Loop.Index, isel: *Select) Air.Inst.Index { + return isel.loops.keys()[@intFromEnum(li)]; + } + + fn get(li: Loop.Index, isel: *Select) *Loop { + return &isel.loops.values()[@intFromEnum(li)]; + } + }; + + pub const empty_list: u32 = std.math.maxInt(u32); + + fn branch(loop: *Loop, isel: *Select) !void { + try isel.instructions.ensureUnusedCapacity(isel.pt.zcu.gpa, 1); + const repeat_list_tail = loop.repeat_list; + loop.repeat_list = @intCast(isel.instructions.items.len); + isel.instructions.appendAssumeCapacity(@bitCast(repeat_list_tail)); + try isel.merge(&loop.live_registers, .{}); + } +}; + +pub fn deinit(isel: *Select) void { + const gpa = isel.pt.zcu.gpa; + + isel.def_order.deinit(gpa); + isel.blocks.deinit(gpa); + isel.loops.deinit(gpa); + isel.active_loops.deinit(gpa); + isel.loop_live.set.deinit(gpa); + isel.loop_live.list.deinit(gpa); + isel.dom.deinit(gpa); + + isel.instructions.deinit(gpa); + isel.literals.deinit(gpa); + isel.nav_relocs.deinit(gpa); + isel.uav_relocs.deinit(gpa); + isel.global_relocs.deinit(gpa); + isel.literal_relocs.deinit(gpa); + + isel.live_values.deinit(gpa); + isel.values.deinit(gpa); + + isel.* = undefined; +} + +pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { + const zcu = isel.pt.zcu; + const ip = &zcu.intern_pool; + const gpa = zcu.gpa; + const air_tags = isel.air.instructions.items(.tag); + const air_data = isel.air.instructions.items(.data); + var air_body_index: usize = 0; + var air_inst_index = air_body[air_body_index]; + const initial_def_order_len = isel.def_order.count(); + air_tag: switch (air_tags[@intFromEnum(air_inst_index)]) { + .arg, + .ret_addr, + .frame_addr, + .err_return_trace, + .save_err_return_trace_index, + .runtime_nav_ptr, + .c_va_start, + => { + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .add, + .add_safe, + .add_optimized, + .add_wrap, + .add_sat, + .sub, + .sub_safe, + .sub_optimized, + .sub_wrap, + .sub_sat, + .mul, + .mul_safe, + .mul_optimized, + .mul_wrap, + .mul_sat, + .div_float, + .div_float_optimized, + .div_trunc, + .div_trunc_optimized, + .div_floor, + .div_floor_optimized, + .div_exact, + .div_exact_optimized, + .rem, + .rem_optimized, + .mod, + .mod_optimized, + .max, + .min, + .bit_and, + .bit_or, + .shr, + .shr_exact, + .shl, + .shl_exact, + .shl_sat, + .xor, + .cmp_lt, + .cmp_lt_optimized, + .cmp_lte, + .cmp_lte_optimized, + .cmp_eq, + .cmp_eq_optimized, + .cmp_gte, + .cmp_gte_optimized, + .cmp_gt, + .cmp_gt_optimized, + .cmp_neq, + .cmp_neq_optimized, + .bool_and, + .bool_or, + .array_elem_val, + .slice_elem_val, + .ptr_elem_val, + => { + const bin_op = air_data[@intFromEnum(air_inst_index)].bin_op; + + try isel.analyzeUse(bin_op.lhs); + try isel.analyzeUse(bin_op.rhs); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .ptr_add, + .ptr_sub, + .add_with_overflow, + .sub_with_overflow, + .mul_with_overflow, + .shl_with_overflow, + .slice, + .slice_elem_ptr, + .ptr_elem_ptr, + => { + const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; + const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; + + try isel.analyzeUse(bin_op.lhs); + try isel.analyzeUse(bin_op.rhs); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .alloc => { + const ty = air_data[@intFromEnum(air_inst_index)].ty; + + isel.stack_align = isel.stack_align.maxStrict(ty.ptrAlignment(zcu)); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .inferred_alloc, + .inferred_alloc_comptime, + .wasm_memory_size, + .wasm_memory_grow, + .work_item_id, + .work_group_size, + .work_group_id, + => unreachable, + .ret_ptr => { + const ty = air_data[@intFromEnum(air_inst_index)].ty; + + if (isel.live_values.get(Block.main)) |ret_vi| switch (ret_vi.parent(isel)) { + .unallocated, .stack_slot => isel.stack_align = isel.stack_align.maxStrict(ty.ptrAlignment(zcu)), + .value, .constant => unreachable, + .address => |address_vi| try isel.live_values.putNoClobber(gpa, air_inst_index, address_vi.ref(isel)), + }; + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .assembly => { + const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; + const extra = isel.air.extraData(Air.Asm, ty_pl.payload); + const operands: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0 .. extra.data.flags.outputs_len + extra.data.inputs_len]); + + for (operands) |operand| if (operand != .none) try isel.analyzeUse(operand); + if (ty_pl.ty != .void_type) try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .not, + .clz, + .ctz, + .popcount, + .byte_swap, + .bit_reverse, + .abs, + .load, + .fptrunc, + .fpext, + .intcast, + .intcast_safe, + .trunc, + .optional_payload, + .optional_payload_ptr, + .optional_payload_ptr_set, + .wrap_optional, + .unwrap_errunion_payload, + .unwrap_errunion_err, + .unwrap_errunion_payload_ptr, + .unwrap_errunion_err_ptr, + .errunion_payload_ptr_set, + .wrap_errunion_payload, + .wrap_errunion_err, + .struct_field_ptr_index_0, + .struct_field_ptr_index_1, + .struct_field_ptr_index_2, + .struct_field_ptr_index_3, + .get_union_tag, + .ptr_slice_len_ptr, + .ptr_slice_ptr_ptr, + .array_to_slice, + .int_from_float, + .int_from_float_optimized, + .int_from_float_safe, + .int_from_float_optimized_safe, + .float_from_int, + .splat, + .error_set_has_value, + .addrspace_cast, + .c_va_arg, + .c_va_copy, + => { + const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op; + + try isel.analyzeUse(ty_op.operand); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .bitcast => { + const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op; + maybe_noop: { + if (ty_op.ty.toInterned().? != isel.air.typeOf(ty_op.operand, ip).toIntern()) break :maybe_noop; + if (true) break :maybe_noop; + if (ty_op.operand.toIndex()) |src_air_inst_index| { + if (isel.hints.get(src_air_inst_index)) |hint_vpsi| { + try isel.hints.putNoClobber(gpa, air_inst_index, hint_vpsi); + } + } + } + try isel.analyzeUse(ty_op.operand); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + inline .block, .dbg_inline_block => |air_tag| { + const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; + const extra = isel.air.extraData(switch (air_tag) { + else => comptime unreachable, + .block => Air.Block, + .dbg_inline_block => Air.DbgInlineBlock, + }, ty_pl.payload); + const result_ty = ty_pl.ty.toInterned().?; + + if (result_ty == .noreturn_type) { + try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); + + air_body_index += 1; + break :air_tag; + } + + assert(!(try isel.blocks.getOrPut(gpa, air_inst_index)).found_existing); + try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); + const block_entry = isel.blocks.pop().?; + assert(block_entry.key == air_inst_index); + + if (result_ty != .void_type) try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .loop => { + const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; + const extra = isel.air.extraData(Air.Block, ty_pl.payload); + + const initial_dom_start = isel.dom_start; + const initial_dom_len = isel.dom_len; + isel.dom_start = @intCast(isel.dom.items.len); + isel.dom_len = @intCast(isel.blocks.count()); + try isel.active_loops.append(gpa, @enumFromInt(isel.loops.count())); + try isel.loops.putNoClobber(gpa, air_inst_index, .{ + .def_order = @intCast(isel.def_order.count()), + .dom = isel.dom_start, + .depth = isel.dom_len, + .live = 0, + .live_registers = undefined, + .repeat_list = undefined, + }); + try isel.dom.appendNTimes(gpa, 0, std.math.divCeil(usize, isel.dom_len, @bitSizeOf(DomInt)) catch unreachable); + try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); + for ( + isel.dom.items[initial_dom_start..].ptr, + isel.dom.items[isel.dom_start..][0 .. std.math.divCeil(usize, initial_dom_len, @bitSizeOf(DomInt)) catch unreachable], + ) |*initial_dom, loop_dom| initial_dom.* |= loop_dom; + isel.dom_start = initial_dom_start; + isel.dom_len = initial_dom_len; + assert(isel.active_loops.pop().?.inst(isel) == air_inst_index); + + air_body_index += 1; + }, + .repeat, .trap, .unreach => air_body_index += 1, + .br => { + const br = air_data[@intFromEnum(air_inst_index)].br; + const block_index = isel.blocks.getIndex(br.block_inst).?; + if (block_index < isel.dom_len) isel.dom.items[isel.dom_start + block_index / @bitSizeOf(DomInt)] |= @as(DomInt, 1) << @truncate(block_index); + try isel.analyzeUse(br.operand); + + air_body_index += 1; + }, + .breakpoint, + .dbg_stmt, + .dbg_empty_stmt, + .dbg_var_ptr, + .dbg_var_val, + .dbg_arg_inline, + => { + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .call, + .call_always_tail, + .call_never_tail, + .call_never_inline, + => { + const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op; + const extra = isel.air.extraData(Air.Call, pl_op.payload); + const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]); + isel.saved_registers.insert(.lr); + + try isel.analyzeUse(pl_op.operand); + var param_it: CallAbiIterator = .init; + for (args) |arg| { + const restore_values_len = isel.values.items.len; + defer isel.values.shrinkRetainingCapacity(restore_values_len); + const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue; + const param_parent = param_vi.parent(isel); + switch (switch (param_parent) { + .unallocated, .stack_slot => param_parent, + .value, .constant => unreachable, + .address => |address_vi| address_vi.parent(isel), + }) { + .unallocated => {}, + .stack_slot => |stack_slot| { + assert(stack_slot.base == .sp); + isel.stack_size = @max(isel.stack_size, stack_slot.offset); + }, + .value, .constant, .address => unreachable, + } + + try isel.analyzeUse(arg); + } + + var ret_it: CallAbiIterator = .init; + if (try ret_it.ret(isel, isel.air.typeOfIndex(air_inst_index, ip))) |ret_vi| { + tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(ret_vi), @intFromEnum(air_inst_index) }); + switch (ret_vi.parent(isel)) { + .unallocated, .stack_slot => {}, + .value, .constant => unreachable, + .address => |address_vi| { + defer address_vi.deref(isel); + const ret_value = ret_vi.get(isel); + ret_value.flags.parent_tag = .unallocated; + ret_value.parent_payload = .{ .unallocated = {} }; + }, + } + try isel.live_values.putNoClobber(gpa, air_inst_index, ret_vi); + + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + } + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .sqrt, + .sin, + .cos, + .tan, + .exp, + .exp2, + .log, + .log2, + .log10, + .floor, + .ceil, + .round, + .trunc_float, + .neg, + .neg_optimized, + .is_null, + .is_non_null, + .is_null_ptr, + .is_non_null_ptr, + .is_err, + .is_non_err, + .is_err_ptr, + .is_non_err_ptr, + .is_named_enum_value, + .tag_name, + .error_name, + .cmp_lt_errors_len, + => { + const un_op = air_data[@intFromEnum(air_inst_index)].un_op; + + try isel.analyzeUse(un_op); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .cmp_vector, .cmp_vector_optimized => { + const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; + const extra = isel.air.extraData(Air.VectorCmp, ty_pl.payload).data; + + try isel.analyzeUse(extra.lhs); + try isel.analyzeUse(extra.rhs); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .cond_br => { + const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op; + const extra = isel.air.extraData(Air.CondBr, pl_op.payload); + + try isel.analyzeUse(pl_op.operand); + + try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.then_body_len])); + try isel.analyze(@ptrCast(isel.air.extra.items[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len])); + + air_body_index += 1; + }, + .switch_br => { + const switch_br = isel.air.unwrapSwitch(air_inst_index); + + try isel.analyzeUse(switch_br.operand); + + var cases_it = switch_br.iterateCases(); + while (cases_it.next()) |case| try isel.analyze(case.body); + if (switch_br.else_body_len > 0) try isel.analyze(cases_it.elseBody()); + + air_body_index += 1; + }, + .loop_switch_br => { + const switch_br = isel.air.unwrapSwitch(air_inst_index); + + const initial_dom_start = isel.dom_start; + const initial_dom_len = isel.dom_len; + isel.dom_start = @intCast(isel.dom.items.len); + isel.dom_len = @intCast(isel.blocks.count()); + try isel.active_loops.append(gpa, @enumFromInt(isel.loops.count())); + try isel.loops.putNoClobber(gpa, air_inst_index, .{ + .def_order = @intCast(isel.def_order.count()), + .dom = isel.dom_start, + .depth = isel.dom_len, + .live = 0, + .live_registers = undefined, + .repeat_list = undefined, + }); + try isel.dom.appendNTimes(gpa, 0, std.math.divCeil(usize, isel.dom_len, @bitSizeOf(DomInt)) catch unreachable); + + var cases_it = switch_br.iterateCases(); + while (cases_it.next()) |case| try isel.analyze(case.body); + if (switch_br.else_body_len > 0) try isel.analyze(cases_it.elseBody()); + + for ( + isel.dom.items[initial_dom_start..].ptr, + isel.dom.items[isel.dom_start..][0 .. std.math.divCeil(usize, initial_dom_len, @bitSizeOf(DomInt)) catch unreachable], + ) |*initial_dom, loop_dom| initial_dom.* |= loop_dom; + isel.dom_start = initial_dom_start; + isel.dom_len = initial_dom_len; + assert(isel.active_loops.pop().?.inst(isel) == air_inst_index); + + air_body_index += 1; + }, + .switch_dispatch => { + const br = air_data[@intFromEnum(air_inst_index)].br; + + try isel.analyzeUse(br.operand); + + air_body_index += 1; + }, + .@"try", .try_cold, .try_ptr, .try_ptr_cold => { + const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op; + const extra = isel.air.extraData(Air.Try, pl_op.payload); + + try isel.analyzeUse(pl_op.operand); + try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .ret, .ret_safe, .ret_load => { + const un_op = air_data[@intFromEnum(air_inst_index)].un_op; + isel.returns = true; + + const block_index = 0; + assert(isel.blocks.keys()[block_index] == Block.main); + if (isel.dom_len > 0) isel.dom.items[isel.dom_start] |= 1 << block_index; + + try isel.analyzeUse(un_op); + + air_body_index += 1; + }, + .store, + .store_safe, + .set_union_tag, + .memset, + .memset_safe, + .memcpy, + .memmove, + .atomic_store_unordered, + .atomic_store_monotonic, + .atomic_store_release, + .atomic_store_seq_cst, + => { + const bin_op = air_data[@intFromEnum(air_inst_index)].bin_op; + + try isel.analyzeUse(bin_op.lhs); + try isel.analyzeUse(bin_op.rhs); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .struct_field_ptr, .struct_field_val => { + const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; + const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data; + + try isel.analyzeUse(extra.struct_operand); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .slice_len => { + const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op; + + try isel.analyzeUse(ty_op.operand); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + const slice_vi = try isel.use(ty_op.operand); + var len_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 8, 8); + if (try len_part_it.only(isel)) |len_part_vi| + try isel.live_values.putNoClobber(gpa, air_inst_index, len_part_vi.ref(isel)); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .slice_ptr => { + const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op; + + try isel.analyzeUse(ty_op.operand); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + const slice_vi = try isel.use(ty_op.operand); + var ptr_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 0, 8); + if (try ptr_part_it.only(isel)) |ptr_part_vi| + try isel.live_values.putNoClobber(gpa, air_inst_index, ptr_part_vi.ref(isel)); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .reduce, .reduce_optimized => { + const reduce = air_data[@intFromEnum(air_inst_index)].reduce; + + try isel.analyzeUse(reduce.operand); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .shuffle_one => { + const extra = isel.air.unwrapShuffleOne(zcu, air_inst_index); + + try isel.analyzeUse(extra.operand); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .shuffle_two => { + const extra = isel.air.unwrapShuffleTwo(zcu, air_inst_index); + + try isel.analyzeUse(extra.operand_a); + try isel.analyzeUse(extra.operand_b); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .select, .mul_add => { + const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op; + const bin_op = isel.air.extraData(Air.Bin, pl_op.payload).data; + + try isel.analyzeUse(pl_op.operand); + try isel.analyzeUse(bin_op.lhs); + try isel.analyzeUse(bin_op.rhs); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .cmpxchg_weak, .cmpxchg_strong => { + const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; + const extra = isel.air.extraData(Air.Cmpxchg, ty_pl.payload).data; + + try isel.analyzeUse(extra.ptr); + try isel.analyzeUse(extra.expected_value); + try isel.analyzeUse(extra.new_value); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .atomic_load => { + const atomic_load = air_data[@intFromEnum(air_inst_index)].atomic_load; + + try isel.analyzeUse(atomic_load.ptr); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .atomic_rmw => { + const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op; + const extra = isel.air.extraData(Air.AtomicRmw, pl_op.payload).data; + + try isel.analyzeUse(extra.operand); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .aggregate_init => { + const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; + const elements: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[ty_pl.payload..][0..@intCast(ty_pl.ty.toType().arrayLen(zcu))]); + + for (elements) |element| try isel.analyzeUse(element); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .union_init => { + const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; + const extra = isel.air.extraData(Air.UnionInit, ty_pl.payload).data; + + try isel.analyzeUse(extra.init); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .prefetch => { + const prefetch = air_data[@intFromEnum(air_inst_index)].prefetch; + + try isel.analyzeUse(prefetch.ptr); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .field_parent_ptr => { + const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; + const extra = isel.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; + + try isel.analyzeUse(extra.field_ptr); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .set_err_return_trace, .c_va_end => { + const un_op = air_data[@intFromEnum(air_inst_index)].un_op; + + try isel.analyzeUse(un_op); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + .vector_store_elem => { + const vector_store_elem = air_data[@intFromEnum(air_inst_index)].vector_store_elem; + const bin_op = isel.air.extraData(Air.Bin, vector_store_elem.payload).data; + + try isel.analyzeUse(vector_store_elem.vector_ptr); + try isel.analyzeUse(bin_op.lhs); + try isel.analyzeUse(bin_op.rhs); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, + } + assert(air_body_index == air_body.len); + isel.def_order.shrinkRetainingCapacity(initial_def_order_len); +} + +fn analyzeUse(isel: *Select, air_ref: Air.Inst.Ref) !void { + const air_inst_index = air_ref.toIndex() orelse return; + const def_order_index = isel.def_order.getIndex(air_inst_index).?; + + // Loop liveness + var active_loop_index = isel.active_loops.items.len; + while (active_loop_index > 0) { + const prev_active_loop_index = active_loop_index - 1; + const active_loop = isel.active_loops.items[prev_active_loop_index]; + if (def_order_index >= active_loop.get(isel).def_order) break; + active_loop_index = prev_active_loop_index; + } + if (active_loop_index < isel.active_loops.items.len) { + const active_loop = isel.active_loops.items[active_loop_index]; + const loop_live_gop = + try isel.loop_live.set.getOrPut(isel.pt.zcu.gpa, .{ active_loop, air_inst_index }); + if (!loop_live_gop.found_existing) active_loop.get(isel).live += 1; + } +} + +pub fn finishAnalysis(isel: *Select) !void { + const gpa = isel.pt.zcu.gpa; + + // Loop Liveness + if (isel.loops.count() > 0) { + try isel.loops.ensureUnusedCapacity(gpa, 1); + + const loop_live_len: u32 = @intCast(isel.loop_live.set.count()); + if (loop_live_len > 0) { + try isel.loop_live.list.resize(gpa, loop_live_len); + + const loops = isel.loops.values(); + for (loops[1..], loops[0 .. loops.len - 1]) |*loop, prev_loop| loop.live += prev_loop.live; + assert(loops[loops.len - 1].live == loop_live_len); + + for (isel.loop_live.set.keys()) |entry| { + const loop, const inst = entry; + const loop_live = &loop.get(isel).live; + loop_live.* -= 1; + isel.loop_live.list.items[loop_live.*] = inst; + } + assert(loops[0].live == 0); + } + + const invalid_gop = isel.loops.getOrPutAssumeCapacity(Loop.invalid); + assert(!invalid_gop.found_existing); + invalid_gop.value_ptr.live = loop_live_len; + } +} + +pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { + const zcu = isel.pt.zcu; + const ip = &zcu.intern_pool; + const gpa = zcu.gpa; + + { + var live_reg_it = isel.live_registers.iterator(); + while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) { + _ => { + const ra = &live_reg_entry.value.get(isel).location_payload.small.register; + assert(ra.* == live_reg_entry.key); + ra.* = .zr; + live_reg_entry.value.* = .free; + }, + .allocating => live_reg_entry.value.* = .free, + .free => {}, + }; + } + + var air: struct { + isel: *Select, + tag_items: []const Air.Inst.Tag, + data_items: []const Air.Inst.Data, + body: []const Air.Inst.Index, + body_index: u32, + inst_index: Air.Inst.Index, + + fn tag(it: *@This(), inst_index: Air.Inst.Index) Air.Inst.Tag { + return it.tag_items[@intFromEnum(inst_index)]; + } + + fn data(it: *@This(), inst_index: Air.Inst.Index) Air.Inst.Data { + return it.data_items[@intFromEnum(inst_index)]; + } + + fn next(it: *@This()) ?Air.Inst.Tag { + if (it.body_index == 0) { + @branchHint(.unlikely); + return null; + } + it.body_index -= 1; + it.inst_index = it.body[it.body_index]; + wip_mir_log.debug("{f}", .{it.fmtAir(it.inst_index)}); + return it.tag(it.inst_index); + } + + fn fmtAir(it: @This(), inst: Air.Inst.Index) struct { + isel: *Select, + inst: Air.Inst.Index, + pub fn format(fmt_air: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { + fmt_air.isel.air.writeInst(writer, fmt_air.inst, fmt_air.isel.pt, null); + } + } { + return .{ .isel = it.isel, .inst = inst }; + } + } = .{ + .isel = isel, + .tag_items = isel.air.instructions.items(.tag), + .data_items = isel.air.instructions.items(.data), + .body = air_body, + .body_index = @intCast(air_body.len), + .inst_index = undefined, + }; + air_tag: switch (air.next().?) { + else => |air_tag| return isel.fail("unimplemented {s}", .{@tagName(air_tag)}), + .arg => { + const arg_vi = isel.live_values.fetchRemove(air.inst_index).?.value; + defer arg_vi.deref(isel); + switch (arg_vi.parent(isel)) { + .unallocated, .stack_slot => if (arg_vi.hint(isel)) |arg_ra| { + try arg_vi.defLiveIn(isel, arg_ra, comptime &.initFill(.free)); + } else { + var arg_part_it = arg_vi.parts(isel); + while (arg_part_it.next()) |arg_part| { + try arg_part.defLiveIn(isel, arg_part.hint(isel).?, comptime &.initFill(.free)); + } + }, + .value, .constant => unreachable, + .address => |address_vi| try address_vi.defLiveIn(isel, address_vi.hint(isel).?, comptime &.initFill(.free)), + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .add, .add_optimized, .add_wrap, .sub, .sub_optimized, .sub_wrap => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const ty = isel.air.typeOf(bin_op.lhs, ip); + if (!ty.isRuntimeFloat()) try res_vi.value.addOrSubtract(isel, ty, try isel.use(bin_op.lhs), switch (air_tag) { + else => unreachable, + .add, .add_wrap => .add, + .sub, .sub_wrap => .sub, + }, try isel.use(bin_op.rhs), .{ .wrap = switch (air_tag) { + else => unreachable, + .add, .sub => false, + .add_wrap, .sub_wrap => true, + } }) else switch (ty.floatBits(isel.target)) { + else => unreachable, + 16, 32, 64 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const need_fcvt = switch (bits) { + else => unreachable, + 16 => !isel.target.cpu.has(.aarch64, .fullfp16), + 32, 64 => false, + }; + if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; + defer if (need_fcvt) isel.freeReg(lhs_ra); + const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; + defer if (need_fcvt) isel.freeReg(rhs_ra); + try isel.emit(bits: switch (bits) { + else => unreachable, + 16 => if (need_fcvt) continue :bits 32 else switch (air_tag) { + else => unreachable, + .add, .add_optimized => .fadd(res_ra.h(), lhs_ra.h(), rhs_ra.h()), + .sub, .sub_optimized => .fsub(res_ra.h(), lhs_ra.h(), rhs_ra.h()), + }, + 32 => switch (air_tag) { + else => unreachable, + .add, .add_optimized => .fadd(res_ra.s(), lhs_ra.s(), rhs_ra.s()), + .sub, .sub_optimized => .fsub(res_ra.s(), lhs_ra.s(), rhs_ra.s()), + }, + 64 => switch (air_tag) { + else => unreachable, + .add, .add_optimized => .fadd(res_ra.d(), lhs_ra.d(), rhs_ra.d()), + .sub, .sub_optimized => .fsub(res_ra.d(), lhs_ra.d(), rhs_ra.d()), + }, + }); + if (need_fcvt) { + try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); + try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); + } + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 80, 128 => |bits| { + try call.prepareReturn(isel); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), + 80 => { + var res_hi16_it = res_vi.value.field(ty, 8, 8); + const res_hi16_vi = try res_hi16_it.only(isel); + try call.returnLiveIn(isel, res_hi16_vi.?, .r1); + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + try call.returnLiveIn(isel, res_lo64_vi.?, .r0); + }, + } + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = switch (air_tag) { + else => unreachable, + .add, .add_optimized => switch (bits) { + else => unreachable, + 16 => "__addhf3", + 32 => "__addsf3", + 64 => "__adddf3", + 80 => "__addxf3", + 128 => "__addtf3", + }, + .sub, .sub_optimized => switch (bits) { + else => unreachable, + 16 => "__subhf3", + 32 => "__subsf3", + 64 => "__subdf3", + 80 => "__subxf3", + 128 => "__subtf3", + }, + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => { + try call.paramLiveOut(isel, rhs_vi, .v1); + try call.paramLiveOut(isel, lhs_vi, .v0); + }, + 80 => { + var rhs_hi16_it = rhs_vi.field(ty, 8, 8); + const rhs_hi16_vi = try rhs_hi16_it.only(isel); + try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); + var rhs_lo64_it = rhs_vi.field(ty, 0, 8); + const rhs_lo64_vi = try rhs_lo64_it.only(isel); + try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); + var lhs_hi16_it = lhs_vi.field(ty, 8, 8); + const lhs_hi16_vi = try lhs_hi16_it.only(isel); + try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); + var lhs_lo64_it = lhs_vi.field(ty, 0, 8); + const lhs_lo64_vi = try lhs_lo64_it.only(isel); + try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .add_sat, .sub_sat => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const ty = isel.air.typeOf(bin_op.lhs, ip); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + switch (int_info.bits) { + 0 => unreachable, + 32, 64 => |bits| switch (int_info.signedness) { + .signed => return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + .unsigned => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const unsat_res_ra = try isel.allocIntReg(); + defer isel.freeReg(unsat_res_ra); + switch (air_tag) { + else => unreachable, + .add_sat => switch (bits) { + else => unreachable, + 32 => { + try isel.emit(.csinv(res_ra.w(), unsat_res_ra.w(), .wzr, .invert(.cs))); + try isel.emit(.adds(unsat_res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); + }, + 64 => { + try isel.emit(.csinv(res_ra.x(), unsat_res_ra.x(), .xzr, .invert(.cs))); + try isel.emit(.adds(unsat_res_ra.x(), lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() })); + }, + }, + .sub_sat => switch (bits) { + else => unreachable, + 32 => { + try isel.emit(.csel(res_ra.w(), unsat_res_ra.w(), .wzr, .invert(.cc))); + try isel.emit(.subs(unsat_res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); + }, + 64 => { + try isel.emit(.csel(res_ra.x(), unsat_res_ra.x(), .xzr, .invert(.cc))); + try isel.emit(.subs(unsat_res_ra.x(), lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() })); + }, + }, + } + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + }, + else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .mul, .mul_optimized, .mul_wrap => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const ty = isel.air.typeOf(bin_op.lhs, ip); + if (!ty.isRuntimeFloat()) { + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + switch (int_info.bits) { + 0 => unreachable, + 1 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + switch (int_info.signedness) { + .signed => switch (air_tag) { + else => unreachable, + .mul => break :unused try isel.emit(.orr(res_ra.w(), .wzr, .{ .register = .wzr })), + .mul_wrap => {}, + }, + .unsigned => {}, + } + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + try isel.emit(.@"and"(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 2...32 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + switch (air_tag) { + else => unreachable, + .mul => {}, + .mul_wrap => switch (bits) { + else => unreachable, + 1...31 => try isel.emit(switch (int_info.signedness) { + .signed => .sbfm(res_ra.w(), res_ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(bits - 1), + }), + .unsigned => .ubfm(res_ra.w(), res_ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(bits - 1), + }), + }), + 32 => {}, + }, + } + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + try isel.emit(.madd(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), .wzr)); + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 33...64 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + switch (air_tag) { + else => unreachable, + .mul => {}, + .mul_wrap => switch (bits) { + else => unreachable, + 33...63 => try isel.emit(switch (int_info.signedness) { + .signed => .sbfm(res_ra.x(), res_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + }), + .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + }), + }), + 64 => {}, + }, + } + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + try isel.emit(.madd(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr)); + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 65...128 => |bits| { + var res_hi64_it = res_vi.value.field(ty, 8, 8); + const res_hi64_vi = try res_hi64_it.only(isel); + const res_hi64_ra = try res_hi64_vi.?.defReg(isel); + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + const res_lo64_ra = try res_lo64_vi.?.defReg(isel); + if (res_hi64_ra == null and res_lo64_ra == null) break :unused; + if (res_hi64_ra) |res_ra| switch (air_tag) { + else => unreachable, + .mul => {}, + .mul_wrap => switch (bits) { + else => unreachable, + 65...127 => try isel.emit(switch (int_info.signedness) { + .signed => .sbfm(res_ra.x(), res_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + }), + .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + }), + }), + 128 => {}, + }, + }; + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_lo64_mat, const rhs_lo64_mat = lo64_mat: { + const res_hi64_lock: RegLock = if (res_hi64_ra != null and res_lo64_ra != null) + isel.lockReg(res_hi64_ra.?) + else + .empty; + defer res_hi64_lock.unlock(isel); + + var rhs_lo64_it = rhs_vi.field(ty, 0, 8); + const rhs_lo64_vi = try rhs_lo64_it.only(isel); + const rhs_lo64_mat = try rhs_lo64_vi.?.matReg(isel); + var lhs_lo64_it = lhs_vi.field(ty, 0, 8); + const lhs_lo64_vi = try lhs_lo64_it.only(isel); + const lhs_lo64_mat = try lhs_lo64_vi.?.matReg(isel); + break :lo64_mat .{ lhs_lo64_mat, rhs_lo64_mat }; + }; + if (res_lo64_ra) |res_ra| try isel.emit(.madd(res_ra.x(), lhs_lo64_mat.ra.x(), rhs_lo64_mat.ra.x(), .xzr)); + if (res_hi64_ra) |res_ra| { + var rhs_hi64_it = rhs_vi.field(ty, 8, 8); + const rhs_hi64_vi = try rhs_hi64_it.only(isel); + const rhs_hi64_mat = try rhs_hi64_vi.?.matReg(isel); + var lhs_hi64_it = lhs_vi.field(ty, 8, 8); + const lhs_hi64_vi = try lhs_hi64_it.only(isel); + const lhs_hi64_mat = try lhs_hi64_vi.?.matReg(isel); + const acc_ra = try isel.allocIntReg(); + defer isel.freeReg(acc_ra); + try isel.emit(.madd(res_ra.x(), lhs_hi64_mat.ra.x(), rhs_lo64_mat.ra.x(), acc_ra.x())); + try isel.emit(.madd(acc_ra.x(), lhs_lo64_mat.ra.x(), rhs_hi64_mat.ra.x(), acc_ra.x())); + try isel.emit(.umulh(acc_ra.x(), lhs_lo64_mat.ra.x(), rhs_lo64_mat.ra.x())); + try rhs_hi64_mat.finish(isel); + try lhs_hi64_mat.finish(isel); + } + try rhs_lo64_mat.finish(isel); + try lhs_lo64_mat.finish(isel); + }, + else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + } + } else switch (ty.floatBits(isel.target)) { + else => unreachable, + 16, 32, 64 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const need_fcvt = switch (bits) { + else => unreachable, + 16 => !isel.target.cpu.has(.aarch64, .fullfp16), + 32, 64 => false, + }; + if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; + defer if (need_fcvt) isel.freeReg(lhs_ra); + const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; + defer if (need_fcvt) isel.freeReg(rhs_ra); + try isel.emit(bits: switch (bits) { + else => unreachable, + 16 => if (need_fcvt) + continue :bits 32 + else + .fmul(res_ra.h(), lhs_ra.h(), rhs_ra.h()), + 32 => .fmul(res_ra.s(), lhs_ra.s(), rhs_ra.s()), + 64 => .fmul(res_ra.d(), lhs_ra.d(), rhs_ra.d()), + }); + if (need_fcvt) { + try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); + try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); + } + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 80, 128 => |bits| { + try call.prepareReturn(isel); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), + 80 => { + var res_hi16_it = res_vi.value.field(ty, 8, 8); + const res_hi16_vi = try res_hi16_it.only(isel); + try call.returnLiveIn(isel, res_hi16_vi.?, .r1); + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + try call.returnLiveIn(isel, res_lo64_vi.?, .r0); + }, + } + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = switch (bits) { + else => unreachable, + 16 => "__mulhf3", + 32 => "__mulsf3", + 64 => "__muldf3", + 80 => "__mulxf3", + 128 => "__multf3", + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => { + try call.paramLiveOut(isel, rhs_vi, .v1); + try call.paramLiveOut(isel, lhs_vi, .v0); + }, + 80 => { + var rhs_hi16_it = rhs_vi.field(ty, 8, 8); + const rhs_hi16_vi = try rhs_hi16_it.only(isel); + try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); + var rhs_lo64_it = rhs_vi.field(ty, 0, 8); + const rhs_lo64_vi = try rhs_lo64_it.only(isel); + try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); + var lhs_hi16_it = lhs_vi.field(ty, 8, 8); + const lhs_hi16_vi = try lhs_hi16_it.only(isel); + try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); + var lhs_lo64_it = lhs_vi.field(ty, 0, 8); + const lhs_lo64_vi = try lhs_lo64_it.only(isel); + try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .mul_sat => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const ty = isel.air.typeOf(bin_op.lhs, ip); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + switch (int_info.bits) { + 0 => unreachable, + 1 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + switch (int_info.signedness) { + .signed => try isel.emit(.orr(res_ra.w(), .wzr, .{ .register = .wzr })), + .unsigned => { + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + try isel.emit(.@"and"(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + } + }, + 2...32 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const saturated_ra = switch (int_info.signedness) { + .signed => try isel.allocIntReg(), + .unsigned => switch (bits) { + else => unreachable, + 2...31 => try isel.allocIntReg(), + 32 => .zr, + }, + }; + defer if (saturated_ra != .zr) isel.freeReg(saturated_ra); + const unwrapped_ra = try isel.allocIntReg(); + defer isel.freeReg(unwrapped_ra); + try isel.emit(switch (saturated_ra) { + else => .csel(res_ra.w(), unwrapped_ra.w(), saturated_ra.w(), .eq), + .zr => .csinv(res_ra.w(), unwrapped_ra.w(), saturated_ra.w(), .eq), + }); + switch (bits) { + else => unreachable, + 2...7, 9...15, 17...31 => switch (int_info.signedness) { + .signed => { + const wrapped_ra = try isel.allocIntReg(); + defer isel.freeReg(wrapped_ra); + switch (bits) { + else => unreachable, + 1...7, 9...15 => { + try isel.emit(.subs(.wzr, unwrapped_ra.w(), .{ .register = wrapped_ra.w() })); + try isel.emit(.sbfm(wrapped_ra.w(), unwrapped_ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(bits - 1), + })); + }, + 17...31 => { + try isel.emit(.subs(.xzr, unwrapped_ra.x(), .{ .register = wrapped_ra.x() })); + try isel.emit(.sbfm(wrapped_ra.x(), unwrapped_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + })); + }, + } + }, + .unsigned => switch (bits) { + else => unreachable, + 1...7, 9...15 => try isel.emit(.ands(.wzr, unwrapped_ra.w(), .{ .immediate = .{ + .N = .word, + .immr = @intCast(32 - bits), + .imms = @intCast(32 - bits - 1), + } })), + 17...31 => try isel.emit(.ands(.xzr, unwrapped_ra.x(), .{ .immediate = .{ + .N = .doubleword, + .immr = @intCast(64 - bits), + .imms = @intCast(64 - bits - 1), + } })), + }, + }, + 8 => try isel.emit(.subs(.wzr, unwrapped_ra.w(), .{ .extended_register = .{ + .register = unwrapped_ra.w(), + .extend = switch (int_info.signedness) { + .signed => .{ .sxtb = 0 }, + .unsigned => .{ .uxtb = 0 }, + }, + } })), + 16 => try isel.emit(.subs(.wzr, unwrapped_ra.w(), .{ .extended_register = .{ + .register = unwrapped_ra.w(), + .extend = switch (int_info.signedness) { + .signed => .{ .sxth = 0 }, + .unsigned => .{ .uxth = 0 }, + }, + } })), + 32 => try isel.emit(.subs(.xzr, unwrapped_ra.x(), .{ .extended_register = .{ + .register = unwrapped_ra.w(), + .extend = switch (int_info.signedness) { + .signed => .{ .sxtw = 0 }, + .unsigned => .{ .uxtw = 0 }, + }, + } })), + } + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + switch (int_info.signedness) { + .signed => { + try isel.emit(.eor(saturated_ra.w(), saturated_ra.w(), .{ .immediate = .{ + .N = .word, + .immr = 0, + .imms = @intCast(bits - 1 - 1), + } })); + try isel.emit(.sbfm(saturated_ra.w(), saturated_ra.w(), .{ + .N = .word, + .immr = @intCast(bits - 1), + .imms = @intCast(bits - 1 + 1 - 1), + })); + try isel.emit(.eor(saturated_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); + }, + .unsigned => switch (bits) { + else => unreachable, + 2...31 => try isel.movImmediate(saturated_ra.w(), @as(u32, std.math.maxInt(u32)) >> @intCast(32 - bits)), + 32 => {}, + }, + } + switch (bits) { + else => unreachable, + 2...16 => try isel.emit(.madd(unwrapped_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), .wzr)), + 17...32 => switch (int_info.signedness) { + .signed => try isel.emit(.smaddl(unwrapped_ra.x(), lhs_mat.ra.w(), rhs_mat.ra.w(), .xzr)), + .unsigned => try isel.emit(.umaddl(unwrapped_ra.x(), lhs_mat.ra.w(), rhs_mat.ra.w(), .xzr)), + }, + } + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 33...64 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const saturated_ra = switch (int_info.signedness) { + .signed => try isel.allocIntReg(), + .unsigned => switch (bits) { + else => unreachable, + 33...63 => try isel.allocIntReg(), + 64 => .zr, + }, + }; + defer if (saturated_ra != .zr) isel.freeReg(saturated_ra); + const unwrapped_lo64_ra = try isel.allocIntReg(); + defer isel.freeReg(unwrapped_lo64_ra); + const unwrapped_hi64_ra = try isel.allocIntReg(); + defer isel.freeReg(unwrapped_hi64_ra); + try isel.emit(switch (saturated_ra) { + else => .csel(res_ra.x(), unwrapped_lo64_ra.x(), saturated_ra.x(), .eq), + .zr => .csinv(res_ra.x(), unwrapped_lo64_ra.x(), saturated_ra.x(), .eq), + }); + switch (int_info.signedness) { + .signed => switch (bits) { + else => unreachable, + 32...63 => { + const wrapped_lo64_ra = try isel.allocIntReg(); + defer isel.freeReg(wrapped_lo64_ra); + try isel.emit(.ccmp( + unwrapped_lo64_ra.x(), + .{ .register = wrapped_lo64_ra.x() }, + .{ .n = false, .z = false, .c = false, .v = false }, + .eq, + )); + try isel.emit(.subs(.xzr, unwrapped_hi64_ra.x(), .{ .shifted_register = .{ + .register = unwrapped_lo64_ra.x(), + .shift = .{ .asr = 63 }, + } })); + try isel.emit(.sbfm(wrapped_lo64_ra.x(), unwrapped_lo64_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + })); + }, + 64 => try isel.emit(.subs(.xzr, unwrapped_hi64_ra.x(), .{ .shifted_register = .{ + .register = unwrapped_lo64_ra.x(), + .shift = .{ .asr = @intCast(bits - 1) }, + } })), + }, + .unsigned => switch (bits) { + else => unreachable, + 32...63 => { + const overflow_ra = try isel.allocIntReg(); + defer isel.freeReg(overflow_ra); + try isel.emit(.subs(.xzr, overflow_ra.x(), .{ .immediate = 0 })); + try isel.emit(.orr(overflow_ra.x(), unwrapped_hi64_ra.x(), .{ .shifted_register = .{ + .register = unwrapped_lo64_ra.x(), + .shift = .{ .lsr = @intCast(bits) }, + } })); + }, + 64 => try isel.emit(.subs(.xzr, unwrapped_hi64_ra.x(), .{ .immediate = 0 })), + }, + } + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + switch (int_info.signedness) { + .signed => { + try isel.emit(.eor(saturated_ra.x(), saturated_ra.x(), .{ .immediate = .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1 - 1), + } })); + try isel.emit(.sbfm(saturated_ra.x(), saturated_ra.x(), .{ + .N = .doubleword, + .immr = @intCast(bits - 1), + .imms = @intCast(bits - 1 + 1 - 1), + })); + try isel.emit(.eor(saturated_ra.x(), lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() })); + try isel.emit(.madd(unwrapped_lo64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr)); + try isel.emit(.smulh(unwrapped_hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x())); + }, + .unsigned => { + switch (bits) { + else => unreachable, + 32...63 => try isel.movImmediate(saturated_ra.x(), @as(u64, std.math.maxInt(u64)) >> @intCast(64 - bits)), + 64 => {}, + } + try isel.emit(.madd(unwrapped_lo64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr)); + try isel.emit(.umulh(unwrapped_hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x())); + }, + } + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .div_float, .div_float_optimized => { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const ty = isel.air.typeOf(bin_op.lhs, ip); + switch (ty.floatBits(isel.target)) { + else => unreachable, + 16, 32, 64 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const need_fcvt = switch (bits) { + else => unreachable, + 16 => !isel.target.cpu.has(.aarch64, .fullfp16), + 32, 64 => false, + }; + if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; + defer if (need_fcvt) isel.freeReg(lhs_ra); + const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; + defer if (need_fcvt) isel.freeReg(rhs_ra); + try isel.emit(bits: switch (bits) { + else => unreachable, + 16 => if (need_fcvt) + continue :bits 32 + else + .fdiv(res_ra.h(), lhs_ra.h(), rhs_ra.h()), + 32 => .fdiv(res_ra.s(), lhs_ra.s(), rhs_ra.s()), + 64 => .fdiv(res_ra.d(), lhs_ra.d(), rhs_ra.d()), + }); + if (need_fcvt) { + try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); + try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); + } + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 80, 128 => |bits| { + try call.prepareReturn(isel); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), + 80 => { + var res_hi16_it = res_vi.value.field(ty, 8, 8); + const res_hi16_vi = try res_hi16_it.only(isel); + try call.returnLiveIn(isel, res_hi16_vi.?, .r1); + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + try call.returnLiveIn(isel, res_lo64_vi.?, .r0); + }, + } + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = switch (bits) { + else => unreachable, + 16 => "__divhf3", + 32 => "__divsf3", + 64 => "__divdf3", + 80 => "__divxf3", + 128 => "__divtf3", + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => { + try call.paramLiveOut(isel, rhs_vi, .v1); + try call.paramLiveOut(isel, lhs_vi, .v0); + }, + 80 => { + var rhs_hi16_it = rhs_vi.field(ty, 8, 8); + const rhs_hi16_vi = try rhs_hi16_it.only(isel); + try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); + var rhs_lo64_it = rhs_vi.field(ty, 0, 8); + const rhs_lo64_vi = try rhs_lo64_it.only(isel); + try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); + var lhs_hi16_it = lhs_vi.field(ty, 8, 8); + const lhs_hi16_vi = try lhs_hi16_it.only(isel); + try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); + var lhs_lo64_it = lhs_vi.field(ty, 0, 8); + const lhs_lo64_vi = try lhs_lo64_it.only(isel); + try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .div_trunc, .div_trunc_optimized, .div_floor, .div_floor_optimized, .div_exact, .div_exact_optimized => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const ty = isel.air.typeOf(bin_op.lhs, ip); + if (!ty.isRuntimeFloat()) { + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + switch (int_info.bits) { + 0 => unreachable, + 1...64 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const div_ra = div_ra: switch (air_tag) { + else => unreachable, + .div_trunc, .div_exact => res_ra, + .div_floor => switch (int_info.signedness) { + .signed => { + const div_ra = try isel.allocIntReg(); + errdefer isel.freeReg(div_ra); + const rem_ra = try isel.allocIntReg(); + defer isel.freeReg(rem_ra); + switch (bits) { + else => unreachable, + 1...32 => { + try isel.emit(.sub(res_ra.w(), div_ra.w(), .{ .register = rem_ra.w() })); + try isel.emit(.csinc(rem_ra.w(), .wzr, .wzr, .ge)); + try isel.emit(.ccmp( + rem_ra.w(), + .{ .immediate = 0 }, + .{ .n = false, .z = false, .c = false, .v = false }, + .ne, + )); + try isel.emit(.eor(rem_ra.w(), rem_ra.w(), .{ .register = rhs_mat.ra.w() })); + try isel.emit(.subs(.wzr, rem_ra.w(), .{ .immediate = 0 })); + try isel.emit(.msub(rem_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w())); + }, + 33...64 => { + try isel.emit(.sub(res_ra.x(), div_ra.x(), .{ .register = rem_ra.x() })); + try isel.emit(.csinc(rem_ra.x(), .xzr, .xzr, .ge)); + try isel.emit(.ccmp( + rem_ra.x(), + .{ .immediate = 0 }, + .{ .n = false, .z = false, .c = false, .v = false }, + .ne, + )); + try isel.emit(.eor(rem_ra.x(), rem_ra.x(), .{ .register = rhs_mat.ra.x() })); + try isel.emit(.subs(.xzr, rem_ra.x(), .{ .immediate = 0 })); + try isel.emit(.msub(rem_ra.x(), div_ra.x(), rhs_mat.ra.x(), lhs_mat.ra.x())); + }, + } + break :div_ra div_ra; + }, + .unsigned => res_ra, + }, + }; + defer if (div_ra != res_ra) isel.freeReg(div_ra); + try isel.emit(switch (bits) { + else => unreachable, + 1...32 => switch (int_info.signedness) { + .signed => .sdiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), + .unsigned => .udiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), + }, + 33...64 => switch (int_info.signedness) { + .signed => .sdiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), + .unsigned => .udiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), + }, + }); + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 65...128 => { + switch (air_tag) { + else => unreachable, + .div_trunc, .div_exact => {}, + .div_floor => switch (int_info.signedness) { + .signed => return isel.fail("unimplemented {s}", .{@tagName(air_tag)}), + .unsigned => {}, + }, + } + + try call.prepareReturn(isel); + var res_hi64_it = res_vi.value.field(ty, 8, 8); + const res_hi64_vi = try res_hi64_it.only(isel); + try call.returnLiveIn(isel, res_hi64_vi.?, .r1); + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + try call.returnLiveIn(isel, res_lo64_vi.?, .r0); + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = switch (int_info.signedness) { + .signed => "__divti3", + .unsigned => "__udivti3", + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + var rhs_hi64_it = rhs_vi.field(ty, 8, 8); + const rhs_hi64_vi = try rhs_hi64_it.only(isel); + try call.paramLiveOut(isel, rhs_hi64_vi.?, .r3); + var rhs_lo64_it = rhs_vi.field(ty, 0, 8); + const rhs_lo64_vi = try rhs_lo64_it.only(isel); + try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); + var lhs_hi64_it = lhs_vi.field(ty, 8, 8); + const lhs_hi64_vi = try lhs_hi64_it.only(isel); + try call.paramLiveOut(isel, lhs_hi64_vi.?, .r1); + var lhs_lo64_it = lhs_vi.field(ty, 0, 8); + const lhs_lo64_vi = try lhs_lo64_it.only(isel); + try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); + try call.finishParams(isel); + }, + else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + } + } else switch (ty.floatBits(isel.target)) { + else => unreachable, + 16, 32, 64 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const need_fcvt = switch (bits) { + else => unreachable, + 16 => !isel.target.cpu.has(.aarch64, .fullfp16), + 32, 64 => false, + }; + if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; + defer if (need_fcvt) isel.freeReg(lhs_ra); + const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; + defer if (need_fcvt) isel.freeReg(rhs_ra); + bits: switch (bits) { + else => unreachable, + 16 => if (need_fcvt) continue :bits 32 else { + switch (air_tag) { + else => unreachable, + .div_trunc, .div_trunc_optimized => try isel.emit(.frintz(res_ra.h(), res_ra.h())), + .div_floor, .div_floor_optimized => try isel.emit(.frintm(res_ra.h(), res_ra.h())), + .div_exact, .div_exact_optimized => {}, + } + try isel.emit(.fdiv(res_ra.h(), lhs_ra.h(), rhs_ra.h())); + }, + 32 => { + switch (air_tag) { + else => unreachable, + .div_trunc, .div_trunc_optimized => try isel.emit(.frintz(res_ra.s(), res_ra.s())), + .div_floor, .div_floor_optimized => try isel.emit(.frintm(res_ra.s(), res_ra.s())), + .div_exact, .div_exact_optimized => {}, + } + try isel.emit(.fdiv(res_ra.s(), lhs_ra.s(), rhs_ra.s())); + }, + 64 => { + switch (air_tag) { + else => unreachable, + .div_trunc, .div_trunc_optimized => try isel.emit(.frintz(res_ra.d(), res_ra.d())), + .div_floor, .div_floor_optimized => try isel.emit(.frintm(res_ra.d(), res_ra.d())), + .div_exact, .div_exact_optimized => {}, + } + try isel.emit(.fdiv(res_ra.d(), lhs_ra.d(), rhs_ra.d())); + }, + } + if (need_fcvt) { + try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); + try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); + } + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 80, 128 => |bits| { + try call.prepareReturn(isel); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), + 80 => { + var res_hi16_it = res_vi.value.field(ty, 8, 8); + const res_hi16_vi = try res_hi16_it.only(isel); + try call.returnLiveIn(isel, res_hi16_vi.?, .r1); + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + try call.returnLiveIn(isel, res_lo64_vi.?, .r0); + }, + } + try call.finishReturn(isel); + + try call.prepareCallee(isel); + switch (air_tag) { + else => unreachable, + .div_trunc, .div_trunc_optimized => { + try isel.global_relocs.append(gpa, .{ + .global = switch (bits) { + else => unreachable, + 16 => "__trunch", + 32 => "truncf", + 64 => "trunc", + 80 => "__truncx", + 128 => "truncq", + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + }, + .div_floor, .div_floor_optimized => { + try isel.global_relocs.append(gpa, .{ + .global = switch (bits) { + else => unreachable, + 16 => "__floorh", + 32 => "floorf", + 64 => "floor", + 80 => "__floorx", + 128 => "floorq", + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + }, + .div_exact, .div_exact_optimized => {}, + } + try isel.global_relocs.append(gpa, .{ + .global = switch (bits) { + else => unreachable, + 16 => "__divhf3", + 32 => "__divsf3", + 64 => "__divdf3", + 80 => "__divxf3", + 128 => "__divtf3", + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => { + try call.paramLiveOut(isel, rhs_vi, .v1); + try call.paramLiveOut(isel, lhs_vi, .v0); + }, + 80 => { + var rhs_hi16_it = rhs_vi.field(ty, 8, 8); + const rhs_hi16_vi = try rhs_hi16_it.only(isel); + try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); + var rhs_lo64_it = rhs_vi.field(ty, 0, 8); + const rhs_lo64_vi = try rhs_lo64_it.only(isel); + try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); + var lhs_hi16_it = lhs_vi.field(ty, 8, 8); + const lhs_hi16_vi = try lhs_hi16_it.only(isel); + try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); + var lhs_lo64_it = lhs_vi.field(ty, 0, 8); + const lhs_lo64_vi = try lhs_lo64_it.only(isel); + try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .rem => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const ty = isel.air.typeOf(bin_op.lhs, ip); + if (!ty.isRuntimeFloat()) { + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const div_ra = try isel.allocIntReg(); + defer isel.freeReg(div_ra); + switch (int_info.bits) { + else => unreachable, + 1...32 => { + try isel.emit(.msub(res_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w())); + try isel.emit(switch (int_info.signedness) { + .signed => .sdiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), + .unsigned => .udiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), + }); + }, + 33...64 => { + try isel.emit(.msub(res_ra.x(), div_ra.x(), rhs_mat.ra.x(), lhs_mat.ra.x())); + try isel.emit(switch (int_info.signedness) { + .signed => .sdiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), + .unsigned => .udiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), + }); + }, + } + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + } else { + const bits = ty.floatBits(isel.target); + + try call.prepareReturn(isel); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), + 80 => { + var res_hi16_it = res_vi.value.field(ty, 8, 8); + const res_hi16_vi = try res_hi16_it.only(isel); + try call.returnLiveIn(isel, res_hi16_vi.?, .r1); + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + try call.returnLiveIn(isel, res_lo64_vi.?, .r0); + }, + } + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = switch (bits) { + else => unreachable, + 16 => "__fmodh", + 32 => "fmodf", + 64 => "fmod", + 80 => "__fmodx", + 128 => "fmodq", + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => { + try call.paramLiveOut(isel, rhs_vi, .v1); + try call.paramLiveOut(isel, lhs_vi, .v0); + }, + 80 => { + var rhs_hi16_it = rhs_vi.field(ty, 8, 8); + const rhs_hi16_vi = try rhs_hi16_it.only(isel); + try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); + var rhs_lo64_it = rhs_vi.field(ty, 0, 8); + const rhs_lo64_vi = try rhs_lo64_it.only(isel); + try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); + var lhs_hi16_it = lhs_vi.field(ty, 8, 8); + const lhs_hi16_vi = try lhs_hi16_it.only(isel); + try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); + var lhs_lo64_it = lhs_vi.field(ty, 0, 8); + const lhs_lo64_vi = try lhs_lo64_it.only(isel); + try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .ptr_add, .ptr_sub => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + + const ty_pl = air.data(air.inst_index).ty_pl; + const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; + const elem_size = ty_pl.ty.toType().elemType2(zcu).abiSize(zcu); + + const base_vi = try isel.use(bin_op.lhs); + var base_part_it = base_vi.field(ty_pl.ty.toType(), 0, 8); + const base_part_vi = try base_part_it.only(isel); + const base_part_mat = try base_part_vi.?.matReg(isel); + const index_vi = try isel.use(bin_op.rhs); + try isel.elemPtr(res_ra, base_part_mat.ra, switch (air_tag) { + else => unreachable, + .ptr_add => .add, + .ptr_sub => .sub, + }, elem_size, index_vi); + try base_part_mat.finish(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .max, .min => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const ty = isel.air.typeOf(bin_op.lhs, ip); + if (!ty.isRuntimeFloat()) { + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const cond: codegen.aarch64.encoding.ConditionCode = switch (air_tag) { + else => unreachable, + .max => switch (int_info.signedness) { + .signed => .ge, + .unsigned => .hs, + }, + .min => switch (int_info.signedness) { + .signed => .lt, + .unsigned => .lo, + }, + }; + switch (int_info.bits) { + else => unreachable, + 1...32 => { + try isel.emit(.csel(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), cond)); + try isel.emit(.subs(.wzr, lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); + }, + 33...64 => { + try isel.emit(.csel(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), cond)); + try isel.emit(.subs(.xzr, lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() })); + }, + } + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + } else switch (ty.floatBits(isel.target)) { + else => unreachable, + 16, 32, 64 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const need_fcvt = switch (bits) { + else => unreachable, + 16 => !isel.target.cpu.has(.aarch64, .fullfp16), + 32, 64 => false, + }; + if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; + defer if (need_fcvt) isel.freeReg(lhs_ra); + const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; + defer if (need_fcvt) isel.freeReg(rhs_ra); + try isel.emit(bits: switch (bits) { + else => unreachable, + 16 => if (need_fcvt) continue :bits 32 else switch (air_tag) { + else => unreachable, + .max => .fmaxnm(res_ra.h(), lhs_ra.h(), rhs_ra.h()), + .min => .fminnm(res_ra.h(), lhs_ra.h(), rhs_ra.h()), + }, + 32 => switch (air_tag) { + else => unreachable, + .max => .fmaxnm(res_ra.s(), lhs_ra.s(), rhs_ra.s()), + .min => .fminnm(res_ra.s(), lhs_ra.s(), rhs_ra.s()), + }, + 64 => switch (air_tag) { + else => unreachable, + .max => .fmaxnm(res_ra.d(), lhs_ra.d(), rhs_ra.d()), + .min => .fminnm(res_ra.d(), lhs_ra.d(), rhs_ra.d()), + }, + }); + if (need_fcvt) { + try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); + try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); + } + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 80, 128 => |bits| { + try call.prepareReturn(isel); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), + 80 => { + var res_hi16_it = res_vi.value.field(ty, 8, 8); + const res_hi16_vi = try res_hi16_it.only(isel); + try call.returnLiveIn(isel, res_hi16_vi.?, .r1); + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + try call.returnLiveIn(isel, res_lo64_vi.?, .r0); + }, + } + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = switch (air_tag) { + else => unreachable, + .max => switch (bits) { + else => unreachable, + 16 => "__fmaxh", + 32 => "fmaxf", + 64 => "fmax", + 80 => "__fmaxx", + 128 => "fmaxq", + }, + .min => switch (bits) { + else => unreachable, + 16 => "__fminh", + 32 => "fminf", + 64 => "fmin", + 80 => "__fminx", + 128 => "fminq", + }, + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => { + try call.paramLiveOut(isel, rhs_vi, .v1); + try call.paramLiveOut(isel, lhs_vi, .v0); + }, + 80 => { + var rhs_hi16_it = rhs_vi.field(ty, 8, 8); + const rhs_hi16_vi = try rhs_hi16_it.only(isel); + try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); + var rhs_lo64_it = rhs_vi.field(ty, 0, 8); + const rhs_lo64_vi = try rhs_lo64_it.only(isel); + try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); + var lhs_hi16_it = lhs_vi.field(ty, 8, 8); + const lhs_hi16_vi = try lhs_hi16_it.only(isel); + try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); + var lhs_lo64_it = lhs_vi.field(ty, 0, 8); + const lhs_lo64_vi = try lhs_lo64_it.only(isel); + try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .add_with_overflow, .sub_with_overflow => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| { + defer res_vi.value.deref(isel); + + const ty_pl = air.data(air.inst_index).ty_pl; + const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; + const ty = isel.air.typeOf(bin_op.lhs, ip); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const ty_size = lhs_vi.size(isel); + var overflow_it = res_vi.value.field(ty_pl.ty.toType(), ty_size, 1); + const overflow_vi = try overflow_it.only(isel); + var wrapped_it = res_vi.value.field(ty_pl.ty.toType(), 0, ty_size); + const wrapped_vi = try wrapped_it.only(isel); + try wrapped_vi.?.addOrSubtract(isel, ty, lhs_vi, switch (air_tag) { + else => unreachable, + .add_with_overflow => .add, + .sub_with_overflow => .sub, + }, rhs_vi, .{ .wrap = true, .overflow_ra = try overflow_vi.?.defReg(isel) orelse .zr }); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .alloc, .ret_ptr => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: { + defer ptr_vi.value.deref(isel); + switch (air_tag) { + else => unreachable, + .alloc => {}, + .ret_ptr => if (isel.live_values.get(Block.main)) |ret_vi| switch (ret_vi.parent(isel)) { + .unallocated, .stack_slot => {}, + .value, .constant => unreachable, + .address => break :unused, + }, + } + const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused; + + const ty = air.data(air.inst_index).ty; + const slot_size = ty.childType(zcu).abiSize(zcu); + const slot_align = ty.ptrAlignment(zcu); + const slot_offset = slot_align.forward(isel.stack_size); + isel.stack_size = @intCast(slot_offset + slot_size); + const lo12: u12 = @truncate(slot_offset >> 0); + const hi12: u12 = @intCast(slot_offset >> 12); + if (hi12 > 0) try isel.emit(.add( + ptr_ra.x(), + if (lo12 > 0) ptr_ra.x() else .sp, + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + )); + if (lo12 > 0 or hi12 == 0) try isel.emit(.add(ptr_ra.x(), .sp, .{ .immediate = lo12 })); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .assembly => { + const ty_pl = air.data(air.inst_index).ty_pl; + const extra = isel.air.extraData(Air.Asm, ty_pl.payload); + var extra_index = extra.end; + const outputs: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra_index..][0..extra.data.flags.outputs_len]); + extra_index += outputs.len; + const inputs: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra_index..][0..extra.data.inputs_len]); + extra_index += inputs.len; + + var as: codegen.aarch64.Assemble = .{ + .source = undefined, + .operands = .empty, + }; + defer as.operands.deinit(gpa); + + for (outputs) |output| { + const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]); + const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]), 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); + // This equation accounts for the fact that even if we have exactly 4 bytes + // for the string, we still use the next u32 for the null terminator. + extra_index += (constraint.len + name.len + (2 + 3)) / 4; + + switch (output) { + else => return isel.fail("invalid constraint: '{s}'", .{constraint}), + .none => if (std.mem.startsWith(u8, constraint, "={") and std.mem.endsWith(u8, constraint, "}")) { + const output_reg = Register.parse(constraint["={".len .. constraint.len - "}".len]) orelse + return isel.fail("invalid constraint: '{s}'", .{constraint}); + const output_ra = output_reg.alias; + if (isel.live_values.fetchRemove(air.inst_index)) |output_vi| { + defer output_vi.value.deref(isel); + try output_vi.value.defLiveIn(isel, output_reg.alias, comptime &.initFill(.free)); + isel.freeReg(output_ra); + } + if (!std.mem.eql(u8, name, "_")) { + const operand_gop = try as.operands.getOrPut(gpa, name); + if (operand_gop.found_existing) return isel.fail("duplicate output name: '{s}'", .{name}); + operand_gop.value_ptr.* = .{ .register = switch (ty_pl.ty.toType().abiSize(zcu)) { + 0 => unreachable, + 1...4 => output_ra.w(), + 5...8 => output_ra.x(), + else => return isel.fail("too big output type: '{f}'", .{isel.fmtType(ty_pl.ty.toType())}), + } }; + } + } else if (std.mem.eql(u8, constraint, "=r")) { + const output_ra = if (isel.live_values.fetchRemove(air.inst_index)) |output_vi| output_ra: { + defer output_vi.value.deref(isel); + break :output_ra try output_vi.value.defReg(isel) orelse try isel.allocIntReg(); + } else try isel.allocIntReg(); + if (!std.mem.eql(u8, name, "_")) { + const operand_gop = try as.operands.getOrPut(gpa, name); + if (operand_gop.found_existing) return isel.fail("duplicate output name: '{s}'", .{name}); + operand_gop.value_ptr.* = .{ .register = switch (ty_pl.ty.toType().abiSize(zcu)) { + 0 => unreachable, + 1...4 => output_ra.w(), + 5...8 => output_ra.x(), + else => return isel.fail("too big output type: '{f}'", .{isel.fmtType(ty_pl.ty.toType())}), + } }; + } + } else return isel.fail("invalid constraint: '{s}'", .{constraint}), + } + } + + const input_mats = try gpa.alloc(Value.Materialize, inputs.len); + defer gpa.free(input_mats); + const inputs_extra_index = extra_index; + for (inputs, input_mats) |input, *input_mat| { + const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]); + const constraint = std.mem.sliceTo(extra_bytes, 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); + // This equation accounts for the fact that even if we have exactly 4 bytes + // for the string, we still use the next u32 for the null terminator. + extra_index += (constraint.len + name.len + (2 + 3)) / 4; + + if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) { + const input_reg = Register.parse(constraint["{".len .. constraint.len - "}".len]) orelse + return isel.fail("invalid constraint: '{s}'", .{constraint}); + input_mat.* = .{ .vi = try isel.use(input), .ra = input_reg.alias }; + if (!std.mem.eql(u8, name, "_")) { + const operand_gop = try as.operands.getOrPut(gpa, name); + if (operand_gop.found_existing) return isel.fail("duplicate input name: '{s}'", .{name}); + const input_ty = isel.air.typeOf(input, ip); + operand_gop.value_ptr.* = .{ .register = switch (input_ty.abiSize(zcu)) { + 0 => unreachable, + 1...4 => input_reg.alias.w(), + 5...8 => input_reg.alias.x(), + else => return isel.fail("too big input type: '{f}'", .{ + isel.fmtType(isel.air.typeOf(input, ip)), + }), + } }; + } + } else if (std.mem.eql(u8, constraint, "r")) { + const input_vi = try isel.use(input); + input_mat.* = try input_vi.matReg(isel); + if (!std.mem.eql(u8, name, "_")) { + const operand_gop = try as.operands.getOrPut(gpa, name); + if (operand_gop.found_existing) return isel.fail("duplicate input name: '{s}'", .{name}); + operand_gop.value_ptr.* = .{ .register = switch (input_vi.size(isel)) { + 0 => unreachable, + 1...4 => input_mat.ra.w(), + 5...8 => input_mat.ra.x(), + else => return isel.fail("too big input type: '{f}'", .{ + isel.fmtType(isel.air.typeOf(input, ip)), + }), + } }; + } + } else if (std.mem.eql(u8, name, "_")) { + input_mat.vi = try isel.use(input); + } else return isel.fail("invalid constraint: '{s}'", .{constraint}); + } + + const clobbers = ip.indexToKey(extra.data.clobbers).aggregate; + const clobbers_ty: ZigType = .fromInterned(clobbers.ty); + for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { + switch (switch (clobbers.storage) { + .bytes => unreachable, + .elems => |elems| elems[field_index], + .repeated_elem => |repeated_elem| repeated_elem, + }) { + else => unreachable, + .bool_false => continue, + .bool_true => {}, + } + const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; + if (std.mem.eql(u8, clobber_name, "memory")) continue; + if (std.mem.eql(u8, clobber_name, "nzcv")) continue; + const clobber_reg = Register.parse(clobber_name) orelse + return isel.fail("unable to parse clobber: '{s}'", .{clobber_name}); + const live_vi = isel.live_registers.getPtr(clobber_reg.alias); + switch (live_vi.*) { + _ => {}, + .allocating => return isel.fail("clobbered twice: '{s}'", .{clobber_name}), + .free => live_vi.* = .allocating, + } + } + for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { + switch (switch (clobbers.storage) { + .bytes => unreachable, + .elems => |elems| elems[field_index], + .repeated_elem => |repeated_elem| repeated_elem, + }) { + else => unreachable, + .bool_false => continue, + .bool_true => {}, + } + const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; + if (std.mem.eql(u8, clobber_name, "memory")) continue; + if (std.mem.eql(u8, clobber_name, "nzcv")) continue; + const clobber_ra = Register.parse(clobber_name).?.alias; + const live_vi = isel.live_registers.getPtr(clobber_ra); + switch (live_vi.*) { + _ => { + if (!try isel.fill(clobber_ra)) + return isel.fail("unable to clobber: '{s}'", .{clobber_name}); + assert(live_vi.* == .free); + live_vi.* = .allocating; + }, + .allocating => {}, + .free => unreachable, + } + } + + as.source = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..])[0..extra.data.source_len :0]; + const asm_start = isel.instructions.items.len; + while (as.nextInstruction() catch |err| switch (err) { + error.InvalidSyntax => { + const remaining_source = std.mem.span(as.source); + return isel.fail("unable to assemble: '{s}'", .{std.mem.trim( + u8, + as.source[0 .. std.mem.indexOfScalar(u8, remaining_source, '\n') orelse remaining_source.len], + &std.ascii.whitespace, + )}); + }, + }) |instruction| try isel.emit(instruction); + std.mem.reverse(codegen.aarch64.encoding.Instruction, isel.instructions.items[asm_start..]); + + extra_index = inputs_extra_index; + for (input_mats) |input_mat| { + const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]); + const constraint = std.mem.sliceTo(extra_bytes, 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); + // This equation accounts for the fact that even if we have exactly 4 bytes + // for the string, we still use the next u32 for the null terminator. + extra_index += (constraint.len + name.len + (2 + 3)) / 4; + + if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) { + try input_mat.vi.liveOut(isel, input_mat.ra); + } else if (std.mem.eql(u8, constraint, "r")) { + try input_mat.finish(isel); + } else if (std.mem.eql(u8, name, "_")) { + try input_mat.vi.mat(isel); + } else unreachable; + } + + for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { + switch (switch (clobbers.storage) { + .bytes => unreachable, + .elems => |elems| elems[field_index], + .repeated_elem => |repeated_elem| repeated_elem, + }) { + else => unreachable, + .bool_false => continue, + .bool_true => {}, + } + const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; + if (std.mem.eql(u8, clobber_name, "memory")) continue; + if (std.mem.eql(u8, clobber_name, "cc")) continue; + isel.freeReg(Register.parse(clobber_name).?.alias); + } + + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .bit_and, .bit_or, .xor, .bool_and, .bool_or => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| { + defer res_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const ty = isel.air.typeOf(bin_op.lhs, ip); + const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type) + .{ .signedness = .unsigned, .bits = 1 } + else if (ty.isAbiInt(zcu)) + ty.intInfo(zcu) + else + return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + var offset = res_vi.value.size(isel); + while (offset > 0) { + const size = @min(offset, 8); + offset -= size; + var res_part_it = res_vi.value.field(ty, offset, size); + const res_part_vi = try res_part_it.only(isel); + const res_part_ra = try res_part_vi.?.defReg(isel) orelse continue; + var lhs_part_it = lhs_vi.field(ty, offset, size); + const lhs_part_vi = try lhs_part_it.only(isel); + const lhs_part_mat = try lhs_part_vi.?.matReg(isel); + var rhs_part_it = rhs_vi.field(ty, offset, size); + const rhs_part_vi = try rhs_part_it.only(isel); + const rhs_part_mat = try rhs_part_vi.?.matReg(isel); + try isel.emit(switch (air_tag) { + else => unreachable, + .bit_and, .bool_and => switch (size) { + else => unreachable, + 1, 2, 4 => .@"and"(res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), + 8 => .@"and"(res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), + }, + .bit_or, .bool_or => switch (size) { + else => unreachable, + 1, 2, 4 => .orr(res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), + 8 => .orr(res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), + }, + .xor => switch (size) { + else => unreachable, + 1, 2, 4 => .eor(res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), + 8 => .eor(res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), + }, + }); + try rhs_part_mat.finish(isel); + try lhs_part_mat.finish(isel); + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .shr, .shr_exact, .shl, .shl_exact => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const ty = isel.air.typeOf(bin_op.lhs, ip); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + switch (int_info.bits) { + 0 => unreachable, + 1...64 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + switch (air_tag) { + else => unreachable, + .shr, .shr_exact, .shl_exact => {}, + .shl => switch (bits) { + else => unreachable, + 1...31 => try isel.emit(switch (int_info.signedness) { + .signed => .sbfm(res_ra.w(), res_ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(bits - 1), + }), + .unsigned => .ubfm(res_ra.w(), res_ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(bits - 1), + }), + }), + 32 => {}, + 33...63 => try isel.emit(switch (int_info.signedness) { + .signed => .sbfm(res_ra.x(), res_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + }), + .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + }), + }), + 64 => {}, + }, + } + + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + try isel.emit(switch (air_tag) { + else => unreachable, + .shr, .shr_exact => switch (bits) { + else => unreachable, + 1...32 => switch (int_info.signedness) { + .signed => .asrv(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), + .unsigned => .lsrv(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), + }, + 33...64 => switch (int_info.signedness) { + .signed => .asrv(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), + .unsigned => .lsrv(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), + }, + }, + .shl, .shl_exact => switch (bits) { + else => unreachable, + 1...32 => .lslv(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), + 33...64 => .lslv(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), + }, + }); + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 65...128 => |bits| { + var res_hi64_it = res_vi.value.field(ty, 8, 8); + const res_hi64_vi = try res_hi64_it.only(isel); + const res_hi64_ra = try res_hi64_vi.?.defReg(isel); + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + const res_lo64_ra = try res_lo64_vi.?.defReg(isel); + if (res_hi64_ra == null and res_lo64_ra == null) break :unused; + if (res_hi64_ra) |res_ra| switch (air_tag) { + else => unreachable, + .shr, .shr_exact, .shl_exact => {}, + .shl => switch (bits) { + else => unreachable, + 65...127 => try isel.emit(switch (int_info.signedness) { + .signed => .sbfm(res_ra.x(), res_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 64 - 1), + }), + .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 64 - 1), + }), + }), + 128 => {}, + }, + }; + + const lhs_vi = try isel.use(bin_op.lhs); + const lhs_hi64_mat = lhs_hi64_mat: { + const res_lock: RegLock = switch (air_tag) { + else => unreachable, + .shr, .shr_exact => switch (int_info.signedness) { + .signed => if (res_lo64_ra) |res_ra| isel.lockReg(res_ra) else .empty, + .unsigned => .empty, + }, + .shl, .shl_exact => .empty, + }; + defer res_lock.unlock(isel); + var lhs_hi64_it = lhs_vi.field(ty, 8, 8); + const lhs_hi64_vi = try lhs_hi64_it.only(isel); + break :lhs_hi64_mat try lhs_hi64_vi.?.matReg(isel); + }; + var lhs_lo64_it = lhs_vi.field(ty, 0, 8); + const lhs_lo64_vi = try lhs_lo64_it.only(isel); + const lhs_lo64_mat = try lhs_lo64_vi.?.matReg(isel); + const rhs_vi = try isel.use(bin_op.rhs); + const rhs_mat = try rhs_vi.matReg(isel); + const lo64_ra = lo64_ra: { + const res_lock: RegLock = switch (air_tag) { + else => unreachable, + .shr, .shr_exact => switch (int_info.signedness) { + .signed => if (res_lo64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty, + .unsigned => .empty, + }, + .shl, .shl_exact => if (res_hi64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty, + }; + defer res_lock.unlock(isel); + break :lo64_ra try isel.allocIntReg(); + }; + defer isel.freeReg(lo64_ra); + const hi64_ra = hi64_ra: { + const res_lock: RegLock = switch (air_tag) { + else => unreachable, + .shr, .shr_exact => if (res_lo64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty, + .shl, .shl_exact => .empty, + }; + defer res_lock.unlock(isel); + break :hi64_ra try isel.allocIntReg(); + }; + defer isel.freeReg(hi64_ra); + switch (air_tag) { + else => unreachable, + .shr, .shr_exact => { + if (res_hi64_ra) |res_ra| switch (int_info.signedness) { + .signed => { + try isel.emit(.csel(res_ra.x(), hi64_ra.x(), lo64_ra.x(), .eq)); + try isel.emit(.sbfm(lo64_ra.x(), lhs_hi64_mat.ra.x(), .{ + .N = .doubleword, + .immr = @intCast(bits - 64 - 1), + .imms = @intCast(bits - 64 - 1), + })); + }, + .unsigned => try isel.emit(.csel(res_ra.x(), hi64_ra.x(), .xzr, .eq)), + }; + if (res_lo64_ra) |res_ra| try isel.emit(.csel(res_ra.x(), lo64_ra.x(), hi64_ra.x(), .eq)); + switch (int_info.signedness) { + .signed => try isel.emit(.asrv(hi64_ra.x(), lhs_hi64_mat.ra.x(), rhs_mat.ra.x())), + .unsigned => try isel.emit(.lsrv(hi64_ra.x(), lhs_hi64_mat.ra.x(), rhs_mat.ra.x())), + } + }, + .shl, .shl_exact => { + if (res_lo64_ra) |res_ra| try isel.emit(.csel(res_ra.x(), lo64_ra.x(), .xzr, .eq)); + if (res_hi64_ra) |res_ra| try isel.emit(.csel(res_ra.x(), hi64_ra.x(), lo64_ra.x(), .eq)); + try isel.emit(.lslv(lo64_ra.x(), lhs_lo64_mat.ra.x(), rhs_mat.ra.x())); + }, + } + try isel.emit(.ands(.wzr, rhs_mat.ra.w(), .{ .immediate = .{ .N = .word, .immr = 32 - 6, .imms = 0 } })); + switch (air_tag) { + else => unreachable, + .shr, .shr_exact => if (res_lo64_ra) |_| { + try isel.emit(.orr( + lo64_ra.x(), + lo64_ra.x(), + .{ .shifted_register = .{ .register = hi64_ra.x(), .shift = .{ .lsl = 1 } } }, + )); + try isel.emit(.lslv(hi64_ra.x(), lhs_hi64_mat.ra.x(), hi64_ra.x())); + try isel.emit(.lsrv(lo64_ra.x(), lhs_lo64_mat.ra.x(), rhs_mat.ra.x())); + try isel.emit(.orn(hi64_ra.w(), .wzr, .{ .register = rhs_mat.ra.w() })); + }, + .shl, .shl_exact => if (res_hi64_ra) |_| { + try isel.emit(.orr( + hi64_ra.x(), + hi64_ra.x(), + .{ .shifted_register = .{ .register = lo64_ra.x(), .shift = .{ .lsr = 1 } } }, + )); + try isel.emit(.lsrv(lo64_ra.x(), lhs_lo64_mat.ra.x(), lo64_ra.x())); + try isel.emit(.lslv(hi64_ra.x(), lhs_hi64_mat.ra.x(), rhs_mat.ra.x())); + try isel.emit(.orn(lo64_ra.w(), .wzr, .{ .register = rhs_mat.ra.w() })); + }, + } + try rhs_mat.finish(isel); + try lhs_lo64_mat.finish(isel); + try lhs_hi64_mat.finish(isel); + break :unused; + }, + else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .not => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| { + defer res_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const ty = ty_op.ty.toType(); + const int_info: std.builtin.Type.Int = int_info: { + if (ty_op.ty == .bool_type) break :int_info .{ .signedness = .unsigned, .bits = 1 }; + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + break :int_info ty.intInfo(zcu); + }; + if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + + const src_vi = try isel.use(ty_op.operand); + var offset = res_vi.value.size(isel); + while (offset > 0) { + const size = @min(offset, 8); + offset -= size; + var res_part_it = res_vi.value.field(ty, offset, size); + const res_part_vi = try res_part_it.only(isel); + const res_part_ra = try res_part_vi.?.defReg(isel) orelse continue; + var src_part_it = src_vi.field(ty, offset, size); + const src_part_vi = try src_part_it.only(isel); + const src_part_mat = try src_part_vi.?.matReg(isel); + try isel.emit(switch (int_info.signedness) { + .signed => switch (size) { + else => unreachable, + 1, 2, 4 => .orn(res_part_ra.w(), .wzr, .{ .register = src_part_mat.ra.w() }), + 8 => .orn(res_part_ra.x(), .xzr, .{ .register = src_part_mat.ra.x() }), + }, + .unsigned => switch (@min(int_info.bits - 8 * offset, 64)) { + else => unreachable, + 1...31 => |bits| .eor(res_part_ra.w(), src_part_mat.ra.w(), .{ .immediate = .{ + .N = .word, + .immr = 0, + .imms = @intCast(bits - 1), + } }), + 32 => .orn(res_part_ra.w(), .wzr, .{ .register = src_part_mat.ra.w() }), + 33...63 => |bits| .eor(res_part_ra.x(), src_part_mat.ra.x(), .{ .immediate = .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + } }), + 64 => .orn(res_part_ra.x(), .xzr, .{ .register = src_part_mat.ra.x() }), + }, + }); + try src_part_mat.finish(isel); + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .bitcast => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { + defer dst_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + const dst_ty = ty_op.ty.toType(); + const dst_tag = dst_ty.zigTypeTag(zcu); + const src_ty = isel.air.typeOf(ty_op.operand, ip); + const src_tag = src_ty.zigTypeTag(zcu); + if (dst_ty.isAbiInt(zcu) and (src_tag == .bool or src_ty.isAbiInt(zcu))) { + const dst_int_info = dst_ty.intInfo(zcu); + const src_int_info: std.builtin.Type.Int = if (src_tag == .bool) .{ .signedness = undefined, .bits = 1 } else src_ty.intInfo(zcu); + assert(dst_int_info.bits == src_int_info.bits); + if (dst_tag != .@"struct" and src_tag != .@"struct" and src_tag != .bool and dst_int_info.signedness == src_int_info.signedness) { + try dst_vi.value.move(isel, ty_op.operand); + } else switch (dst_int_info.bits) { + 0 => unreachable, + 1...31 => |dst_bits| { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(switch (dst_int_info.signedness) { + .signed => .sbfm(dst_ra.w(), src_mat.ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(dst_bits - 1), + }), + .unsigned => .ubfm(dst_ra.w(), src_mat.ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(dst_bits - 1), + }), + }); + try src_mat.finish(isel); + }, + 32 => try dst_vi.value.move(isel, ty_op.operand), + 33...63 => |dst_bits| { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(switch (dst_int_info.signedness) { + .signed => .sbfm(dst_ra.x(), src_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(dst_bits - 1), + }), + .unsigned => .ubfm(dst_ra.x(), src_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(dst_bits - 1), + }), + }); + try src_mat.finish(isel); + }, + 64 => try dst_vi.value.move(isel, ty_op.operand), + 65...127 => |dst_bits| { + const src_vi = try isel.use(ty_op.operand); + var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8); + const dst_hi64_vi = try dst_hi64_it.only(isel); + if (try dst_hi64_vi.?.defReg(isel)) |dst_hi64_ra| { + var src_hi64_it = src_vi.field(src_ty, 8, 8); + const src_hi64_vi = try src_hi64_it.only(isel); + const src_hi64_mat = try src_hi64_vi.?.matReg(isel); + try isel.emit(switch (dst_int_info.signedness) { + .signed => .sbfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(dst_bits - 64 - 1), + }), + .unsigned => .ubfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(dst_bits - 64 - 1), + }), + }); + try src_hi64_mat.finish(isel); + } + var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); + const dst_lo64_vi = try dst_lo64_it.only(isel); + if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| { + var src_lo64_it = src_vi.field(src_ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + try src_lo64_vi.?.liveOut(isel, dst_lo64_ra); + } + }, + 128 => try dst_vi.value.move(isel, ty_op.operand), + else => return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), + } + } else if ((dst_ty.isPtrAtRuntime(zcu) or dst_ty.isAbiInt(zcu)) and (src_ty.isPtrAtRuntime(zcu) or src_ty.isAbiInt(zcu))) { + try dst_vi.value.move(isel, ty_op.operand); + } else if (dst_ty.isSliceAtRuntime(zcu) and src_ty.isSliceAtRuntime(zcu)) { + try dst_vi.value.move(isel, ty_op.operand); + } else if (dst_tag == .error_union and src_tag == .error_union) { + assert(dst_ty.errorUnionSet(zcu).hasRuntimeBitsIgnoreComptime(zcu) == + src_ty.errorUnionSet(zcu).hasRuntimeBitsIgnoreComptime(zcu)); + if (dst_ty.errorUnionPayload(zcu).toIntern() == src_ty.errorUnionPayload(zcu).toIntern()) { + try dst_vi.value.move(isel, ty_op.operand); + } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + } else if (dst_tag == .float and src_tag == .float) { + assert(dst_ty.floatBits(isel.target) == src_ty.floatBits(isel.target)); + try dst_vi.value.move(isel, ty_op.operand); + } else if (dst_ty.isAbiInt(zcu) and src_tag == .float) { + const dst_int_info = dst_ty.intInfo(zcu); + assert(dst_int_info.bits == src_ty.floatBits(isel.target)); + switch (dst_int_info.bits) { + else => unreachable, + 16 => { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + switch (dst_int_info.signedness) { + .signed => try isel.emit(.smov(dst_ra.w(), src_mat.ra.@"h[]"(0))), + .unsigned => try isel.emit(if (isel.target.cpu.has(.aarch64, .fullfp16)) + .fmov(dst_ra.w(), .{ .register = src_mat.ra.h() }) + else + .umov(dst_ra.w(), src_mat.ra.@"h[]"(0))), + } + try src_mat.finish(isel); + }, + 32 => { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(.fmov(dst_ra.w(), .{ .register = src_mat.ra.s() })); + try src_mat.finish(isel); + }, + 64 => { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(.fmov(dst_ra.x(), .{ .register = src_mat.ra.d() })); + try src_mat.finish(isel); + }, + 80 => switch (dst_int_info.signedness) { + .signed => { + const src_vi = try isel.use(ty_op.operand); + var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8); + const dst_hi16_vi = try dst_hi16_it.only(isel); + if (try dst_hi16_vi.?.defReg(isel)) |dst_hi16_ra| { + var src_hi16_it = src_vi.field(src_ty, 8, 8); + const src_hi16_vi = try src_hi16_it.only(isel); + const src_hi16_mat = try src_hi16_vi.?.matReg(isel); + try isel.emit(.sbfm(dst_hi16_ra.x(), src_hi16_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = 16 - 1, + })); + try src_hi16_mat.finish(isel); + } + var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); + const dst_lo64_vi = try dst_lo64_it.only(isel); + if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| { + var src_lo64_it = src_vi.field(src_ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + try src_lo64_vi.?.liveOut(isel, dst_lo64_ra); + } + }, + else => try dst_vi.value.move(isel, ty_op.operand), + }, + 128 => { + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8); + const dst_hi64_vi = try dst_hi64_it.only(isel); + if (try dst_hi64_vi.?.defReg(isel)) |dst_hi64_ra| try isel.emit(.fmov(dst_hi64_ra.x(), .{ .register = src_mat.ra.@"d[]"(1) })); + var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); + const dst_lo64_vi = try dst_lo64_it.only(isel); + if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| try isel.emit(.fmov(dst_lo64_ra.x(), .{ .register = src_mat.ra.d() })); + try src_mat.finish(isel); + }, + } + } else if (dst_tag == .float and src_ty.isAbiInt(zcu)) { + const src_int_info = src_ty.intInfo(zcu); + assert(dst_ty.floatBits(isel.target) == src_int_info.bits); + switch (src_int_info.bits) { + else => unreachable, + 16 => { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(.fmov( + if (isel.target.cpu.has(.aarch64, .fullfp16)) dst_ra.h() else dst_ra.s(), + .{ .register = src_mat.ra.w() }, + )); + try src_mat.finish(isel); + }, + 32 => { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(.fmov(dst_ra.s(), .{ .register = src_mat.ra.w() })); + try src_mat.finish(isel); + }, + 64 => { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(.fmov(dst_ra.d(), .{ .register = src_mat.ra.x() })); + try src_mat.finish(isel); + }, + 80 => switch (src_int_info.signedness) { + .signed => { + const src_vi = try isel.use(ty_op.operand); + var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8); + const dst_hi16_vi = try dst_hi16_it.only(isel); + if (try dst_hi16_vi.?.defReg(isel)) |dst_hi16_ra| { + var src_hi16_it = src_vi.field(src_ty, 8, 8); + const src_hi16_vi = try src_hi16_it.only(isel); + const src_hi16_mat = try src_hi16_vi.?.matReg(isel); + try isel.emit(.ubfm(dst_hi16_ra.x(), src_hi16_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = 16 - 1, + })); + try src_hi16_mat.finish(isel); + } + var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); + const dst_lo64_vi = try dst_lo64_it.only(isel); + if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| { + var src_lo64_it = src_vi.field(src_ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + try src_lo64_vi.?.liveOut(isel, dst_lo64_ra); + } + }, + else => try dst_vi.value.move(isel, ty_op.operand), + }, + 128 => { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + var src_hi64_it = src_vi.field(src_ty, 8, 8); + const src_hi64_vi = try src_hi64_it.only(isel); + const src_hi64_mat = try src_hi64_vi.?.matReg(isel); + try isel.emit(.fmov(dst_ra.@"d[]"(1), .{ .register = src_hi64_mat.ra.x() })); + try src_hi64_mat.finish(isel); + var src_lo64_it = src_vi.field(src_ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + const src_lo64_mat = try src_lo64_vi.?.matReg(isel); + try isel.emit(.fmov(dst_ra.d(), .{ .register = src_lo64_mat.ra.x() })); + try src_lo64_mat.finish(isel); + }, + } + } else if (dst_ty.isAbiInt(zcu) and src_tag == .array and src_ty.childType(zcu).isAbiInt(zcu)) { + const dst_int_info = dst_ty.intInfo(zcu); + const src_child_int_info = src_ty.childType(zcu).intInfo(zcu); + const src_len = src_ty.arrayLenIncludingSentinel(zcu); + assert(dst_int_info.bits == src_child_int_info.bits * src_len); + const src_child_size = src_ty.childType(zcu).abiSize(zcu); + if (8 * src_child_size == src_child_int_info.bits) { + try dst_vi.value.defAddr(isel, dst_ty, dst_int_info, comptime &.initFill(.free)) orelse break :unused; + + try call.prepareReturn(isel); + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = "memcpy", + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const src_vi = try isel.use(ty_op.operand); + try isel.movImmediate(.x2, src_child_size * src_len); + try call.paramAddress(isel, src_vi, .r1); + try call.paramAddress(isel, dst_vi.value, .r0); + try call.finishParams(isel); + } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + } else if (dst_tag == .array and dst_ty.childType(zcu).isAbiInt(zcu) and src_ty.isAbiInt(zcu)) { + const dst_child_int_info = dst_ty.childType(zcu).intInfo(zcu); + const src_int_info = src_ty.intInfo(zcu); + const dst_len = dst_ty.arrayLenIncludingSentinel(zcu); + assert(dst_child_int_info.bits * dst_len == src_int_info.bits); + const dst_child_size = dst_ty.childType(zcu).abiSize(zcu); + if (8 * dst_child_size == dst_child_int_info.bits) { + try dst_vi.value.defAddr(isel, dst_ty, null, comptime &.initFill(.free)) orelse break :unused; + + try call.prepareReturn(isel); + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = "memcpy", + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const src_vi = try isel.use(ty_op.operand); + try isel.movImmediate(.x2, dst_child_size * dst_len); + try call.paramAddress(isel, src_vi, .r1); + try call.paramAddress(isel, dst_vi.value, .r0); + try call.finishParams(isel); + } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .block => { + const ty_pl = air.data(air.inst_index).ty_pl; + const extra = isel.air.extraData(Air.Block, ty_pl.payload); + + if (ty_pl.ty != .noreturn_type) { + isel.blocks.putAssumeCapacityNoClobber(air.inst_index, .{ + .live_registers = isel.live_registers, + .target_label = @intCast(isel.instructions.items.len), + }); + } + try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); + if (ty_pl.ty != .noreturn_type) { + const block_entry = isel.blocks.pop().?; + assert(block_entry.key == air.inst_index); + if (isel.live_values.fetchRemove(air.inst_index)) |result_vi| result_vi.value.deref(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .loop => { + const ty_pl = air.data(air.inst_index).ty_pl; + const extra = isel.air.extraData(Air.Block, ty_pl.payload); + const loops = isel.loops.values(); + const loop_index = isel.loops.getIndex(air.inst_index).?; + const loop = &loops[loop_index]; + + tracking_log.debug("{f}", .{ + isel.fmtDom(air.inst_index, loop.dom, @intCast(isel.blocks.count())), + }); + tracking_log.debug("{f}", .{isel.fmtLoopLive(air.inst_index)}); + assert(loop.depth == isel.blocks.count()); + + if (false) { + // loops are dumb... + for (isel.loop_live.list.items[loop.live..loops[loop_index + 1].live]) |live_inst| { + const live_vi = try isel.use(live_inst.toRef()); + try live_vi.mat(isel); + } + + // IT'S DOM TIME!!! + for (isel.blocks.values(), 0..) |*block, dom_index| { + if (@as(u1, @truncate(isel.dom.items[ + loop.dom + dom_index / @bitSizeOf(DomInt) + ] >> @truncate(dom_index))) == 0) continue; + var live_reg_it = block.live_registers.iterator(); + while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) { + _ => |live_vi| try live_vi.mat(isel), + .allocating => unreachable, + .free => {}, + }; + } + } + + loop.live_registers = isel.live_registers; + loop.repeat_list = Loop.empty_list; + try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); + try isel.merge(&loop.live_registers, .{ .fill_extra = true }); + + var repeat_label = loop.repeat_list; + assert(repeat_label != Loop.empty_list); + while (repeat_label != Loop.empty_list) { + const instruction = &isel.instructions.items[repeat_label]; + const next_repeat_label = instruction.*; + instruction.* = .b(-@as(i28, @intCast((isel.instructions.items.len - 1 - repeat_label) << 2))); + repeat_label = @bitCast(next_repeat_label); + } + + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .repeat => { + const repeat = air.data(air.inst_index).repeat; + try isel.loops.getPtr(repeat.loop_inst).?.branch(isel); + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .br => { + const br = air.data(air.inst_index).br; + const block = isel.blocks.getPtr(br.block_inst).?; + try block.branch(isel); + if (isel.live_values.get(br.block_inst)) |dst_vi| try dst_vi.move(isel, br.operand); + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .trap => { + try isel.emit(.brk(0x1)); + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .breakpoint => { + try isel.emit(.brk(0xf000)); + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .call => { + const pl_op = air.data(air.inst_index).pl_op; + const extra = isel.air.extraData(Air.Call, pl_op.payload); + const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]); + + try call.prepareReturn(isel); + const maybe_def_ret_vi = isel.live_values.fetchRemove(air.inst_index); + var maybe_ret_addr_vi: ?Value.Index = null; + if (maybe_def_ret_vi) |def_ret_vi| { + defer def_ret_vi.value.deref(isel); + + var ret_it: CallAbiIterator = .init; + const ret_vi = try ret_it.ret(isel, isel.air.typeOfIndex(air.inst_index, ip)); + defer ret_vi.?.deref(isel); + switch (ret_vi.?.parent(isel)) { + .unallocated, .stack_slot => if (ret_vi.?.hint(isel)) |ret_ra| { + try call.returnLiveIn(isel, def_ret_vi.value, ret_ra); + } else { + var def_ret_part_it = def_ret_vi.value.parts(isel); + var ret_part_it = ret_vi.?.parts(isel); + while (def_ret_part_it.next()) |ret_part_vi| { + try call.returnLiveIn(isel, ret_part_vi, ret_part_it.next().?.hint(isel).?); + } + }, + .value, .constant => unreachable, + .address => |address_vi| { + maybe_ret_addr_vi = address_vi; + _ = try def_ret_vi.value.defAddr( + isel, + isel.air.typeOfIndex(air.inst_index, ip), + null, + &call.caller_saved_regs, + ); + }, + } + } + try call.finishReturn(isel); + + try call.prepareCallee(isel); + if (pl_op.operand.toInterned()) |ct_callee| { + try isel.nav_relocs.append(gpa, switch (ip.indexToKey(ct_callee)) { + else => unreachable, + inline .@"extern", .func => |func| .{ + .nav = func.owner_nav, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }, + .ptr => |ptr| .{ + .nav = ptr.base_addr.nav, + .reloc = .{ + .label = @intCast(isel.instructions.items.len), + .addend = ptr.byte_offset, + }, + }, + }); + try isel.emit(.bl(0)); + } else { + const callee_vi = try isel.use(pl_op.operand); + const callee_mat = try callee_vi.matReg(isel); + try isel.emit(.blr(callee_mat.ra.x())); + try callee_mat.finish(isel); + } + try call.finishCallee(isel); + + try call.prepareParams(isel); + if (maybe_ret_addr_vi) |ret_addr_vi| try call.paramAddress( + isel, + maybe_def_ret_vi.?.value, + ret_addr_vi.hint(isel).?, + ); + var param_it: CallAbiIterator = .init; + for (args) |arg| { + const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue; + defer param_vi.deref(isel); + const arg_vi = try isel.use(arg); + const passed_vi = switch (param_vi.parent(isel)) { + .unallocated, .stack_slot => param_vi, + .value, .constant => unreachable, + .address => |address_vi| { + try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?); + continue; + }, + }; + if (passed_vi.hint(isel)) |param_ra| { + try call.paramLiveOut(isel, arg_vi, param_ra); + } else { + var param_part_it = passed_vi.parts(isel); + var arg_part_it = arg_vi.parts(isel); + if (arg_part_it.only()) |_| { + try isel.values.ensureUnusedCapacity(isel.pt.zcu.gpa, param_part_it.remaining); + arg_vi.setParts(isel, param_part_it.remaining); + while (param_part_it.next()) |param_part_vi| _ = arg_vi.addPart( + isel, + param_part_vi.get(isel).offset_from_parent, + param_part_vi.size(isel), + ); + param_part_it = passed_vi.parts(isel); + arg_part_it = arg_vi.parts(isel); + } + while (param_part_it.next()) |param_part_vi| { + const arg_part_vi = arg_part_it.next().?; + assert(arg_part_vi.get(isel).offset_from_parent == + param_part_vi.get(isel).offset_from_parent); + assert(arg_part_vi.size(isel) == param_part_vi.size(isel)); + try call.paramLiveOut(isel, arg_part_vi, param_part_vi.hint(isel).?); + } + } + } + try call.finishParams(isel); + + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .clz => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const ty = isel.air.typeOf(ty_op.operand, ip); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + switch (int_info.bits) { + 0 => unreachable, + 1...64 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.clzLimb(res_ra, int_info, src_mat.ra); + try src_mat.finish(isel); + }, + 65...128 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + var src_hi64_it = src_vi.field(ty, 8, 8); + const src_hi64_vi = try src_hi64_it.only(isel); + const src_hi64_mat = try src_hi64_vi.?.matReg(isel); + var src_lo64_it = src_vi.field(ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + const src_lo64_mat = try src_lo64_vi.?.matReg(isel); + const lo64_ra = try isel.allocIntReg(); + defer isel.freeReg(lo64_ra); + const hi64_ra = try isel.allocIntReg(); + defer isel.freeReg(hi64_ra); + try isel.emit(.csel(res_ra.w(), lo64_ra.w(), hi64_ra.w(), .eq)); + try isel.emit(.add(lo64_ra.w(), lo64_ra.w(), .{ .immediate = @intCast(bits - 64) })); + try isel.emit(.subs(.xzr, src_hi64_mat.ra.x(), .{ .immediate = 0 })); + try isel.clzLimb(hi64_ra, .{ .signedness = int_info.signedness, .bits = bits - 64 }, src_hi64_mat.ra); + try isel.clzLimb(lo64_ra, .{ .signedness = .unsigned, .bits = 64 }, src_lo64_mat.ra); + try src_hi64_mat.finish(isel); + try src_lo64_mat.finish(isel); + }, + else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .ctz => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const ty = isel.air.typeOf(ty_op.operand, ip); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + switch (int_info.bits) { + 0 => unreachable, + 1...64 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.ctzLimb(res_ra, int_info, src_mat.ra); + try src_mat.finish(isel); + }, + 65...128 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + var src_hi64_it = src_vi.field(ty, 8, 8); + const src_hi64_vi = try src_hi64_it.only(isel); + const src_hi64_mat = try src_hi64_vi.?.matReg(isel); + var src_lo64_it = src_vi.field(ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + const src_lo64_mat = try src_lo64_vi.?.matReg(isel); + const lo64_ra = try isel.allocIntReg(); + defer isel.freeReg(lo64_ra); + const hi64_ra = try isel.allocIntReg(); + defer isel.freeReg(hi64_ra); + try isel.emit(.csel(res_ra.w(), lo64_ra.w(), hi64_ra.w(), .ne)); + try isel.emit(.add(hi64_ra.w(), hi64_ra.w(), .{ .immediate = 64 })); + try isel.emit(.subs(.xzr, src_lo64_mat.ra.x(), .{ .immediate = 0 })); + try isel.ctzLimb(hi64_ra, .{ .signedness = .unsigned, .bits = 64 }, src_hi64_mat.ra); + try isel.ctzLimb(lo64_ra, .{ .signedness = int_info.signedness, .bits = bits - 64 }, src_lo64_mat.ra); + try src_hi64_mat.finish(isel); + try src_lo64_mat.finish(isel); + }, + else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .popcount => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const ty = isel.air.typeOf(ty_op.operand, ip); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + const vec_ra = try isel.allocVecReg(); + defer isel.freeReg(vec_ra); + try isel.emit(.umov(res_ra.w(), vec_ra.@"b[]"(0))); + switch (int_info.bits) { + else => unreachable, + 1...8 => {}, + 9...16 => try isel.emit(.addp(vec_ra.@"8b"(), vec_ra.@"8b"(), .{ .vector = vec_ra.@"8b"() })), + 17...64 => try isel.emit(.addv(vec_ra.b(), vec_ra.@"8b"())), + } + try isel.emit(.cnt(vec_ra.@"8b"(), vec_ra.@"8b"())); + switch (int_info.bits) { + else => unreachable, + 1...31 => |bits| switch (int_info.signedness) { + .signed => { + try isel.emit(.fmov(vec_ra.s(), .{ .register = res_ra.w() })); + try isel.emit(.ubfm(res_ra.w(), src_mat.ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(bits - 1), + })); + }, + .unsigned => try isel.emit(.fmov(vec_ra.s(), .{ .register = src_mat.ra.w() })), + }, + 32 => try isel.emit(.fmov(vec_ra.s(), .{ .register = src_mat.ra.w() })), + 33...63 => |bits| switch (int_info.signedness) { + .signed => { + try isel.emit(.fmov(vec_ra.d(), .{ .register = res_ra.x() })); + try isel.emit(.ubfm(res_ra.x(), src_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + })); + }, + .unsigned => try isel.emit(.fmov(vec_ra.d(), .{ .register = src_mat.ra.x() })), + }, + 64 => try isel.emit(.fmov(vec_ra.d(), .{ .register = src_mat.ra.x() })), + } + try src_mat.finish(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .byte_swap => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const ty = ty_op.ty.toType(); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + + if (int_info.bits == 8) break :unused try res_vi.value.move(isel, ty_op.operand); + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + switch (int_info.bits) { + else => unreachable, + 16 => switch (int_info.signedness) { + .signed => { + try isel.emit(.sbfm(res_ra.w(), res_ra.w(), .{ + .N = .word, + .immr = 32 - 16, + .imms = 32 - 1, + })); + try isel.emit(.rev(res_ra.w(), src_mat.ra.w())); + }, + .unsigned => try isel.emit(.rev16(res_ra.w(), src_mat.ra.w())), + }, + 24 => { + switch (int_info.signedness) { + .signed => try isel.emit(.sbfm(res_ra.w(), res_ra.w(), .{ + .N = .word, + .immr = 32 - 24, + .imms = 32 - 1, + })), + .unsigned => try isel.emit(.ubfm(res_ra.w(), res_ra.w(), .{ + .N = .word, + .immr = 32 - 24, + .imms = 32 - 1, + })), + } + try isel.emit(.rev(res_ra.w(), src_mat.ra.w())); + }, + 32 => try isel.emit(.rev(res_ra.w(), src_mat.ra.w())), + 40, 48, 56 => |bits| { + switch (int_info.signedness) { + .signed => try isel.emit(.sbfm(res_ra.x(), res_ra.x(), .{ + .N = .doubleword, + .immr = @intCast(64 - bits), + .imms = 64 - 1, + })), + .unsigned => try isel.emit(.ubfm(res_ra.x(), res_ra.x(), .{ + .N = .doubleword, + .immr = @intCast(64 - bits), + .imms = 64 - 1, + })), + } + try isel.emit(.rev(res_ra.x(), src_mat.ra.x())); + }, + 64 => try isel.emit(.rev(res_ra.x(), src_mat.ra.x())), + } + try src_mat.finish(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .bit_reverse => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const ty = ty_op.ty.toType(); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + switch (int_info.bits) { + else => unreachable, + 1...31 => |bits| { + switch (int_info.signedness) { + .signed => try isel.emit(.sbfm(res_ra.w(), res_ra.w(), .{ + .N = .word, + .immr = @intCast(32 - bits), + .imms = 32 - 1, + })), + .unsigned => try isel.emit(.ubfm(res_ra.w(), res_ra.w(), .{ + .N = .word, + .immr = @intCast(32 - bits), + .imms = 32 - 1, + })), + } + try isel.emit(.rbit(res_ra.w(), src_mat.ra.w())); + }, + 32 => try isel.emit(.rbit(res_ra.w(), src_mat.ra.w())), + 33...63 => |bits| { + switch (int_info.signedness) { + .signed => try isel.emit(.sbfm(res_ra.x(), res_ra.x(), .{ + .N = .doubleword, + .immr = @intCast(64 - bits), + .imms = 64 - 1, + })), + .unsigned => try isel.emit(.ubfm(res_ra.x(), res_ra.x(), .{ + .N = .doubleword, + .immr = @intCast(64 - bits), + .imms = 64 - 1, + })), + } + try isel.emit(.rbit(res_ra.x(), src_mat.ra.x())); + }, + 64 => try isel.emit(.rbit(res_ra.x(), src_mat.ra.x())), + } + try src_mat.finish(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .sqrt, .floor, .ceil, .round, .trunc_float => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const un_op = air.data(air.inst_index).un_op; + const ty = isel.air.typeOf(un_op, ip); + switch (ty.floatBits(isel.target)) { + else => unreachable, + 16, 32, 64 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const need_fcvt = switch (bits) { + else => unreachable, + 16 => !isel.target.cpu.has(.aarch64, .fullfp16), + 32, 64 => false, + }; + if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); + const src_vi = try isel.use(un_op); + const src_mat = try src_vi.matReg(isel); + const src_ra = if (need_fcvt) try isel.allocVecReg() else src_mat.ra; + defer if (need_fcvt) isel.freeReg(src_ra); + try isel.emit(bits: switch (bits) { + else => unreachable, + 16 => if (need_fcvt) continue :bits 32 else switch (air_tag) { + else => unreachable, + .sqrt => .fsqrt(res_ra.h(), src_ra.h()), + .floor => .frintm(res_ra.h(), src_ra.h()), + .ceil => .frintp(res_ra.h(), src_ra.h()), + .round => .frinta(res_ra.h(), src_ra.h()), + .trunc_float => .frintz(res_ra.h(), src_ra.h()), + }, + 32 => switch (air_tag) { + else => unreachable, + .sqrt => .fsqrt(res_ra.s(), src_ra.s()), + .floor => .frintm(res_ra.s(), src_ra.s()), + .ceil => .frintp(res_ra.s(), src_ra.s()), + .round => .frinta(res_ra.s(), src_ra.s()), + .trunc_float => .frintz(res_ra.s(), src_ra.s()), + }, + 64 => switch (air_tag) { + else => unreachable, + .sqrt => .fsqrt(res_ra.d(), src_ra.d()), + .floor => .frintm(res_ra.d(), src_ra.d()), + .ceil => .frintp(res_ra.d(), src_ra.d()), + .round => .frinta(res_ra.d(), src_ra.d()), + .trunc_float => .frintz(res_ra.d(), src_ra.d()), + }, + }); + if (need_fcvt) try isel.emit(.fcvt(src_ra.s(), src_mat.ra.h())); + try src_mat.finish(isel); + }, + 80, 128 => |bits| { + try call.prepareReturn(isel); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), + 80 => { + var res_hi16_it = res_vi.value.field(ty, 8, 8); + const res_hi16_vi = try res_hi16_it.only(isel); + try call.returnLiveIn(isel, res_hi16_vi.?, .r1); + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + try call.returnLiveIn(isel, res_lo64_vi.?, .r0); + }, + } + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = switch (air_tag) { + else => unreachable, + .sqrt => switch (bits) { + else => unreachable, + 16 => "__sqrth", + 32 => "sqrtf", + 64 => "sqrt", + 80 => "__sqrtx", + 128 => "sqrtq", + }, + .floor => switch (bits) { + else => unreachable, + 16 => "__floorh", + 32 => "floorf", + 64 => "floor", + 80 => "__floorx", + 128 => "floorq", + }, + .ceil => switch (bits) { + else => unreachable, + 16 => "__ceilh", + 32 => "ceilf", + 64 => "ceil", + 80 => "__ceilx", + 128 => "ceilq", + }, + .round => switch (bits) { + else => unreachable, + 16 => "__roundh", + 32 => "roundf", + 64 => "round", + 80 => "__roundx", + 128 => "roundq", + }, + .trunc_float => switch (bits) { + else => unreachable, + 16 => "__trunch", + 32 => "truncf", + 64 => "trunc", + 80 => "__truncx", + 128 => "truncq", + }, + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const src_vi = try isel.use(un_op); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0), + 80 => { + var src_hi16_it = src_vi.field(ty, 8, 8); + const src_hi16_vi = try src_hi16_it.only(isel); + try call.paramLiveOut(isel, src_hi16_vi.?, .r1); + var src_lo64_it = src_vi.field(ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + try call.paramLiveOut(isel, src_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .sin, .cos, .tan, .exp, .exp2, .log, .log2, .log10 => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| { + defer res_vi.value.deref(isel); + + const un_op = air.data(air.inst_index).un_op; + const ty = isel.air.typeOf(un_op, ip); + const bits = ty.floatBits(isel.target); + try call.prepareReturn(isel); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), + 80 => { + var res_hi16_it = res_vi.value.field(ty, 8, 8); + const res_hi16_vi = try res_hi16_it.only(isel); + try call.returnLiveIn(isel, res_hi16_vi.?, .r1); + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + try call.returnLiveIn(isel, res_lo64_vi.?, .r0); + }, + } + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = switch (air_tag) { + else => unreachable, + .sin => switch (bits) { + else => unreachable, + 16 => "__sinh", + 32 => "sinf", + 64 => "sin", + 80 => "__sinx", + 128 => "sinq", + }, + .cos => switch (bits) { + else => unreachable, + 16 => "__cosh", + 32 => "cosf", + 64 => "cos", + 80 => "__cosx", + 128 => "cosq", + }, + .tan => switch (bits) { + else => unreachable, + 16 => "__tanh", + 32 => "tanf", + 64 => "tan", + 80 => "__tanx", + 128 => "tanq", + }, + .exp => switch (bits) { + else => unreachable, + 16 => "__exph", + 32 => "expf", + 64 => "exp", + 80 => "__expx", + 128 => "expq", + }, + .exp2 => switch (bits) { + else => unreachable, + 16 => "__exp2h", + 32 => "exp2f", + 64 => "exp2", + 80 => "__exp2x", + 128 => "exp2q", + }, + .log => switch (bits) { + else => unreachable, + 16 => "__logh", + 32 => "logf", + 64 => "log", + 80 => "__logx", + 128 => "logq", + }, + .log2 => switch (bits) { + else => unreachable, + 16 => "__log2h", + 32 => "log2f", + 64 => "log2", + 80 => "__log2x", + 128 => "log2q", + }, + .log10 => switch (bits) { + else => unreachable, + 16 => "__log10h", + 32 => "log10f", + 64 => "log10", + 80 => "__log10x", + 128 => "log10q", + }, + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const src_vi = try isel.use(un_op); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0), + 80 => { + var src_hi16_it = src_vi.field(ty, 8, 8); + const src_hi16_vi = try src_hi16_it.only(isel); + try call.paramLiveOut(isel, src_hi16_vi.?, .r1); + var src_lo64_it = src_vi.field(ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + try call.paramLiveOut(isel, src_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .abs => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const ty = ty_op.ty.toType(); + if (!ty.isRuntimeFloat()) { + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + switch (ty.intInfo(zcu).bits) { + 0 => unreachable, + 1...32 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(.csneg(res_ra.w(), src_mat.ra.w(), src_mat.ra.w(), .pl)); + try isel.emit(.subs(.wzr, src_mat.ra.w(), .{ .immediate = 0 })); + try src_mat.finish(isel); + }, + 33...64 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(.csneg(res_ra.x(), src_mat.ra.x(), src_mat.ra.x(), .pl)); + try isel.emit(.subs(.xzr, src_mat.ra.x(), .{ .immediate = 0 })); + try src_mat.finish(isel); + }, + 65...128 => { + var res_hi64_it = res_vi.value.field(ty, 8, 8); + const res_hi64_vi = try res_hi64_it.only(isel); + const res_hi64_ra = try res_hi64_vi.?.defReg(isel); + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + const res_lo64_ra = try res_lo64_vi.?.defReg(isel); + if (res_hi64_ra == null and res_lo64_ra == null) break :unused; + const src_ty = isel.air.typeOf(ty_op.operand, ip); + const src_vi = try isel.use(ty_op.operand); + var src_hi64_it = src_vi.field(src_ty, 8, 8); + const src_hi64_vi = try src_hi64_it.only(isel); + const src_hi64_mat = try src_hi64_vi.?.matReg(isel); + var src_lo64_it = src_vi.field(src_ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + const src_lo64_mat = try src_lo64_vi.?.matReg(isel); + const lo64_ra = try isel.allocIntReg(); + defer isel.freeReg(lo64_ra); + const hi64_ra, const mask_ra = alloc_ras: { + const res_lo64_lock: RegLock = if (res_lo64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty; + defer res_lo64_lock.unlock(isel); + break :alloc_ras .{ try isel.allocIntReg(), try isel.allocIntReg() }; + }; + defer { + isel.freeReg(hi64_ra); + isel.freeReg(mask_ra); + } + if (res_hi64_ra) |res_ra| try isel.emit(.sbc(res_ra.x(), hi64_ra.x(), mask_ra.x())); + try isel.emit(.subs( + if (res_lo64_ra) |res_ra| res_ra.x() else .xzr, + lo64_ra.x(), + .{ .register = mask_ra.x() }, + )); + if (res_hi64_ra) |_| try isel.emit(.eor(hi64_ra.x(), src_hi64_mat.ra.x(), .{ .register = mask_ra.x() })); + try isel.emit(.eor(lo64_ra.x(), src_lo64_mat.ra.x(), .{ .register = mask_ra.x() })); + try isel.emit(.sbfm(mask_ra.x(), src_hi64_mat.ra.x(), .{ + .N = .doubleword, + .immr = 64 - 1, + .imms = 64 - 1, + })); + try src_lo64_mat.finish(isel); + try src_hi64_mat.finish(isel); + }, + else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + } + } else switch (ty.floatBits(isel.target)) { + else => unreachable, + 16 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(if (isel.target.cpu.has(.aarch64, .fullfp16)) + .fabs(res_ra.h(), src_mat.ra.h()) + else + .bic(res_ra.@"4h"(), res_ra.@"4h"(), .{ .shifted_immediate = .{ + .immediate = 0b10000000, + .lsl = 8, + } })); + try src_mat.finish(isel); + }, + 32 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(.fabs(res_ra.s(), src_mat.ra.s())); + try src_mat.finish(isel); + }, + 64 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(.fabs(res_ra.d(), src_mat.ra.d())); + try src_mat.finish(isel); + }, + 80 => { + const src_vi = try isel.use(ty_op.operand); + var res_hi16_it = res_vi.value.field(ty, 8, 8); + const res_hi16_vi = try res_hi16_it.only(isel); + if (try res_hi16_vi.?.defReg(isel)) |res_hi16_ra| { + var src_hi16_it = src_vi.field(ty, 8, 8); + const src_hi16_vi = try src_hi16_it.only(isel); + const src_hi16_mat = try src_hi16_vi.?.matReg(isel); + try isel.emit(.@"and"(res_hi16_ra.w(), src_hi16_mat.ra.w(), .{ .immediate = .{ + .N = .word, + .immr = 0, + .imms = 15 - 1, + } })); + try src_hi16_mat.finish(isel); + } + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + if (try res_lo64_vi.?.defReg(isel)) |res_lo64_ra| { + var src_lo64_it = src_vi.field(ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + try src_lo64_vi.?.liveOut(isel, res_lo64_ra); + } + }, + 128 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + const neg_zero_ra = try isel.allocVecReg(); + defer isel.freeReg(neg_zero_ra); + try isel.emit(.bic(res_ra.@"16b"(), src_mat.ra.@"16b"(), .{ .register = neg_zero_ra.@"16b"() })); + try isel.literals.appendNTimes(gpa, 0, -%isel.literals.items.len % 4); + try isel.literal_relocs.append(gpa, .{ + .label = @intCast(isel.instructions.items.len), + }); + try isel.emit(.ldr(neg_zero_ra.q(), .{ + .literal = @intCast((isel.instructions.items.len + 1 + isel.literals.items.len) << 2), + })); + try isel.emitLiteral(&(.{0} ** 15 ++ .{0x80})); + try src_mat.finish(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .neg, .neg_optimized => { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const un_op = air.data(air.inst_index).un_op; + const ty = isel.air.typeOf(un_op, ip); + switch (ty.floatBits(isel.target)) { + else => unreachable, + 16 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(un_op); + const src_mat = try src_vi.matReg(isel); + if (isel.target.cpu.has(.aarch64, .fullfp16)) { + try isel.emit(.fneg(res_ra.h(), src_mat.ra.h())); + } else { + const neg_zero_ra = try isel.allocVecReg(); + defer isel.freeReg(neg_zero_ra); + try isel.emit(.eor(res_ra.@"8b"(), res_ra.@"8b"(), .{ .register = neg_zero_ra.@"8b"() })); + try isel.emit(.movi(neg_zero_ra.@"4h"(), 0b10000000, .{ .lsl = 8 })); + } + try src_mat.finish(isel); + }, + 32 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(un_op); + const src_mat = try src_vi.matReg(isel); + try isel.emit(.fneg(res_ra.s(), src_mat.ra.s())); + try src_mat.finish(isel); + }, + 64 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(un_op); + const src_mat = try src_vi.matReg(isel); + try isel.emit(.fneg(res_ra.d(), src_mat.ra.d())); + try src_mat.finish(isel); + }, + 80 => { + const src_vi = try isel.use(un_op); + var res_hi16_it = res_vi.value.field(ty, 8, 8); + const res_hi16_vi = try res_hi16_it.only(isel); + if (try res_hi16_vi.?.defReg(isel)) |res_hi16_ra| { + var src_hi16_it = src_vi.field(ty, 8, 8); + const src_hi16_vi = try src_hi16_it.only(isel); + const src_hi16_mat = try src_hi16_vi.?.matReg(isel); + try isel.emit(.eor(res_hi16_ra.w(), src_hi16_mat.ra.w(), .{ .immediate = .{ + .N = .word, + .immr = 32 - 15, + .imms = 1 - 1, + } })); + try src_hi16_mat.finish(isel); + } + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + if (try res_lo64_vi.?.defReg(isel)) |res_lo64_ra| { + var src_lo64_it = src_vi.field(ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + try src_lo64_vi.?.liveOut(isel, res_lo64_ra); + } + }, + 128 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(un_op); + const src_mat = try src_vi.matReg(isel); + const neg_zero_ra = try isel.allocVecReg(); + defer isel.freeReg(neg_zero_ra); + try isel.emit(.eor(res_ra.@"16b"(), src_mat.ra.@"16b"(), .{ .register = neg_zero_ra.@"16b"() })); + try isel.literals.appendNTimes(gpa, 0, -%isel.literals.items.len % 4); + try isel.literal_relocs.append(gpa, .{ + .label = @intCast(isel.instructions.items.len), + }); + try isel.emit(.ldr(neg_zero_ra.q(), .{ + .literal = @intCast((isel.instructions.items.len + 1 + isel.literals.items.len) << 2), + })); + try isel.emitLiteral(&(.{0} ** 15 ++ .{0x80})); + try src_mat.finish(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .cmp_lt, .cmp_lte, .cmp_eq, .cmp_gte, .cmp_gt, .cmp_neq => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + var bin_op = air.data(air.inst_index).bin_op; + const ty = isel.air.typeOf(bin_op.lhs, ip); + if (!ty.isRuntimeFloat()) { + const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type) + .{ .signedness = .unsigned, .bits = 1 } + else if (ty.isAbiInt(zcu)) + ty.intInfo(zcu) + else if (ty.isPtrAtRuntime(zcu)) + .{ .signedness = .unsigned, .bits = 64 } + else + return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + if (int_info.bits > 256) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (air_tag) { + else => unreachable, + .cmp_lt => switch (int_info.signedness) { + .signed => .lt, + .unsigned => .lo, + }, + .cmp_lte => switch (int_info.bits) { + else => unreachable, + 1...64 => switch (int_info.signedness) { + .signed => .le, + .unsigned => .ls, + }, + 65...128 => { + std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs); + continue :cond .cmp_gte; + }, + }, + .cmp_eq => .eq, + .cmp_gte => switch (int_info.signedness) { + .signed => .ge, + .unsigned => .hs, + }, + .cmp_gt => switch (int_info.bits) { + else => unreachable, + 1...64 => switch (int_info.signedness) { + .signed => .gt, + .unsigned => .hi, + }, + 65...128 => { + std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs); + continue :cond .cmp_lt; + }, + }, + .cmp_neq => .ne, + }))); + + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + var part_offset = lhs_vi.size(isel); + while (part_offset > 0) { + const part_size = @min(part_offset, 8); + part_offset -= part_size; + var lhs_part_it = lhs_vi.field(ty, part_offset, part_size); + const lhs_part_vi = try lhs_part_it.only(isel); + const lhs_part_mat = try lhs_part_vi.?.matReg(isel); + var rhs_part_it = rhs_vi.field(ty, part_offset, part_size); + const rhs_part_vi = try rhs_part_it.only(isel); + const rhs_part_mat = try rhs_part_vi.?.matReg(isel); + try isel.emit(switch (part_size) { + else => unreachable, + 1...4 => switch (part_offset) { + 0 => .subs(.wzr, lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), + else => switch (air_tag) { + else => unreachable, + .cmp_lt, .cmp_lte, .cmp_gte, .cmp_gt => .sbcs( + .wzr, + lhs_part_mat.ra.w(), + rhs_part_mat.ra.w(), + ), + .cmp_eq, .cmp_neq => .ccmp( + lhs_part_mat.ra.w(), + .{ .register = rhs_part_mat.ra.w() }, + .{ .n = false, .z = false, .c = false, .v = false }, + .eq, + ), + }, + }, + 5...8 => switch (part_offset) { + 0 => .subs(.xzr, lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), + else => switch (air_tag) { + else => unreachable, + .cmp_lt, .cmp_lte, .cmp_gte, .cmp_gt => .sbcs( + .xzr, + lhs_part_mat.ra.x(), + rhs_part_mat.ra.x(), + ), + .cmp_eq, .cmp_neq => .ccmp( + lhs_part_mat.ra.x(), + .{ .register = rhs_part_mat.ra.x() }, + .{ .n = false, .z = false, .c = false, .v = false }, + .eq, + ), + }, + }, + }); + try rhs_part_mat.finish(isel); + try lhs_part_mat.finish(isel); + } + } else switch (ty.floatBits(isel.target)) { + else => unreachable, + 16, 32, 64 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const need_fcvt = switch (bits) { + else => unreachable, + 16 => !isel.target.cpu.has(.aarch64, .fullfp16), + 32, 64 => false, + }; + try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(switch (air_tag) { + else => unreachable, + .cmp_lt => .lo, + .cmp_lte => .ls, + .cmp_eq => .eq, + .cmp_gte => .ge, + .cmp_gt => .gt, + .cmp_neq => .ne, + }))); + + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; + defer if (need_fcvt) isel.freeReg(lhs_ra); + const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; + defer if (need_fcvt) isel.freeReg(rhs_ra); + try isel.emit(bits: switch (bits) { + else => unreachable, + 16 => if (need_fcvt) + continue :bits 32 + else + .fcmp(lhs_ra.h(), .{ .register = rhs_ra.h() }), + 32 => .fcmp(lhs_ra.s(), .{ .register = rhs_ra.s() }), + 64 => .fcmp(lhs_ra.d(), .{ .register = rhs_ra.d() }), + }); + if (need_fcvt) { + try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); + try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); + } + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 80, 128 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + + try call.prepareReturn(isel); + try call.returnFill(isel, .r0); + try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (air_tag) { + else => unreachable, + .cmp_lt => .lt, + .cmp_lte => .le, + .cmp_eq => .eq, + .cmp_gte => { + std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs); + continue :cond .cmp_lte; + }, + .cmp_gt => { + std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs); + continue :cond .cmp_lt; + }, + .cmp_neq => .ne, + }))); + try isel.emit(.subs(.wzr, .w0, .{ .immediate = 0 })); + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = switch (bits) { + else => unreachable, + 16 => "__cmphf2", + 32 => "__cmpsf2", + 64 => "__cmpdf2", + 80 => "__cmpxf2", + 128 => "__cmptf2", + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => { + try call.paramLiveOut(isel, rhs_vi, .v1); + try call.paramLiveOut(isel, lhs_vi, .v0); + }, + 80 => { + var rhs_hi16_it = rhs_vi.field(ty, 8, 8); + const rhs_hi16_vi = try rhs_hi16_it.only(isel); + try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); + var rhs_lo64_it = rhs_vi.field(ty, 0, 8); + const rhs_lo64_vi = try rhs_lo64_it.only(isel); + try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); + var lhs_hi16_it = lhs_vi.field(ty, 8, 8); + const lhs_hi16_vi = try lhs_hi16_it.only(isel); + try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); + var lhs_lo64_it = lhs_vi.field(ty, 0, 8); + const lhs_lo64_vi = try lhs_lo64_it.only(isel); + try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .cond_br => { + const pl_op = air.data(air.inst_index).pl_op; + const extra = isel.air.extraData(Air.CondBr, pl_op.payload); + + try isel.body(@ptrCast(isel.air.extra.items[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len])); + const else_label = isel.instructions.items.len; + const else_live_registers = isel.live_registers; + try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.then_body_len])); + try isel.merge(&else_live_registers, .{}); + + const cond_vi = try isel.use(pl_op.operand); + const cond_mat = try cond_vi.matReg(isel); + try isel.emit(.tbz( + cond_mat.ra.x(), + 0, + @intCast((isel.instructions.items.len + 1 - else_label) << 2), + )); + try cond_mat.finish(isel); + + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .switch_br => { + const switch_br = isel.air.unwrapSwitch(air.inst_index); + const cond_ty = isel.air.typeOf(switch_br.operand, ip); + const cond_int_info: std.builtin.Type.Int = if (cond_ty.toIntern() == .bool_type) + .{ .signedness = .unsigned, .bits = 1 } + else if (cond_ty.isAbiInt(zcu)) + cond_ty.intInfo(zcu) + else + return isel.fail("bad switch cond {f}", .{isel.fmtType(cond_ty)}); + + var final_case = true; + if (switch_br.else_body_len > 0) { + var cases_it = switch_br.iterateCases(); + while (cases_it.next()) |_| {} + try isel.body(cases_it.elseBody()); + assert(final_case); + final_case = false; + } + const zero_reg: Register = switch (cond_int_info.bits) { + else => unreachable, + 1...32 => .wzr, + 33...64 => .xzr, + }; + var cond_mat: ?Value.Materialize = null; + var cond_reg: Register = undefined; + var temp_reg: Register = undefined; + var cases_it = switch_br.iterateCases(); + while (cases_it.next()) |case| { + const next_label = isel.instructions.items.len; + const next_live_registers = isel.live_registers; + try isel.body(case.body); + if (final_case) { + final_case = false; + continue; + } + try isel.merge(&next_live_registers, .{}); + if (cond_mat == null) { + var cond_vi = try isel.use(switch_br.operand); + cond_mat = try cond_vi.matReg(isel); + const temp_ra = try isel.allocIntReg(); + cond_reg, temp_reg = switch (cond_int_info.bits) { + else => unreachable, + 1...32 => .{ cond_mat.?.ra.w(), temp_ra.w() }, + 33...64 => .{ cond_mat.?.ra.x(), temp_ra.x() }, + }; + } + if (case.ranges.len == 0 and case.items.len == 1 and Constant.fromInterned( + case.items[0].toInterned().?, + ).orderAgainstZero(zcu).compare(.eq)) { + try isel.emit(.cbnz( + cond_reg, + @intCast((isel.instructions.items.len + 1 - next_label) << 2), + )); + continue; + } + try isel.emit(.@"b."( + .invert(switch (case.ranges.len) { + 0 => .eq, + else => .ls, + }), + @intCast((isel.instructions.items.len + 1 - next_label) << 2), + )); + var case_range_index = case.ranges.len; + while (case_range_index > 0) { + case_range_index -= 1; + + const low_val: Constant = .fromInterned(case.ranges[case_range_index][0].toInterned().?); + var low_bigint_space: Constant.BigIntSpace = undefined; + const low_bigint = low_val.toBigInt(&low_bigint_space, zcu); + const low_int: i64 = if (low_bigint.positive) @bitCast( + low_bigint.toInt(u64) catch + return isel.fail("too big case range start: {f}", .{isel.fmtConstant(low_val)}), + ) else low_bigint.toInt(i64) catch + return isel.fail("too big case range start: {f}", .{isel.fmtConstant(low_val)}); + + const high_val: Constant = .fromInterned(case.ranges[case_range_index][1].toInterned().?); + var high_bigint_space: Constant.BigIntSpace = undefined; + const high_bigint = high_val.toBigInt(&high_bigint_space, zcu); + const high_int: i64 = if (high_bigint.positive) @bitCast( + high_bigint.toInt(u64) catch + return isel.fail("too big case range end: {f}", .{isel.fmtConstant(high_val)}), + ) else high_bigint.toInt(i64) catch + return isel.fail("too big case range end: {f}", .{isel.fmtConstant(high_val)}); + + const delta_int = high_int -% low_int; + if (case_range_index > 0) { + return isel.fail("case range", .{}); + } else if (case.items.len > 0) { + return isel.fail("case range", .{}); + } else { + const adjusted_reg = switch (low_int) { + 0 => cond_reg, + else => temp_reg, + }; + + if (std.math.cast(u12, delta_int)) |pos_imm| try isel.emit(.subs( + zero_reg, + adjusted_reg, + .{ .immediate = pos_imm }, + )) else if (std.math.cast(u12, -delta_int)) |neg_imm| try isel.emit(.adds( + zero_reg, + adjusted_reg, + .{ .immediate = neg_imm }, + )) else if (if (@as(i12, @truncate(delta_int)) == 0) + std.math.cast(u12, delta_int >> 12) + else + null) |pos_imm_lsr_12| try isel.emit(.subs( + zero_reg, + adjusted_reg, + .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } }, + )) else if (if (@as(i12, @truncate(-delta_int)) == 0) + std.math.cast(u12, -delta_int >> 12) + else + null) |neg_imm_lsr_12| try isel.emit(.adds( + zero_reg, + adjusted_reg, + .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } }, + )) else { + try isel.movImmediate(temp_reg, @bitCast(delta_int)); + try isel.emit(.subs(zero_reg, adjusted_reg, .{ .register = temp_reg })); + } + + switch (low_int) { + 0 => {}, + else => { + if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub( + adjusted_reg, + cond_reg, + .{ .immediate = pos_imm }, + )) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add( + adjusted_reg, + cond_reg, + .{ .immediate = neg_imm }, + )) else if (if (@as(i12, @truncate(low_int)) == 0) + std.math.cast(u12, low_int >> 12) + else + null) |pos_imm_lsr_12| try isel.emit(.sub( + adjusted_reg, + cond_reg, + .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } }, + )) else if (if (@as(i12, @truncate(-low_int)) == 0) + std.math.cast(u12, -low_int >> 12) + else + null) |neg_imm_lsr_12| try isel.emit(.add( + adjusted_reg, + cond_reg, + .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } }, + )) else { + try isel.movImmediate(temp_reg, @bitCast(low_int)); + try isel.emit(.subs(adjusted_reg, cond_reg, .{ .register = temp_reg })); + } + }, + } + } + } + var case_item_index = case.items.len; + while (case_item_index > 0) { + case_item_index -= 1; + + const item_val: Constant = .fromInterned(case.items[case_item_index].toInterned().?); + var item_bigint_space: Constant.BigIntSpace = undefined; + const item_bigint = item_val.toBigInt(&item_bigint_space, zcu); + const item_int: i64 = if (item_bigint.positive) @bitCast( + item_bigint.toInt(u64) catch + return isel.fail("too big case item: {f}", .{isel.fmtConstant(item_val)}), + ) else item_bigint.toInt(i64) catch + return isel.fail("too big case item: {f}", .{isel.fmtConstant(item_val)}); + + if (case_item_index > 0) { + if (std.math.cast(u5, item_int)) |pos_imm| try isel.emit(.ccmp( + cond_reg, + .{ .immediate = pos_imm }, + .{ .n = false, .z = true, .c = false, .v = false }, + .ne, + )) else if (std.math.cast(u5, -item_int)) |neg_imm| try isel.emit(.ccmn( + cond_reg, + .{ .immediate = neg_imm }, + .{ .n = false, .z = true, .c = false, .v = false }, + .ne, + )) else { + try isel.movImmediate(temp_reg, @bitCast(item_int)); + try isel.emit(.ccmp( + cond_reg, + .{ .register = temp_reg }, + .{ .n = false, .z = true, .c = false, .v = false }, + .ne, + )); + } + } else { + if (std.math.cast(u12, item_int)) |pos_imm| try isel.emit(.subs( + zero_reg, + cond_reg, + .{ .immediate = pos_imm }, + )) else if (std.math.cast(u12, -item_int)) |neg_imm| try isel.emit(.adds( + zero_reg, + cond_reg, + .{ .immediate = neg_imm }, + )) else if (if (@as(i12, @truncate(item_int)) == 0) + std.math.cast(u12, item_int >> 12) + else + null) |pos_imm_lsr_12| try isel.emit(.subs( + zero_reg, + cond_reg, + .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } }, + )) else if (if (@as(i12, @truncate(-item_int)) == 0) + std.math.cast(u12, -item_int >> 12) + else + null) |neg_imm_lsr_12| try isel.emit(.adds( + zero_reg, + cond_reg, + .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } }, + )) else { + try isel.movImmediate(temp_reg, @bitCast(item_int)); + try isel.emit(.subs(zero_reg, cond_reg, .{ .register = temp_reg })); + } + } + } + } + if (cond_mat) |mat| { + try mat.finish(isel); + isel.freeReg(temp_reg.alias); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .@"try", .try_cold => { + const pl_op = air.data(air.inst_index).pl_op; + const extra = isel.air.extraData(Air.Try, pl_op.payload); + const error_union_ty = isel.air.typeOf(pl_op.operand, ip); + const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type; + const payload_ty: ZigType = .fromInterned(error_union_info.payload_type); + + const error_union_vi = try isel.use(pl_op.operand); + if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| { + defer payload_vi.value.deref(isel); + + var payload_part_it = error_union_vi.field( + error_union_ty, + codegen.errUnionPayloadOffset(payload_ty, zcu), + payload_vi.value.size(isel), + ); + const payload_part_vi = try payload_part_it.only(isel); + try payload_vi.value.copy(isel, payload_ty, payload_part_vi.?); + } + + const cont_label = isel.instructions.items.len; + const cont_live_registers = isel.live_registers; + try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); + try isel.merge(&cont_live_registers, .{}); + + var error_set_part_it = error_union_vi.field( + error_union_ty, + codegen.errUnionErrorOffset(payload_ty, zcu), + ZigType.fromInterned(error_union_info.error_set_type).abiSize(zcu), + ); + const error_set_part_vi = try error_set_part_it.only(isel); + const error_set_part_mat = try error_set_part_vi.?.matReg(isel); + try isel.emit(.cbz( + switch (error_set_part_vi.?.size(isel)) { + else => unreachable, + 1...4 => error_set_part_mat.ra.w(), + 5...8 => error_set_part_mat.ra.x(), + }, + @intCast((isel.instructions.items.len + 1 - cont_label) << 2), + )); + try error_set_part_mat.finish(isel); + + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .dbg_stmt => { + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .dbg_empty_stmt => { + try isel.emit(.nop()); + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => { + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .is_null, .is_non_null => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: { + defer is_vi.value.deref(isel); + const is_ra = try is_vi.value.defReg(isel) orelse break :unused; + + const un_op = air.data(air.inst_index).un_op; + const opt_ty = isel.air.typeOf(un_op, ip); + const payload_ty = opt_ty.optionalChild(zcu); + const payload_size = payload_ty.abiSize(zcu); + const has_value_offset, const has_value_size = if (!opt_ty.optionalReprIsPayload(zcu)) + .{ payload_size, 1 } + else if (payload_ty.isSlice(zcu)) + .{ 0, 8 } + else + .{ 0, payload_size }; + + try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(switch (air_tag) { + else => unreachable, + .is_null => .eq, + .is_non_null => .ne, + }))); + const opt_vi = try isel.use(un_op); + var has_value_part_it = opt_vi.field(opt_ty, has_value_offset, has_value_size); + const has_value_part_vi = try has_value_part_it.only(isel); + const has_value_part_mat = try has_value_part_vi.?.matReg(isel); + try isel.emit(switch (has_value_size) { + else => unreachable, + 1...4 => .subs(.wzr, has_value_part_mat.ra.w(), .{ .immediate = 0 }), + 5...8 => .subs(.xzr, has_value_part_mat.ra.x(), .{ .immediate = 0 }), + }); + try has_value_part_mat.finish(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .is_err, .is_non_err => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: { + defer is_vi.value.deref(isel); + const is_ra = try is_vi.value.defReg(isel) orelse break :unused; + + const un_op = air.data(air.inst_index).un_op; + const error_union_ty = isel.air.typeOf(un_op, ip); + const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type; + const error_set_ty: ZigType = .fromInterned(error_union_info.error_set_type); + const payload_ty: ZigType = .fromInterned(error_union_info.payload_type); + const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu); + const error_set_size = error_set_ty.abiSize(zcu); + + try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(switch (air_tag) { + else => unreachable, + .is_err => .ne, + .is_non_err => .eq, + }))); + const error_union_vi = try isel.use(un_op); + var error_set_part_it = error_union_vi.field(error_union_ty, error_set_offset, error_set_size); + const error_set_part_vi = try error_set_part_it.only(isel); + const error_set_part_mat = try error_set_part_vi.?.matReg(isel); + try isel.emit(.ands(.wzr, error_set_part_mat.ra.w(), .{ .immediate = .{ + .N = .word, + .immr = 0, + .imms = @intCast(8 * error_set_size - 1), + } })); + try error_set_part_mat.finish(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .load => { + const ty_op = air.data(air.inst_index).ty_op; + const ptr_ty = isel.air.typeOf(ty_op.operand, ip); + const ptr_info = ptr_ty.ptrInfo(zcu); + if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed load", .{}); + + if (ptr_info.flags.is_volatile) _ = try isel.use(air.inst_index.toRef()); + if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { + defer dst_vi.value.deref(isel); + switch (dst_vi.value.size(isel)) { + 0 => unreachable, + 1...Value.max_parts => { + const ptr_vi = try isel.use(ty_op.operand); + const ptr_mat = try ptr_vi.matReg(isel); + _ = try dst_vi.value.load(isel, ty_op.ty.toType(), ptr_mat.ra, .{ + .@"volatile" = ptr_info.flags.is_volatile, + }); + try ptr_mat.finish(isel); + }, + else => |size| { + try dst_vi.value.defAddr(isel, .fromInterned(ptr_info.child), null, comptime &.initFill(.free)) orelse break :unused; + + try call.prepareReturn(isel); + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = "memcpy", + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const ptr_vi = try isel.use(ty_op.operand); + try isel.movImmediate(.x2, size); + try call.paramLiveOut(isel, ptr_vi, .r1); + try call.paramAddress(isel, dst_vi.value, .r0); + try call.finishParams(isel); + }, + } + } + + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .ret, .ret_safe => { + assert(isel.blocks.keys()[0] == Block.main); + try isel.blocks.values()[0].branch(isel); + if (isel.live_values.get(Block.main)) |ret_vi| { + const un_op = air.data(air.inst_index).un_op; + const src_vi = try isel.use(un_op); + switch (ret_vi.parent(isel)) { + .unallocated, .stack_slot => if (ret_vi.hint(isel)) |ret_ra| { + try src_vi.liveOut(isel, ret_ra); + } else { + var ret_part_it = ret_vi.parts(isel); + var src_part_it = src_vi.parts(isel); + if (src_part_it.only()) |_| { + try isel.values.ensureUnusedCapacity(gpa, ret_part_it.remaining); + src_vi.setParts(isel, ret_part_it.remaining); + while (ret_part_it.next()) |ret_part_vi| { + const src_part_vi = src_vi.addPart( + isel, + ret_part_vi.get(isel).offset_from_parent, + ret_part_vi.size(isel), + ); + switch (ret_part_vi.signedness(isel)) { + .signed => src_part_vi.setSignedness(isel, .signed), + .unsigned => {}, + } + if (ret_part_vi.isVector(isel)) src_part_vi.setIsVector(isel); + } + ret_part_it = ret_vi.parts(isel); + src_part_it = src_vi.parts(isel); + } + while (ret_part_it.next()) |ret_part_vi| { + const src_part_vi = src_part_it.next().?; + assert(ret_part_vi.get(isel).offset_from_parent == src_part_vi.get(isel).offset_from_parent); + assert(ret_part_vi.size(isel) == src_part_vi.size(isel)); + try src_part_vi.liveOut(isel, ret_part_vi.hint(isel).?); + } + }, + .value, .constant => unreachable, + .address => |address_vi| { + const ptr_mat = try address_vi.matReg(isel); + try src_vi.store(isel, isel.air.typeOf(un_op, ip), ptr_mat.ra, .{}); + try ptr_mat.finish(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .ret_load => { + const un_op = air.data(air.inst_index).un_op; + const ptr_ty = isel.air.typeOf(un_op, ip); + const ptr_info = ptr_ty.ptrInfo(zcu); + if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed load", .{}); + + assert(isel.blocks.keys()[0] == Block.main); + try isel.blocks.values()[0].branch(isel); + if (isel.live_values.get(Block.main)) |ret_vi| switch (ret_vi.parent(isel)) { + .unallocated, .stack_slot => { + var ret_part_it: Value.PartIterator = if (ret_vi.hint(isel)) |_| .initOne(ret_vi) else ret_vi.parts(isel); + while (ret_part_it.next()) |ret_part_vi| try ret_part_vi.liveOut(isel, ret_part_vi.hint(isel).?); + const ptr_vi = try isel.use(un_op); + const ptr_mat = try ptr_vi.matReg(isel); + _ = try ret_vi.load(isel, .fromInterned(ptr_info.child), ptr_mat.ra, .{}); + try ptr_mat.finish(isel); + }, + .value, .constant => unreachable, + .address => {}, + }; + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .store, .store_safe, .atomic_store_unordered => { + const bin_op = air.data(air.inst_index).bin_op; + const ptr_ty = isel.air.typeOf(bin_op.lhs, ip); + const ptr_info = ptr_ty.ptrInfo(zcu); + if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed store", .{}); + if (bin_op.rhs.toInterned()) |rhs_val| if (ip.isUndef(rhs_val)) { + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + break :air_tag; + }; + + const src_vi = try isel.use(bin_op.rhs); + const size = src_vi.size(isel); + if (ZigType.fromInterned(ptr_info.child).zigTypeTag(zcu) != .@"union") switch (size) { + 0 => unreachable, + 1...Value.max_parts => { + const ptr_vi = try isel.use(bin_op.lhs); + const ptr_mat = try ptr_vi.matReg(isel); + try src_vi.store(isel, isel.air.typeOf(bin_op.rhs, ip), ptr_mat.ra, .{ + .@"volatile" = ptr_info.flags.is_volatile, + }); + try ptr_mat.finish(isel); + + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + break :air_tag; + }, + else => {}, + }; + try call.prepareReturn(isel); + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = "memcpy", + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const ptr_vi = try isel.use(bin_op.lhs); + try isel.movImmediate(.x2, size); + try call.paramAddress(isel, src_vi, .r1); + try call.paramLiveOut(isel, ptr_vi, .r0); + try call.finishParams(isel); + + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .unreach => if (air.next()) |next_air_tag| continue :air_tag next_air_tag, + .fptrunc, .fpext => { + if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { + defer dst_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const dst_ty = ty_op.ty.toType(); + const dst_bits = dst_ty.floatBits(isel.target); + const src_ty = isel.air.typeOf(ty_op.operand, ip); + const src_bits = src_ty.floatBits(isel.target); + assert(dst_bits != src_bits); + switch (@max(dst_bits, src_bits)) { + else => unreachable, + 16, 32, 64 => { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(.fcvt(switch (dst_bits) { + else => unreachable, + 16 => dst_ra.h(), + 32 => dst_ra.s(), + 64 => dst_ra.d(), + }, switch (src_bits) { + else => unreachable, + 16 => src_mat.ra.h(), + 32 => src_mat.ra.s(), + 64 => src_mat.ra.d(), + })); + try src_mat.finish(isel); + }, + 80, 128 => { + try call.prepareReturn(isel); + switch (dst_bits) { + else => unreachable, + 16, 32, 64, 128 => try call.returnLiveIn(isel, dst_vi.value, .v0), + 80 => { + var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8); + const dst_hi16_vi = try dst_hi16_it.only(isel); + try call.returnLiveIn(isel, dst_hi16_vi.?, .r1); + var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); + const dst_lo64_vi = try dst_lo64_it.only(isel); + try call.returnLiveIn(isel, dst_lo64_vi.?, .r0); + }, + } + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = switch (dst_bits) { + else => unreachable, + 16 => switch (src_bits) { + else => unreachable, + 32 => "__truncsfhf2", + 64 => "__truncdfhf2", + 80 => "__truncxfhf2", + 128 => "__trunctfhf2", + }, + 32 => switch (src_bits) { + else => unreachable, + 16 => "__extendhfsf2", + 64 => "__truncdfsf2", + 80 => "__truncxfsf2", + 128 => "__trunctfsf2", + }, + 64 => switch (src_bits) { + else => unreachable, + 16 => "__extendhfdf2", + 32 => "__extendsfdf2", + 80 => "__truncxfdf2", + 128 => "__trunctfdf2", + }, + 80 => switch (src_bits) { + else => unreachable, + 16 => "__extendhfxf2", + 32 => "__extendsfxf2", + 64 => "__extenddfxf2", + 128 => "__trunctfxf2", + }, + 128 => switch (src_bits) { + else => unreachable, + 16 => "__extendhftf2", + 32 => "__extendsftf2", + 64 => "__extenddftf2", + 80 => "__extendxftf2", + }, + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const src_vi = try isel.use(ty_op.operand); + switch (src_bits) { + else => unreachable, + 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0), + 80 => { + var src_hi16_it = src_vi.field(src_ty, 8, 8); + const src_hi16_vi = try src_hi16_it.only(isel); + try call.paramLiveOut(isel, src_hi16_vi.?, .r1); + var src_lo64_it = src_vi.field(src_ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + try call.paramLiveOut(isel, src_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .intcast => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { + defer dst_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const dst_ty = ty_op.ty.toType(); + const dst_int_info = dst_ty.intInfo(zcu); + const src_ty = isel.air.typeOf(ty_op.operand, ip); + const src_int_info = src_ty.intInfo(zcu); + const can_be_negative = dst_int_info.signedness == .signed and + src_int_info.signedness == .signed; + if ((dst_int_info.bits <= 8 and src_int_info.bits <= 8) or + (dst_int_info.bits > 8 and dst_int_info.bits <= 16 and + src_int_info.bits > 8 and src_int_info.bits <= 16) or + (dst_int_info.bits > 16 and dst_int_info.bits <= 32 and + src_int_info.bits > 16 and src_int_info.bits <= 32) or + (dst_int_info.bits > 32 and dst_int_info.bits <= 64 and + src_int_info.bits > 32 and src_int_info.bits <= 64) or + (dst_int_info.bits > 64 and src_int_info.bits > 64 and + (dst_int_info.bits - 1) / 128 == (src_int_info.bits - 1) / 128)) + { + try dst_vi.value.move(isel, ty_op.operand); + } else if (dst_int_info.bits <= 32 and src_int_info.bits <= 64) { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(.orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() })); + try src_mat.finish(isel); + } else if (dst_int_info.bits <= 64 and src_int_info.bits <= 32) { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + try isel.emit(if (can_be_negative) .sbfm(dst_ra.x(), src_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(src_int_info.bits - 1), + }) else .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() })); + try src_mat.finish(isel); + } else if (dst_int_info.bits <= 32 and src_int_info.bits <= 128) { + assert(src_int_info.bits > 64); + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + + var src_lo64_it = src_vi.field(src_ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + const src_lo64_mat = try src_lo64_vi.?.matReg(isel); + try isel.emit(.orr(dst_ra.w(), .wzr, .{ .register = src_lo64_mat.ra.w() })); + try src_lo64_mat.finish(isel); + } else if (dst_int_info.bits <= 64 and src_int_info.bits <= 128) { + assert(dst_int_info.bits > 32 and src_int_info.bits > 64); + const src_vi = try isel.use(ty_op.operand); + + var src_lo64_it = src_vi.field(src_ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + try dst_vi.value.copy(isel, dst_ty, src_lo64_vi.?); + } else if (dst_int_info.bits <= 128 and src_int_info.bits <= 64) { + assert(dst_int_info.bits > 64); + const src_vi = try isel.use(ty_op.operand); + + var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); + const dst_lo64_vi = try dst_lo64_it.only(isel); + if (src_int_info.bits <= 32) unused_lo64: { + const dst_lo64_ra = try dst_lo64_vi.?.defReg(isel) orelse break :unused_lo64; + const src_mat = try src_vi.matReg(isel); + try isel.emit(if (can_be_negative) .sbfm(dst_lo64_ra.x(), src_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(src_int_info.bits - 1), + }) else .orr(dst_lo64_ra.w(), .wzr, .{ .register = src_mat.ra.w() })); + try src_mat.finish(isel); + } else try dst_lo64_vi.?.copy(isel, src_ty, src_vi); + + var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8); + const dst_hi64_vi = try dst_hi64_it.only(isel); + const dst_hi64_ra = try dst_hi64_vi.?.defReg(isel); + if (dst_hi64_ra) |dst_ra| switch (can_be_negative) { + false => try isel.emit(.orr(dst_ra.x(), .xzr, .{ .register = .xzr })), + true => { + const src_mat = try src_vi.matReg(isel); + try isel.emit(.sbfm(dst_ra.x(), src_mat.ra.x(), .{ + .N = .doubleword, + .immr = @intCast(src_int_info.bits - 1), + .imms = @intCast(src_int_info.bits - 1), + })); + try src_mat.finish(isel); + }, + }; + } else return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .trunc => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { + defer dst_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const dst_ty = ty_op.ty.toType(); + const src_ty = isel.air.typeOf(ty_op.operand, ip); + if (!dst_ty.isAbiInt(zcu) or !src_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + const dst_int_info = dst_ty.intInfo(zcu); + switch (dst_int_info.bits) { + 0 => unreachable, + 1...64 => |dst_bits| { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + var src_part_it = src_vi.field(src_ty, 0, @min(src_vi.size(isel), 8)); + const src_part_vi = try src_part_it.only(isel); + const src_part_mat = try src_part_vi.?.matReg(isel); + try isel.emit(switch (dst_bits) { + else => unreachable, + 1...31 => |bits| switch (dst_int_info.signedness) { + .signed => .sbfm(dst_ra.w(), src_part_mat.ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(bits - 1), + }), + .unsigned => .ubfm(dst_ra.w(), src_part_mat.ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(bits - 1), + }), + }, + 32 => .orr(dst_ra.w(), .wzr, .{ .register = src_part_mat.ra.w() }), + 33...63 => |bits| switch (dst_int_info.signedness) { + .signed => .sbfm(dst_ra.x(), src_part_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + }), + .unsigned => .ubfm(dst_ra.x(), src_part_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + }), + }, + 64 => .orr(dst_ra.x(), .xzr, .{ .register = src_part_mat.ra.x() }), + }); + try src_part_mat.finish(isel); + }, + 65...128 => |dst_bits| switch (src_ty.intInfo(zcu).bits) { + 0 => unreachable, + 65...128 => { + const src_vi = try isel.use(ty_op.operand); + var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8); + const dst_hi64_vi = try dst_hi64_it.only(isel); + if (try dst_hi64_vi.?.defReg(isel)) |dst_hi64_ra| { + var src_hi64_it = src_vi.field(src_ty, 8, 8); + const src_hi64_vi = try src_hi64_it.only(isel); + const src_hi64_mat = try src_hi64_vi.?.matReg(isel); + try isel.emit(switch (dst_int_info.signedness) { + .signed => .sbfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(dst_bits - 64 - 1), + }), + .unsigned => .ubfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(dst_bits - 64 - 1), + }), + }); + try src_hi64_mat.finish(isel); + } + var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); + const dst_lo64_vi = try dst_lo64_it.only(isel); + if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| { + var src_lo64_it = src_vi.field(src_ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + try src_lo64_vi.?.liveOut(isel, dst_lo64_ra); + } + }, + else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), + }, + else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .optional_payload_ptr => { + if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| { + defer dst_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + try dst_vi.value.move(isel, ty_op.operand); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .optional_payload => { + if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| unused: { + defer payload_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const opt_ty = isel.air.typeOf(ty_op.operand, ip); + if (opt_ty.optionalReprIsPayload(zcu)) { + try payload_vi.value.move(isel, ty_op.operand); + break :unused; + } + + const opt_vi = try isel.use(ty_op.operand); + var payload_part_it = opt_vi.field(opt_ty, 0, payload_vi.value.size(isel)); + const payload_part_vi = try payload_part_it.only(isel); + try payload_vi.value.copy(isel, ty_op.ty.toType(), payload_part_vi.?); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .wrap_optional => { + if (isel.live_values.fetchRemove(air.inst_index)) |opt_vi| unused: { + defer opt_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + if (ty_op.ty.toType().optionalReprIsPayload(zcu)) { + try opt_vi.value.move(isel, ty_op.operand); + break :unused; + } + + const payload_size = isel.air.typeOf(ty_op.operand, ip).abiSize(zcu); + var payload_part_it = opt_vi.value.field(ty_op.ty.toType(), 0, payload_size); + const payload_part_vi = try payload_part_it.only(isel); + try payload_part_vi.?.move(isel, ty_op.operand); + var has_value_part_it = opt_vi.value.field(ty_op.ty.toType(), payload_size, 1); + const has_value_part_vi = try has_value_part_it.only(isel); + const has_value_part_ra = try has_value_part_vi.?.defReg(isel) orelse break :unused; + try isel.emit(.movz(has_value_part_ra.w(), 1, .{ .lsl = .@"0" })); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .unwrap_errunion_payload => { + if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| { + defer payload_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const error_union_ty = isel.air.typeOf(ty_op.operand, ip); + + const error_union_vi = try isel.use(ty_op.operand); + var payload_part_it = error_union_vi.field( + error_union_ty, + codegen.errUnionPayloadOffset(ty_op.ty.toType(), zcu), + payload_vi.value.size(isel), + ); + const payload_part_vi = try payload_part_it.only(isel); + try payload_vi.value.copy(isel, ty_op.ty.toType(), payload_part_vi.?); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .unwrap_errunion_err => { + if (isel.live_values.fetchRemove(air.inst_index)) |error_set_vi| { + defer error_set_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const error_union_ty = isel.air.typeOf(ty_op.operand, ip); + + const error_union_vi = try isel.use(ty_op.operand); + var error_set_part_it = error_union_vi.field( + error_union_ty, + codegen.errUnionErrorOffset(error_union_ty.errorUnionPayload(zcu), zcu), + error_set_vi.value.size(isel), + ); + const error_set_part_vi = try error_set_part_it.only(isel); + try error_set_vi.value.copy(isel, ty_op.ty.toType(), error_set_part_vi.?); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .wrap_errunion_payload => { + if (isel.live_values.fetchRemove(air.inst_index)) |error_union_vi| { + defer error_union_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const error_union_ty = ty_op.ty.toType(); + const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type; + const error_set_ty: ZigType = .fromInterned(error_union_info.error_set_type); + const payload_ty: ZigType = .fromInterned(error_union_info.payload_type); + const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu); + const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu); + const error_set_size = error_set_ty.abiSize(zcu); + const payload_size = payload_ty.abiSize(zcu); + + var payload_part_it = error_union_vi.value.field(error_union_ty, payload_offset, payload_size); + const payload_part_vi = try payload_part_it.only(isel); + try payload_part_vi.?.move(isel, ty_op.operand); + var error_set_part_it = error_union_vi.value.field(error_union_ty, error_set_offset, error_set_size); + const error_set_part_vi = try error_set_part_it.only(isel); + if (try error_set_part_vi.?.defReg(isel)) |error_set_part_ra| try isel.emit(switch (error_set_size) { + else => unreachable, + 1...4 => .orr(error_set_part_ra.w(), .wzr, .{ .register = .wzr }), + 5...8 => .orr(error_set_part_ra.x(), .xzr, .{ .register = .xzr }), + }); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .wrap_errunion_err => { + if (isel.live_values.fetchRemove(air.inst_index)) |error_union_vi| { + defer error_union_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const error_union_ty = ty_op.ty.toType(); + const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type; + const error_set_ty: ZigType = .fromInterned(error_union_info.error_set_type); + const payload_ty: ZigType = .fromInterned(error_union_info.payload_type); + const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu); + const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu); + const error_set_size = error_set_ty.abiSize(zcu); + const payload_size = payload_ty.abiSize(zcu); + + if (payload_size > 0) { + var payload_part_it = error_union_vi.value.field(error_union_ty, payload_offset, payload_size); + const payload_part_vi = try payload_part_it.only(isel); + if (try payload_part_vi.?.defReg(isel)) |payload_part_ra| try isel.emit(switch (payload_size) { + else => unreachable, + 1...4 => .orr(payload_part_ra.w(), .wzr, .{ .immediate = .{ + .N = .word, + .immr = 0b000001, + .imms = 0b111100, + } }), + 5...8 => .orr(payload_part_ra.x(), .xzr, .{ .immediate = .{ + .N = .word, + .immr = 0b000001, + .imms = 0b111100, + } }), + }); + } + var error_set_part_it = error_union_vi.value.field(error_union_ty, error_set_offset, error_set_size); + const error_set_part_vi = try error_set_part_it.only(isel); + try error_set_part_vi.?.move(isel, ty_op.operand); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .struct_field_ptr => { + if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { + defer dst_vi.value.deref(isel); + const ty_pl = air.data(air.inst_index).ty_pl; + const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data; + switch (codegen.fieldOffset( + isel.air.typeOf(extra.struct_operand, ip), + ty_pl.ty.toType(), + extra.field_index, + zcu, + )) { + 0 => try dst_vi.value.move(isel, extra.struct_operand), + else => |field_offset| { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(extra.struct_operand); + const src_mat = try src_vi.matReg(isel); + const lo12: u12 = @truncate(field_offset >> 0); + const hi12: u12 = @intCast(field_offset >> 12); + if (hi12 > 0) try isel.emit(.add( + dst_ra.x(), + if (lo12 > 0) dst_ra.x() else src_mat.ra.x(), + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + )); + if (lo12 > 0) try isel.emit(.add(dst_ra.x(), src_mat.ra.x(), .{ .immediate = lo12 })); + try src_mat.finish(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .struct_field_ptr_index_0, + .struct_field_ptr_index_1, + .struct_field_ptr_index_2, + .struct_field_ptr_index_3, + => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { + defer dst_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + switch (codegen.fieldOffset( + isel.air.typeOf(ty_op.operand, ip), + ty_op.ty.toType(), + switch (air_tag) { + else => unreachable, + .struct_field_ptr_index_0 => 0, + .struct_field_ptr_index_1 => 1, + .struct_field_ptr_index_2 => 2, + .struct_field_ptr_index_3 => 3, + }, + zcu, + )) { + 0 => try dst_vi.value.move(isel, ty_op.operand), + else => |field_offset| { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + const lo12: u12 = @truncate(field_offset >> 0); + const hi12: u12 = @intCast(field_offset >> 12); + if (hi12 > 0) try isel.emit(.add( + dst_ra.x(), + if (lo12 > 0) dst_ra.x() else src_mat.ra.x(), + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + )); + if (lo12 > 0) try isel.emit(.add(dst_ra.x(), src_mat.ra.x(), .{ .immediate = lo12 })); + try src_mat.finish(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .struct_field_val => { + if (isel.live_values.fetchRemove(air.inst_index)) |field_vi| { + defer field_vi.value.deref(isel); + + const ty_pl = air.data(air.inst_index).ty_pl; + const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data; + const agg_ty = isel.air.typeOf(extra.struct_operand, ip); + const field_ty = ty_pl.ty.toType(); + const field_bit_offset, const field_bit_size, const is_packed = switch (agg_ty.containerLayout(zcu)) { + .auto, .@"extern" => .{ + 8 * agg_ty.structFieldOffset(extra.field_index, zcu), + 8 * field_ty.abiSize(zcu), + false, + }, + .@"packed" => .{ + if (zcu.typeToPackedStruct(agg_ty)) |loaded_struct| + zcu.structPackedFieldBitOffset(loaded_struct, extra.field_index) + else + 0, + field_ty.bitSize(zcu), + true, + }, + }; + if (is_packed) return isel.fail("packed field of {f}", .{ + isel.fmtType(agg_ty), + }); + + const agg_vi = try isel.use(extra.struct_operand); + var agg_part_it = agg_vi.field(agg_ty, @divExact(field_bit_offset, 8), @divExact(field_bit_size, 8)); + while (try agg_part_it.next(isel)) |agg_part| { + var field_part_it = field_vi.value.field(ty_pl.ty.toType(), agg_part.offset, agg_part.vi.size(isel)); + const field_part_vi = try field_part_it.only(isel); + if (field_part_vi.? == agg_part.vi) continue; + var field_subpart_it = field_part_vi.?.parts(isel); + const field_part_offset = if (field_subpart_it.only()) |field_subpart_vi| + field_subpart_vi.get(isel).offset_from_parent + else + 0; + while (field_subpart_it.next()) |field_subpart_vi| { + const field_subpart_ra = try field_subpart_vi.defReg(isel) orelse continue; + const field_subpart_offset, const field_subpart_size = field_subpart_vi.position(isel); + var agg_subpart_it = agg_part.vi.field( + field_ty, + agg_part.offset + field_subpart_offset - field_part_offset, + field_subpart_size, + ); + const agg_subpart_vi = try agg_subpart_it.only(isel); + try agg_subpart_vi.?.liveOut(isel, field_subpart_ra); + } + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .slice => { + if (isel.live_values.fetchRemove(air.inst_index)) |slice_vi| { + defer slice_vi.value.deref(isel); + const ty_pl = air.data(air.inst_index).ty_pl; + const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; + var ptr_part_it = slice_vi.value.field(ty_pl.ty.toType(), 0, 8); + const ptr_part_vi = try ptr_part_it.only(isel); + try ptr_part_vi.?.move(isel, bin_op.lhs); + var len_part_it = slice_vi.value.field(ty_pl.ty.toType(), 8, 8); + const len_part_vi = try len_part_it.only(isel); + try len_part_vi.?.move(isel, bin_op.rhs); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .slice_len => { + if (isel.live_values.fetchRemove(air.inst_index)) |len_vi| { + defer len_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + const slice_vi = try isel.use(ty_op.operand); + var len_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 8, 8); + const len_part_vi = try len_part_it.only(isel); + try len_vi.value.copy(isel, ty_op.ty.toType(), len_part_vi.?); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .slice_ptr => { + if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| { + defer ptr_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + const slice_vi = try isel.use(ty_op.operand); + var ptr_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 0, 8); + const ptr_part_vi = try ptr_part_it.only(isel); + try ptr_vi.value.copy(isel, ty_op.ty.toType(), ptr_part_vi.?); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .array_elem_val => { + if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: { + defer elem_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const array_ty = isel.air.typeOf(bin_op.lhs, ip); + const elem_ty = array_ty.childType(zcu); + const elem_size = elem_ty.abiSize(zcu); + if (elem_size <= 16 and array_ty.arrayLenIncludingSentinel(zcu) <= Value.max_parts) if (bin_op.rhs.toInterned()) |index_val| { + const elem_offset = elem_size * Constant.fromInterned(index_val).toUnsignedInt(zcu); + const array_vi = try isel.use(bin_op.lhs); + var elem_part_it = array_vi.field(array_ty, elem_offset, elem_size); + const elem_part_vi = try elem_part_it.only(isel); + try elem_vi.value.copy(isel, elem_ty, elem_part_vi.?); + break :unused; + }; + switch (elem_size) { + 0 => unreachable, + 1, 2, 4, 8 => { + const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused; + const array_ptr_ra = try isel.allocIntReg(); + defer isel.freeReg(array_ptr_ra); + const index_vi = try isel.use(bin_op.rhs); + const index_mat = try index_vi.matReg(isel); + try isel.emit(switch (elem_size) { + else => unreachable, + 1 => if (elem_vi.value.isVector(isel)) .ldr(elem_ra.b(), .{ .extended_register = .{ + .base = array_ptr_ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 0 }, + } }) else switch (elem_vi.value.signedness(isel)) { + .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{ + .base = array_ptr_ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 0 }, + } }), + .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{ + .base = array_ptr_ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 0 }, + } }), + }, + 2 => if (elem_vi.value.isVector(isel)) .ldr(elem_ra.h(), .{ .extended_register = .{ + .base = array_ptr_ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 1 }, + } }) else switch (elem_vi.value.signedness(isel)) { + .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{ + .base = array_ptr_ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 1 }, + } }), + .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{ + .base = array_ptr_ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 1 }, + } }), + }, + 4 => .ldr(if (elem_vi.value.isVector(isel)) elem_ra.s() else elem_ra.w(), .{ .extended_register = .{ + .base = array_ptr_ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 2 }, + } }), + 8 => .ldr(if (elem_vi.value.isVector(isel)) elem_ra.d() else elem_ra.x(), .{ .extended_register = .{ + .base = array_ptr_ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 3 }, + } }), + 16 => .ldr(elem_ra.q(), .{ .extended_register = .{ + .base = array_ptr_ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 4 }, + } }), + }); + try index_mat.finish(isel); + const array_vi = try isel.use(bin_op.lhs); + try array_vi.address(isel, 0, array_ptr_ra); + }, + else => { + const ptr_ra = try isel.allocIntReg(); + defer isel.freeReg(ptr_ra); + if (!try elem_vi.value.load(isel, elem_ty, ptr_ra, .{})) break :unused; + const index_vi = try isel.use(bin_op.rhs); + try isel.elemPtr(ptr_ra, ptr_ra, .add, elem_size, index_vi); + const array_vi = try isel.use(bin_op.lhs); + try array_vi.address(isel, 0, ptr_ra); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .slice_elem_val => { + if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: { + defer elem_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const slice_ty = isel.air.typeOf(bin_op.lhs, ip); + const ptr_info = slice_ty.ptrInfo(zcu); + const elem_size = elem_vi.value.size(isel); + const elem_is_vector = elem_vi.value.isVector(isel); + if (switch (elem_size) { + 0 => unreachable, + 1, 2, 4, 8 => true, + 16 => elem_is_vector, + else => false, + }) { + const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused; + const slice_vi = try isel.use(bin_op.lhs); + const index_vi = try isel.use(bin_op.rhs); + var ptr_part_it = slice_vi.field(slice_ty, 0, 8); + const ptr_part_vi = try ptr_part_it.only(isel); + const base_mat = try ptr_part_vi.?.matReg(isel); + const index_mat = try index_vi.matReg(isel); + try isel.emit(switch (elem_size) { + else => unreachable, + 1 => if (elem_is_vector) .ldr(elem_ra.b(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 0 }, + } }) else switch (elem_vi.value.signedness(isel)) { + .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 0 }, + } }), + .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 0 }, + } }), + }, + 2 => if (elem_is_vector) .ldr(elem_ra.h(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 0 }, + } }) else switch (elem_vi.value.signedness(isel)) { + .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 1 }, + } }), + .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 1 }, + } }), + }, + 4 => .ldr(if (elem_is_vector) elem_ra.s() else elem_ra.w(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 2 }, + } }), + 8 => .ldr(if (elem_is_vector) elem_ra.d() else elem_ra.x(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 3 }, + } }), + 16 => .ldr(elem_ra.q(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 4 }, + } }), + }); + try index_mat.finish(isel); + try base_mat.finish(isel); + break :unused; + } else { + const elem_ptr_ra = try isel.allocIntReg(); + defer isel.freeReg(elem_ptr_ra); + if (!try elem_vi.value.load(isel, slice_ty.elemType2(zcu), elem_ptr_ra, .{ + .@"volatile" = ptr_info.flags.is_volatile, + })) break :unused; + const slice_vi = try isel.use(bin_op.lhs); + var ptr_part_it = slice_vi.field(slice_ty, 0, 8); + const ptr_part_vi = try ptr_part_it.only(isel); + const ptr_part_mat = try ptr_part_vi.?.matReg(isel); + const index_vi = try isel.use(bin_op.rhs); + try isel.elemPtr(elem_ptr_ra, ptr_part_mat.ra, .add, elem_size, index_vi); + try ptr_part_mat.finish(isel); + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .slice_elem_ptr => { + if (isel.live_values.fetchRemove(air.inst_index)) |elem_ptr_vi| unused: { + defer elem_ptr_vi.value.deref(isel); + const elem_ptr_ra = try elem_ptr_vi.value.defReg(isel) orelse break :unused; + + const ty_pl = air.data(air.inst_index).ty_pl; + const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; + const elem_size = ty_pl.ty.toType().childType(zcu).abiSize(zcu); + + const slice_vi = try isel.use(bin_op.lhs); + var ptr_part_it = slice_vi.field(isel.air.typeOf(bin_op.lhs, ip), 0, 8); + const ptr_part_vi = try ptr_part_it.only(isel); + const ptr_part_mat = try ptr_part_vi.?.matReg(isel); + const index_vi = try isel.use(bin_op.rhs); + try isel.elemPtr(elem_ptr_ra, ptr_part_mat.ra, .add, elem_size, index_vi); + try ptr_part_mat.finish(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .ptr_elem_val => { + if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: { + defer elem_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const ptr_ty = isel.air.typeOf(bin_op.lhs, ip); + const ptr_info = ptr_ty.ptrInfo(zcu); + const elem_size = elem_vi.value.size(isel); + switch (elem_size) { + 0 => unreachable, + 1, 2, 4, 8 => { + const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused; + const base_vi = try isel.use(bin_op.lhs); + const index_vi = try isel.use(bin_op.rhs); + const base_mat = try base_vi.matReg(isel); + const index_mat = try index_vi.matReg(isel); + try isel.emit(switch (elem_size) { + else => unreachable, + 1 => switch (elem_vi.value.signedness(isel)) { + .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 0 }, + } }), + .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 0 }, + } }), + }, + 2 => switch (elem_vi.value.signedness(isel)) { + .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 1 }, + } }), + .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 1 }, + } }), + }, + 4 => .ldr(elem_ra.w(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 2 }, + } }), + 8 => .ldr(elem_ra.x(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 3 }, + } }), + }); + try index_mat.finish(isel); + try base_mat.finish(isel); + }, + else => { + const elem_ptr_ra = try isel.allocIntReg(); + defer isel.freeReg(elem_ptr_ra); + if (!try elem_vi.value.load(isel, ptr_ty.elemType2(zcu), elem_ptr_ra, .{ + .@"volatile" = ptr_info.flags.is_volatile, + })) break :unused; + const base_vi = try isel.use(bin_op.lhs); + const base_mat = try base_vi.matReg(isel); + const index_vi = try isel.use(bin_op.rhs); + try isel.elemPtr(elem_ptr_ra, base_mat.ra, .add, elem_size, index_vi); + try base_mat.finish(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .ptr_elem_ptr => { + if (isel.live_values.fetchRemove(air.inst_index)) |elem_ptr_vi| unused: { + defer elem_ptr_vi.value.deref(isel); + const elem_ptr_ra = try elem_ptr_vi.value.defReg(isel) orelse break :unused; + + const ty_pl = air.data(air.inst_index).ty_pl; + const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; + const elem_size = ty_pl.ty.toType().childType(zcu).abiSize(zcu); + + const base_vi = try isel.use(bin_op.lhs); + const base_mat = try base_vi.matReg(isel); + const index_vi = try isel.use(bin_op.rhs); + try isel.elemPtr(elem_ptr_ra, base_mat.ra, .add, elem_size, index_vi); + try base_mat.finish(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .array_to_slice => { + if (isel.live_values.fetchRemove(air.inst_index)) |slice_vi| { + defer slice_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + var ptr_part_it = slice_vi.value.field(ty_op.ty.toType(), 0, 8); + const ptr_part_vi = try ptr_part_it.only(isel); + try ptr_part_vi.?.move(isel, ty_op.operand); + var len_part_it = slice_vi.value.field(ty_op.ty.toType(), 8, 8); + const len_part_vi = try len_part_it.only(isel); + if (try len_part_vi.?.defReg(isel)) |len_ra| try isel.movImmediate( + len_ra.x(), + isel.air.typeOf(ty_op.operand, ip).childType(zcu).arrayLen(zcu), + ); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .int_from_float, .int_from_float_optimized => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { + defer dst_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const dst_ty = ty_op.ty.toType(); + const src_ty = isel.air.typeOf(ty_op.operand, ip); + if (!dst_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + const dst_int_info = dst_ty.intInfo(zcu); + const src_bits = src_ty.floatBits(isel.target); + switch (@max(dst_int_info.bits, src_bits)) { + 0 => unreachable, + 1...64 => { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const need_fcvt = switch (src_bits) { + else => unreachable, + 16 => !isel.target.cpu.has(.aarch64, .fullfp16), + 32, 64 => false, + }; + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + const src_ra = if (need_fcvt) try isel.allocVecReg() else src_mat.ra; + defer if (need_fcvt) isel.freeReg(src_ra); + const dst_reg = switch (dst_int_info.bits) { + else => unreachable, + 1...32 => dst_ra.w(), + 33...64 => dst_ra.x(), + }; + const src_reg = switch (src_bits) { + else => unreachable, + 16 => if (need_fcvt) src_ra.s() else src_ra.h(), + 32 => src_ra.s(), + 64 => src_ra.d(), + }; + try isel.emit(switch (dst_int_info.signedness) { + .signed => .fcvtzs(dst_reg, src_reg), + .unsigned => .fcvtzu(dst_reg, src_reg), + }); + if (need_fcvt) try isel.emit(.fcvt(src_reg, src_mat.ra.h())); + try src_mat.finish(isel); + }, + 65...128 => { + try call.prepareReturn(isel); + switch (dst_int_info.bits) { + else => unreachable, + 1...64 => try call.returnLiveIn(isel, dst_vi.value, .r0), + 65...128 => { + var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8); + const dst_hi64_vi = try dst_hi64_it.only(isel); + try call.returnLiveIn(isel, dst_hi64_vi.?, .r1); + var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); + const dst_lo64_vi = try dst_lo64_it.only(isel); + try call.returnLiveIn(isel, dst_lo64_vi.?, .r0); + }, + } + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = switch (dst_int_info.bits) { + else => unreachable, + 1...32 => switch (dst_int_info.signedness) { + .signed => switch (src_bits) { + else => unreachable, + 16 => "__fixhfsi", + 32 => "__fixsfsi", + 64 => "__fixdfsi", + 80 => "__fixxfsi", + 128 => "__fixtfsi", + }, + .unsigned => switch (src_bits) { + else => unreachable, + 16 => "__fixunshfsi", + 32 => "__fixunssfsi", + 64 => "__fixunsdfsi", + 80 => "__fixunsxfsi", + 128 => "__fixunstfsi", + }, + }, + 33...64 => switch (dst_int_info.signedness) { + .signed => switch (src_bits) { + else => unreachable, + 16 => "__fixhfdi", + 32 => "__fixsfdi", + 64 => "__fixdfdi", + 80 => "__fixxfdi", + 128 => "__fixtfdi", + }, + .unsigned => switch (src_bits) { + else => unreachable, + 16 => "__fixunshfdi", + 32 => "__fixunssfdi", + 64 => "__fixunsdfdi", + 80 => "__fixunsxfdi", + 128 => "__fixunstfdi", + }, + }, + 65...128 => switch (dst_int_info.signedness) { + .signed => switch (src_bits) { + else => unreachable, + 16 => "__fixhfti", + 32 => "__fixsfti", + 64 => "__fixdfti", + 80 => "__fixxfti", + 128 => "__fixtfti", + }, + .unsigned => switch (src_bits) { + else => unreachable, + 16 => "__fixunshfti", + 32 => "__fixunssfti", + 64 => "__fixunsdfti", + 80 => "__fixunsxfti", + 128 => "__fixunstfti", + }, + }, + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const src_vi = try isel.use(ty_op.operand); + switch (src_bits) { + else => unreachable, + 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0), + 80 => { + var src_hi16_it = src_vi.field(src_ty, 8, 8); + const src_hi16_vi = try src_hi16_it.only(isel); + try call.paramLiveOut(isel, src_hi16_vi.?, .r1); + var src_lo64_it = src_vi.field(src_ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + try call.paramLiveOut(isel, src_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + }, + else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .float_from_int => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { + defer dst_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const dst_ty = ty_op.ty.toType(); + const src_ty = isel.air.typeOf(ty_op.operand, ip); + const dst_bits = dst_ty.floatBits(isel.target); + if (!src_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + const src_int_info = src_ty.intInfo(zcu); + switch (@max(dst_bits, src_int_info.bits)) { + 0 => unreachable, + 1...64 => { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const need_fcvt = switch (dst_bits) { + else => unreachable, + 16 => !isel.target.cpu.has(.aarch64, .fullfp16), + 32, 64 => false, + }; + if (need_fcvt) try isel.emit(.fcvt(dst_ra.h(), dst_ra.s())); + const src_vi = try isel.use(ty_op.operand); + const src_mat = try src_vi.matReg(isel); + const dst_reg = switch (dst_bits) { + else => unreachable, + 16 => if (need_fcvt) dst_ra.s() else dst_ra.h(), + 32 => dst_ra.s(), + 64 => dst_ra.d(), + }; + const src_reg = switch (src_int_info.bits) { + else => unreachable, + 1...32 => src_mat.ra.w(), + 33...64 => src_mat.ra.x(), + }; + try isel.emit(switch (src_int_info.signedness) { + .signed => .scvtf(dst_reg, src_reg), + .unsigned => .ucvtf(dst_reg, src_reg), + }); + try src_mat.finish(isel); + }, + 65...128 => { + try call.prepareReturn(isel); + switch (dst_bits) { + else => unreachable, + 16, 32, 64, 128 => try call.returnLiveIn(isel, dst_vi.value, .v0), + 80 => { + var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8); + const dst_hi16_vi = try dst_hi16_it.only(isel); + try call.returnLiveIn(isel, dst_hi16_vi.?, .r1); + var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); + const dst_lo64_vi = try dst_lo64_it.only(isel); + try call.returnLiveIn(isel, dst_lo64_vi.?, .r0); + }, + } + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = switch (src_int_info.bits) { + else => unreachable, + 1...32 => switch (src_int_info.signedness) { + .signed => switch (dst_bits) { + else => unreachable, + 16 => "__floatsihf", + 32 => "__floatsisf", + 64 => "__floatsidf", + 80 => "__floatsixf", + 128 => "__floatsitf", + }, + .unsigned => switch (dst_bits) { + else => unreachable, + 16 => "__floatunsihf", + 32 => "__floatunsisf", + 64 => "__floatunsidf", + 80 => "__floatunsixf", + 128 => "__floatunsitf", + }, + }, + 33...64 => switch (src_int_info.signedness) { + .signed => switch (dst_bits) { + else => unreachable, + 16 => "__floatdihf", + 32 => "__floatdisf", + 64 => "__floatdidf", + 80 => "__floatdixf", + 128 => "__floatditf", + }, + .unsigned => switch (dst_bits) { + else => unreachable, + 16 => "__floatundihf", + 32 => "__floatundisf", + 64 => "__floatundidf", + 80 => "__floatundixf", + 128 => "__floatunditf", + }, + }, + 65...128 => switch (src_int_info.signedness) { + .signed => switch (dst_bits) { + else => unreachable, + 16 => "__floattihf", + 32 => "__floattisf", + 64 => "__floattidf", + 80 => "__floattixf", + 128 => "__floattitf", + }, + .unsigned => switch (dst_bits) { + else => unreachable, + 16 => "__floatuntihf", + 32 => "__floatuntisf", + 64 => "__floatuntidf", + 80 => "__floatuntixf", + 128 => "__floatuntitf", + }, + }, + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const src_vi = try isel.use(ty_op.operand); + switch (src_int_info.bits) { + else => unreachable, + 1...64 => try call.paramLiveOut(isel, src_vi, .r0), + 65...128 => { + var src_hi64_it = src_vi.field(src_ty, 8, 8); + const src_hi64_vi = try src_hi64_it.only(isel); + try call.paramLiveOut(isel, src_hi64_vi.?, .r1); + var src_lo64_it = src_vi.field(src_ty, 0, 8); + const src_lo64_vi = try src_lo64_it.only(isel); + try call.paramLiveOut(isel, src_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + }, + else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .memset => |air_tag| { + const bin_op = air.data(air.inst_index).bin_op; + const dst_ty = isel.air.typeOf(bin_op.lhs, ip); + const dst_info = dst_ty.ptrInfo(zcu); + const fill_byte: union(enum) { constant: u8, value: Air.Inst.Ref } = fill_byte: { + if (bin_op.rhs.toInterned()) |fill_val| + if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte| + break :fill_byte .{ .constant = fill_byte }; + switch (dst_ty.elemType2(zcu).abiSize(zcu)) { + 0 => unreachable, + 1 => break :fill_byte .{ .value = bin_op.rhs }, + 2, 4, 8 => |size| { + const dst_vi = try isel.use(bin_op.lhs); + const ptr_ra = try isel.allocIntReg(); + const fill_vi = try isel.use(bin_op.rhs); + const fill_mat = try fill_vi.matReg(isel); + const len_mat: Value.Materialize = len_mat: switch (dst_info.flags.size) { + .one => .{ .vi = undefined, .ra = try isel.allocIntReg() }, + .many => unreachable, + .slice => { + var dst_len_it = dst_vi.field(dst_ty, 8, 8); + const dst_len_vi = try dst_len_it.only(isel); + break :len_mat try dst_len_vi.?.matReg(isel); + }, + .c => unreachable, + }; + + const skip_label = isel.instructions.items.len; + _ = try isel.instructions.addOne(gpa); + try isel.emit(.sub(len_mat.ra.x(), len_mat.ra.x(), .{ .immediate = 1 })); + try isel.emit(switch (size) { + else => unreachable, + 2 => .strh(fill_mat.ra.w(), .{ .post_index = .{ .base = ptr_ra.x(), .index = 2 } }), + 4 => .str(fill_mat.ra.w(), .{ .post_index = .{ .base = ptr_ra.x(), .index = 4 } }), + 8 => .str(fill_mat.ra.x(), .{ .post_index = .{ .base = ptr_ra.x(), .index = 8 } }), + }); + isel.instructions.items[skip_label] = .cbnz( + len_mat.ra.x(), + -@as(i21, @intCast((isel.instructions.items.len - 1 - skip_label) << 2)), + ); + switch (dst_info.flags.size) { + .one => { + const len_imm = ZigType.fromInterned(dst_info.child).arrayLen(zcu); + assert(len_imm > 0); + try isel.movImmediate(len_mat.ra.x(), len_imm); + isel.freeReg(len_mat.ra); + try fill_mat.finish(isel); + isel.freeReg(ptr_ra); + try dst_vi.liveOut(isel, ptr_ra); + }, + .many => unreachable, + .slice => { + try isel.emit(.cbz( + len_mat.ra.x(), + @intCast((isel.instructions.items.len + 1 - skip_label) << 2), + )); + try len_mat.finish(isel); + try fill_mat.finish(isel); + isel.freeReg(ptr_ra); + var dst_ptr_it = dst_vi.field(dst_ty, 0, 8); + const dst_ptr_vi = try dst_ptr_it.only(isel); + try dst_ptr_vi.?.liveOut(isel, ptr_ra); + }, + .c => unreachable, + } + + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + break :air_tag; + }, + else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty) }), + } + }; + + try call.prepareReturn(isel); + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = "memset", + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const dst_vi = try isel.use(bin_op.lhs); + switch (dst_info.flags.size) { + .one => { + try isel.movImmediate(.x2, ZigType.fromInterned(dst_info.child).abiSize(zcu)); + switch (fill_byte) { + .constant => |byte| try isel.movImmediate(.w1, byte), + .value => |byte| try call.paramLiveOut(isel, try isel.use(byte), .r1), + } + try call.paramLiveOut(isel, dst_vi, .r0); + }, + .many => unreachable, + .slice => { + var dst_ptr_it = dst_vi.field(dst_ty, 0, 8); + const dst_ptr_vi = try dst_ptr_it.only(isel); + var dst_len_it = dst_vi.field(dst_ty, 8, 8); + const dst_len_vi = try dst_len_it.only(isel); + try isel.elemPtr(.r2, .zr, .add, ZigType.fromInterned(dst_info.child).abiSize(zcu), dst_len_vi.?); + switch (fill_byte) { + .constant => |byte| try isel.movImmediate(.w1, byte), + .value => |byte| try call.paramLiveOut(isel, try isel.use(byte), .r1), + } + try call.paramLiveOut(isel, dst_ptr_vi.?, .r0); + }, + .c => unreachable, + } + try call.finishParams(isel); + + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .memcpy, .memmove => |air_tag| { + const bin_op = air.data(air.inst_index).bin_op; + const dst_ty = isel.air.typeOf(bin_op.lhs, ip); + const dst_info = dst_ty.ptrInfo(zcu); + + try call.prepareReturn(isel); + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = @tagName(air_tag), + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + switch (dst_info.flags.size) { + .one => { + const dst_vi = try isel.use(bin_op.lhs); + const src_vi = try isel.use(bin_op.rhs); + try isel.movImmediate(.x2, ZigType.fromInterned(dst_info.child).abiSize(zcu)); + try call.paramLiveOut(isel, src_vi, .r1); + try call.paramLiveOut(isel, dst_vi, .r0); + }, + .many => unreachable, + .slice => { + const dst_vi = try isel.use(bin_op.lhs); + var dst_ptr_it = dst_vi.field(dst_ty, 0, 8); + const dst_ptr_vi = try dst_ptr_it.only(isel); + var dst_len_it = dst_vi.field(dst_ty, 8, 8); + const dst_len_vi = try dst_len_it.only(isel); + const src_vi = try isel.use(bin_op.rhs); + try isel.elemPtr(.r2, .zr, .add, ZigType.fromInterned(dst_info.child).abiSize(zcu), dst_len_vi.?); + try call.paramLiveOut(isel, src_vi, .r1); + try call.paramLiveOut(isel, dst_ptr_vi.?, .r0); + }, + .c => unreachable, + } + try call.finishParams(isel); + + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .atomic_load => { + const atomic_load = air.data(air.inst_index).atomic_load; + const ptr_ty = isel.air.typeOf(atomic_load.ptr, ip); + const ptr_info = ptr_ty.ptrInfo(zcu); + if (atomic_load.order != .unordered) return isel.fail("ordered atomic load", .{}); + if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed atomic load", .{}); + + if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| { + defer dst_vi.value.deref(isel); + var ptr_mat: ?Value.Materialize = null; + var dst_part_it = dst_vi.value.parts(isel); + while (dst_part_it.next()) |dst_part_vi| { + const dst_ra = try dst_part_vi.defReg(isel) orelse continue; + if (ptr_mat == null) { + const ptr_vi = try isel.use(atomic_load.ptr); + ptr_mat = try ptr_vi.matReg(isel); + } + try isel.emit(switch (dst_part_vi.size(isel)) { + else => |size| return isel.fail("bad atomic load size of {d} from {f}", .{ + size, isel.fmtType(ptr_ty), + }), + 1 => switch (dst_part_vi.signedness(isel)) { + .signed => .ldrsb(dst_ra.w(), .{ .unsigned_offset = .{ + .base = ptr_mat.?.ra.x(), + .offset = @intCast(dst_part_vi.get(isel).offset_from_parent), + } }), + .unsigned => .ldrb(dst_ra.w(), .{ .unsigned_offset = .{ + .base = ptr_mat.?.ra.x(), + .offset = @intCast(dst_part_vi.get(isel).offset_from_parent), + } }), + }, + 2 => switch (dst_part_vi.signedness(isel)) { + .signed => .ldrsh(dst_ra.w(), .{ .unsigned_offset = .{ + .base = ptr_mat.?.ra.x(), + .offset = @intCast(dst_part_vi.get(isel).offset_from_parent), + } }), + .unsigned => .ldrh(dst_ra.w(), .{ .unsigned_offset = .{ + .base = ptr_mat.?.ra.x(), + .offset = @intCast(dst_part_vi.get(isel).offset_from_parent), + } }), + }, + 4 => .ldr(dst_ra.w(), .{ .unsigned_offset = .{ + .base = ptr_mat.?.ra.x(), + .offset = @intCast(dst_part_vi.get(isel).offset_from_parent), + } }), + 8 => .ldr(dst_ra.x(), .{ .unsigned_offset = .{ + .base = ptr_mat.?.ra.x(), + .offset = @intCast(dst_part_vi.get(isel).offset_from_parent), + } }), + }); + } + if (ptr_mat) |mat| try mat.finish(isel); + } else if (ptr_info.flags.is_volatile) return isel.fail("volatile atomic load", .{}); + + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .aggregate_init => { + if (isel.live_values.fetchRemove(air.inst_index)) |agg_vi| { + defer agg_vi.value.deref(isel); + + const ty_pl = air.data(air.inst_index).ty_pl; + const agg_ty = ty_pl.ty.toType(); + switch (ip.indexToKey(agg_ty.toIntern())) { + .array_type => |array_type| { + const elems: []const Air.Inst.Ref = + @ptrCast(isel.air.extra.items[ty_pl.payload..][0..@intCast(array_type.len)]); + var elem_offset: u64 = 0; + const elem_size = ZigType.fromInterned(array_type.child).abiSize(zcu); + for (elems) |elem| { + var agg_part_it = agg_vi.value.field(agg_ty, elem_offset, elem_size); + const agg_part_vi = try agg_part_it.only(isel); + try agg_part_vi.?.move(isel, elem); + elem_offset += elem_size; + } + switch (array_type.sentinel) { + .none => {}, + else => |sentinel| { + var agg_part_it = agg_vi.value.field(agg_ty, elem_offset, elem_size); + const agg_part_vi = try agg_part_it.only(isel); + try agg_part_vi.?.move(isel, .fromIntern(sentinel)); + }, + } + }, + .struct_type => { + const loaded_struct = ip.loadStructType(agg_ty.toIntern()); + const elems: []const Air.Inst.Ref = + @ptrCast(isel.air.extra.items[ty_pl.payload..][0..loaded_struct.field_types.len]); + var field_offset: u64 = 0; + var field_it = loaded_struct.iterateRuntimeOrder(ip); + while (field_it.next()) |field_index| { + const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); + field_offset = field_ty.structFieldAlignment( + loaded_struct.fieldAlign(ip, field_index), + loaded_struct.layout, + zcu, + ).forward(field_offset); + const field_size = field_ty.abiSize(zcu); + if (field_size == 0) continue; + var agg_part_it = agg_vi.value.field(agg_ty, field_offset, field_size); + const agg_part_vi = try agg_part_it.only(isel); + try agg_part_vi.?.move(isel, elems[field_index]); + field_offset += field_size; + } + assert(field_offset == agg_vi.value.size(isel)); + }, + .tuple_type => |tuple_type| { + const elems: []const Air.Inst.Ref = + @ptrCast(isel.air.extra.items[ty_pl.payload..][0..tuple_type.types.len]); + var field_offset: u64 = 0; + for ( + tuple_type.types.get(ip), + tuple_type.values.get(ip), + elems, + ) |field_ty_index, field_val, elem| { + if (field_val != .none) continue; + const field_ty: ZigType = .fromInterned(field_ty_index); + field_offset = field_ty.abiAlignment(zcu).forward(field_offset); + const field_size = field_ty.abiSize(zcu); + if (field_size == 0) continue; + var agg_part_it = agg_vi.value.field(agg_ty, field_offset, field_size); + const agg_part_vi = try agg_part_it.only(isel); + try agg_part_vi.?.move(isel, elem); + field_offset += field_size; + } + assert(field_offset == agg_vi.value.size(isel)); + }, + else => return isel.fail("aggregate init {f}", .{isel.fmtType(agg_ty)}), + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .union_init => { + if (isel.live_values.fetchRemove(air.inst_index)) |un_vi| unused: { + defer un_vi.value.deref(isel); + + const ty_pl = air.data(air.inst_index).ty_pl; + const extra = isel.air.extraData(Air.UnionInit, ty_pl.payload).data; + const un_ty = ty_pl.ty.toType(); + if (un_ty.containerLayout(zcu) != .@"extern") return isel.fail("bad union init {f}", .{isel.fmtType(un_ty)}); + + try un_vi.value.defAddr(isel, un_ty, null, comptime &.initFill(.free)) orelse break :unused; + + try call.prepareReturn(isel); + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = "memcpy", + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const init_vi = try isel.use(extra.init); + try isel.movImmediate(.x2, init_vi.size(isel)); + try call.paramAddress(isel, init_vi, .r1); + try call.paramAddress(isel, un_vi.value, .r0); + try call.finishParams(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .prefetch => { + const prefetch = air.data(air.inst_index).prefetch; + if (!(prefetch.rw == .write and prefetch.cache == .instruction)) { + const maybe_slice_ty = isel.air.typeOf(prefetch.ptr, ip); + const maybe_slice_vi = try isel.use(prefetch.ptr); + const ptr_vi = if (maybe_slice_ty.isSlice(zcu)) ptr_vi: { + var ptr_part_it = maybe_slice_vi.field(maybe_slice_ty, 0, 8); + const ptr_part_vi = try ptr_part_it.only(isel); + break :ptr_vi ptr_part_vi.?; + } else maybe_slice_vi; + const ptr_mat = try ptr_vi.matReg(isel); + try isel.emit(.prfm(.{ + .policy = switch (prefetch.locality) { + 1, 2, 3 => .keep, + 0 => .strm, + }, + .target = switch (prefetch.locality) { + 0, 3 => .l1, + 2 => .l2, + 1 => .l3, + }, + .type = switch (prefetch.rw) { + .read => switch (prefetch.cache) { + .data => .pld, + .instruction => .pli, + }, + .write => switch (prefetch.cache) { + .data => .pst, + .instruction => unreachable, + }, + }, + }, .{ .base = ptr_mat.ra.x() })); + try ptr_mat.finish(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .mul_add => { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const pl_op = air.data(air.inst_index).pl_op; + const bin_op = isel.air.extraData(Air.Bin, pl_op.payload).data; + const ty = isel.air.typeOf(pl_op.operand, ip); + switch (ty.floatBits(isel.target)) { + else => unreachable, + 16, 32, 64 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const need_fcvt = switch (bits) { + else => unreachable, + 16 => !isel.target.cpu.has(.aarch64, .fullfp16), + 32, 64 => false, + }; + if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const addend_vi = try isel.use(pl_op.operand); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const addend_mat = try addend_vi.matReg(isel); + const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; + defer if (need_fcvt) isel.freeReg(lhs_ra); + const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; + defer if (need_fcvt) isel.freeReg(rhs_ra); + const addend_ra = if (need_fcvt) try isel.allocVecReg() else addend_mat.ra; + defer if (need_fcvt) isel.freeReg(addend_ra); + try isel.emit(bits: switch (bits) { + else => unreachable, + 16 => if (need_fcvt) + continue :bits 32 + else + .fmadd(res_ra.h(), lhs_ra.h(), rhs_ra.h(), addend_ra.h()), + 32 => .fmadd(res_ra.s(), lhs_ra.s(), rhs_ra.s(), addend_ra.s()), + 64 => .fmadd(res_ra.d(), lhs_ra.d(), rhs_ra.d(), addend_ra.d()), + }); + if (need_fcvt) { + try isel.emit(.fcvt(addend_ra.s(), addend_mat.ra.h())); + try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); + try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); + } + try addend_mat.finish(isel); + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 80, 128 => |bits| { + try call.prepareReturn(isel); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), + 80 => { + var res_hi16_it = res_vi.value.field(ty, 8, 8); + const res_hi16_vi = try res_hi16_it.only(isel); + try call.returnLiveIn(isel, res_hi16_vi.?, .r1); + var res_lo64_it = res_vi.value.field(ty, 0, 8); + const res_lo64_vi = try res_lo64_it.only(isel); + try call.returnLiveIn(isel, res_lo64_vi.?, .r0); + }, + } + try call.finishReturn(isel); + + try call.prepareCallee(isel); + try isel.global_relocs.append(gpa, .{ + .global = switch (bits) { + else => unreachable, + 16 => "__fmah", + 32 => "fmaf", + 64 => "fma", + 80 => "__fmax", + 128 => "fmaq", + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); + try call.finishCallee(isel); + + try call.prepareParams(isel); + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const addend_vi = try isel.use(pl_op.operand); + switch (bits) { + else => unreachable, + 16, 32, 64, 128 => { + try call.paramLiveOut(isel, addend_vi, .v2); + try call.paramLiveOut(isel, rhs_vi, .v1); + try call.paramLiveOut(isel, lhs_vi, .v0); + }, + 80 => { + var addend_hi16_it = addend_vi.field(ty, 8, 8); + const addend_hi16_vi = try addend_hi16_it.only(isel); + try call.paramLiveOut(isel, addend_hi16_vi.?, .r5); + var addend_lo64_it = addend_vi.field(ty, 0, 8); + const addend_lo64_vi = try addend_lo64_it.only(isel); + try call.paramLiveOut(isel, addend_lo64_vi.?, .r4); + var rhs_hi16_it = rhs_vi.field(ty, 8, 8); + const rhs_hi16_vi = try rhs_hi16_it.only(isel); + try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); + var rhs_lo64_it = rhs_vi.field(ty, 0, 8); + const rhs_lo64_vi = try rhs_lo64_it.only(isel); + try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); + var lhs_hi16_it = lhs_vi.field(ty, 8, 8); + const lhs_hi16_vi = try lhs_hi16_it.only(isel); + try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); + var lhs_lo64_it = lhs_vi.field(ty, 0, 8); + const lhs_lo64_vi = try lhs_lo64_it.only(isel); + try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); + }, + } + try call.finishParams(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .field_parent_ptr => { + if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { + defer dst_vi.value.deref(isel); + const ty_pl = air.data(air.inst_index).ty_pl; + const extra = isel.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; + switch (codegen.fieldOffset( + ty_pl.ty.toType(), + isel.air.typeOf(extra.field_ptr, ip), + extra.field_index, + zcu, + )) { + 0 => try dst_vi.value.move(isel, extra.field_ptr), + else => |field_offset| { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(extra.field_ptr); + const src_mat = try src_vi.matReg(isel); + const lo12: u12 = @truncate(field_offset >> 0); + const hi12: u12 = @intCast(field_offset >> 12); + if (hi12 > 0) try isel.emit(.sub( + dst_ra.x(), + if (lo12 > 0) dst_ra.x() else src_mat.ra.x(), + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + )); + if (lo12 > 0) try isel.emit(.sub(dst_ra.x(), src_mat.ra.x(), .{ .immediate = lo12 })); + try src_mat.finish(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .runtime_nav_ptr => { + if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: { + defer ptr_vi.value.deref(isel); + const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused; + + const ty_nav = air.data(air.inst_index).ty_nav; + if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) { + false => { + try isel.nav_relocs.append(zcu.gpa, .{ + .nav = ty_nav.nav, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.adr(ptr_ra.x(), 0)); + }, + true => { + try isel.nav_relocs.append(zcu.gpa, .{ + .nav = ty_nav.nav, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 })); + try isel.nav_relocs.append(zcu.gpa, .{ + .nav = ty_nav.nav, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.adrp(ptr_ra.x(), 0)); + }, + } else try isel.movImmediate(ptr_ra.x(), isel.pt.navAlignment(ty_nav.nav).forward(0xaaaaaaaaaaaaaaaa)); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .add_safe, + .sub_safe, + .mul_safe, + .inferred_alloc, + .inferred_alloc_comptime, + .int_from_float_safe, + .int_from_float_optimized_safe, + .wasm_memory_size, + .wasm_memory_grow, + .work_item_id, + .work_group_size, + .work_group_id, + => unreachable, + } + assert(air.body_index == 0); +} + +pub fn verify(isel: *Select, check_values: bool) void { + if (!std.debug.runtime_safety) return; + assert(isel.blocks.count() == 1 and isel.blocks.keys()[0] == Select.Block.main); + assert(isel.active_loops.items.len == 0); + assert(isel.dom_start == 0 and isel.dom_len == 0); + var live_reg_it = isel.live_registers.iterator(); + while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) { + _ => { + isel.dumpValues(.all); + unreachable; + }, + .allocating, .free => {}, + }; + if (check_values) for (isel.values.items) |value| if (value.refs != 0) { + isel.dumpValues(.only_referenced); + unreachable; + }; +} + +/// Stack Frame Layout +/// +-+-----------------------------------+ +/// |R| allocated stack | +/// +-+-----------------------------------+ +/// |S| caller frame record | +---------------+ +/// +-+-----------------------------------+ <-| entry/exit FP | +/// |R| caller frame | +---------------+ +/// +-+-----------------------------------+ +/// |R| variable incoming stack arguments | +---------------+ +/// +-+-----------------------------------+ <-| __stack | +/// |S| named incoming stack arguments | +---------------+ +/// +-+-----------------------------------+ <-| entry/exit SP | +/// |S| incoming gr arguments | | __gr_top | +/// +-+-----------------------------------+ +---------------+ +/// |S| alignment gap | +/// +-+-----------------------------------+ +/// |S| frame record | +----------+ +/// +-+-----------------------------------+ <-| FP | +/// |S| incoming vr arguments | | __vr_top | +/// +-+-----------------------------------+ +----------+ +/// |L| alignment gap | +/// +-+-----------------------------------+ +/// |L| callee saved vr area | +/// +-+-----------------------------------+ +/// |L| callee saved gr area | +----------------------+ +/// +-+-----------------------------------+ <-| prologue/epilogue SP | +/// |R| realignment gap | +----------------------+ +/// +-+-----------------------------------+ +/// |L| locals | +/// +-+-----------------------------------+ +/// |S| outgoing stack arguments | +----+ +/// +-+-----------------------------------+ <-| SP | +/// |R| unallocated stack | +----+ +/// +-+-----------------------------------+ +/// [S] Size computed by `analyze`, can be used by the body. +/// [L] Size computed by `layout`, can be used by the prologue/epilogue. +/// [R] Size unknown until runtime, can vary from one call to the next. +/// +/// Constraints that led to this layout: +/// * FP to __stack/__gr_top/__vr_top must only pass through [S] +/// * SP to outgoing stack arguments/locals must only pass through [S] +/// * entry/exit SP to prologue/epilogue SP must only pass through [S/L] +/// * all save areas must be at a positive offset from prologue/epilogue SP +/// * the entry/exit SP to prologue/epilogue SP distance must +/// - be a multiple of 16 due to hardware restrictions on the value of SP +/// - conform to the limit from the first matching condition in the +/// following list due to instruction encoding limitations +/// 1. callee saved gr count >= 2: multiple of 8 of at most 504 bytes +/// 2. callee saved vr count >= 2: multiple of 8 of at most 504 bytes +/// 3. callee saved gr count >= 1: at most 255 bytes +/// 4. callee saved vr count >= 1: at most 255 bytes +/// 5. variable incoming vr argument count >= 2: multiple of 16 of at most 1008 bytes +/// 6. variable incoming vr argument count >= 1: at most 255 bytes +/// 7. have frame record: multiple of 8 of at most 504 bytes +pub fn layout( + isel: *Select, + incoming: CallAbiIterator, + have_va: bool, + saved_gra_len: u7, + saved_vra_len: u7, + mod: *const Package.Module, +) !usize { + const zcu = isel.pt.zcu; + const ip = &zcu.intern_pool; + const nav = ip.getNav(isel.nav_index); + wip_mir_log.debug("{f}:\n", .{nav.fqn.fmt(ip)}); + + const stack_size: u24 = @intCast(InternPool.Alignment.@"16".forward(isel.stack_size)); + const stack_size_low: u12 = @truncate(stack_size >> 0); + const stack_size_high: u12 = @truncate(stack_size >> 12); + + var saves_buf: [10 + 8 + 8 + 2 + 8]struct { + class: enum { integer, vector }, + needs_restore: bool, + register: Register, + offset: u10, + size: u5, + } = undefined; + const saves, const saves_size, const frame_record_offset = saves: { + var saves_len: usize = 0; + var saves_size: u10 = 0; + var save_ra: Register.Alias = undefined; + + // callee saved gr area + save_ra = .r19; + while (save_ra != .r29) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { + if (!isel.saved_registers.contains(save_ra)) continue; + saves_size = std.mem.alignForward(u10, saves_size, 8); + saves_buf[saves_len] = .{ + .class = .integer, + .needs_restore = true, + .register = save_ra.x(), + .offset = saves_size, + .size = 8, + }; + saves_len += 1; + saves_size += 8; + } + var deferred_gr = if (saves_size == 8 or (saves_size % 16 != 0 and saved_gra_len % 2 != 0)) gr: { + saves_len -= 1; + saves_size -= 8; + break :gr saves_buf[saves_len].register; + } else null; + defer assert(deferred_gr == null); + + // callee saved vr area + save_ra = .v8; + while (save_ra != .v16) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { + if (!isel.saved_registers.contains(save_ra)) continue; + saves_size = std.mem.alignForward(u10, saves_size, 8); + saves_buf[saves_len] = .{ + .class = .vector, + .needs_restore = true, + .register = save_ra.d(), + .offset = saves_size, + .size = 8, + }; + saves_len += 1; + saves_size += 8; + } + if (deferred_gr != null and saved_gra_len % 2 == 0) { + saves_size = std.mem.alignForward(u10, saves_size, 8); + saves_buf[saves_len] = .{ + .class = .integer, + .needs_restore = true, + .register = deferred_gr.?, + .offset = saves_size, + .size = 8, + }; + saves_len += 1; + saves_size += 8; + deferred_gr = null; + } + if (saves_size % 16 != 0 and saved_vra_len % 2 != 0) { + const prev_save = &saves_buf[saves_len - 1]; + switch (prev_save.class) { + .integer => {}, + .vector => { + prev_save.register = prev_save.register.alias.q(); + prev_save.size = 16; + saves_size += 8; + }, + } + } + + // incoming vr arguments + save_ra = if (mod.strip) incoming.nsrn else CallAbiIterator.nsrn_start; + while (save_ra != if (have_va) CallAbiIterator.nsrn_end else incoming.nsrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { + saves_size = std.mem.alignForward(u10, saves_size, 16); + saves_buf[saves_len] = .{ + .class = .vector, + .needs_restore = false, + .register = save_ra.q(), + .offset = saves_size, + .size = 16, + }; + saves_len += 1; + saves_size += 16; + } + + // frame record + saves_size = std.mem.alignForward(u10, saves_size, 16); + const frame_record_offset = saves_size; + saves_buf[saves_len] = .{ + .class = .integer, + .needs_restore = true, + .register = .fp, + .offset = saves_size, + .size = 8, + }; + saves_len += 1; + saves_size += 8; + + saves_size = std.mem.alignForward(u10, saves_size, 8); + saves_buf[saves_len] = .{ + .class = .integer, + .needs_restore = true, + .register = .lr, + .offset = saves_size, + .size = 8, + }; + saves_len += 1; + saves_size += 8; + + // incoming gr arguments + if (deferred_gr) |gr| { + saves_size = std.mem.alignForward(u10, saves_size, 8); + saves_buf[saves_len] = .{ + .class = .integer, + .needs_restore = true, + .register = gr, + .offset = saves_size, + .size = 8, + }; + saves_len += 1; + saves_size += 8; + deferred_gr = null; + } + save_ra = if (mod.strip) incoming.ngrn else CallAbiIterator.ngrn_start; + while (save_ra != if (have_va) CallAbiIterator.ngrn_end else incoming.ngrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { + saves_size = std.mem.alignForward(u10, saves_size, 8); + saves_buf[saves_len] = .{ + .class = .integer, + .needs_restore = false, + .register = save_ra.x(), + .offset = saves_size, + .size = 8, + }; + saves_len += 1; + saves_size += 8; + } + + assert(InternPool.Alignment.@"16".check(saves_size)); + break :saves .{ saves_buf[0..saves_len], saves_size, frame_record_offset }; + }; + + { + wip_mir_log.debug("{f}:", .{nav.fqn.fmt(ip)}); + var save_index: usize = 0; + while (save_index < saves.len) { + if (save_index + 2 <= saves.len and saves[save_index + 0].class == saves[save_index + 1].class and + saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset) + { + try isel.emit(.stp( + saves[save_index + 0].register, + saves[save_index + 1].register, + switch (saves[save_index + 0].offset) { + 0 => .{ .pre_index = .{ + .base = .sp, + .index = @intCast(-@as(i11, saves_size)), + } }, + else => |offset| .{ .signed_offset = .{ + .base = .sp, + .offset = @intCast(offset), + } }, + }, + )); + save_index += 2; + } else { + try isel.emit(.str( + saves[save_index].register, + switch (saves[save_index].offset) { + 0 => .{ .pre_index = .{ + .base = .sp, + .index = @intCast(-@as(i11, saves_size)), + } }, + else => |offset| .{ .unsigned_offset = .{ + .base = .sp, + .offset = @intCast(offset), + } }, + }, + )); + save_index += 1; + } + } + + const scratch_reg: Register = if (isel.stack_align == .@"16") + .sp + else if (stack_size == 0) + .fp + else + .x9; + try isel.emit(.add(.fp, .sp, .{ .immediate = frame_record_offset })); + if (stack_size_high > 0) try isel.emit(.sub(scratch_reg, .sp, .{ + .shifted_immediate = .{ .immediate = stack_size_high, .lsl = .@"12" }, + })); + if (stack_size_low > 0) try isel.emit(.sub( + scratch_reg, + if (stack_size_high > 0) scratch_reg else .sp, + .{ .immediate = stack_size_low }, + )); + if (isel.stack_align != .@"16") { + try isel.emit(.@"and"(.sp, scratch_reg, .{ .immediate = .{ + .N = .doubleword, + .immr = -%isel.stack_align.toLog2Units(), + .imms = ~isel.stack_align.toLog2Units(), + } })); + } + wip_mir_log.debug("", .{}); + } + + const epilogue = isel.instructions.items.len; + if (isel.returns) { + try isel.emit(.ret(.lr)); + var save_index: usize = 0; + while (save_index < saves.len) { + if (save_index + 2 <= saves.len and saves[save_index + 1].needs_restore and + saves[save_index + 0].class == saves[save_index + 1].class and + saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset) + { + try isel.emit(.ldp( + saves[save_index + 0].register, + saves[save_index + 1].register, + switch (saves[save_index + 0].offset) { + 0 => .{ .post_index = .{ + .base = .sp, + .index = @intCast(saves_size), + } }, + else => |offset| .{ .signed_offset = .{ + .base = .sp, + .offset = @intCast(offset), + } }, + }, + )); + save_index += 2; + } else if (saves[save_index].needs_restore) { + try isel.emit(.ldr( + saves[save_index].register, + switch (saves[save_index].offset) { + 0 => .{ .post_index = .{ + .base = .sp, + .index = @intCast(saves_size), + } }, + else => |offset| .{ .unsigned_offset = .{ + .base = .sp, + .offset = @intCast(offset), + } }, + }, + )); + save_index += 1; + } else save_index += 1; + } + if (isel.stack_align != .@"16" or (stack_size_low > 0 and stack_size_high > 0)) { + try isel.emit(switch (frame_record_offset) { + 0 => .add(.sp, .fp, .{ .immediate = 0 }), + else => |offset| .sub(.sp, .fp, .{ .immediate = offset }), + }); + } else { + if (stack_size_high > 0) try isel.emit(.add(.sp, .sp, .{ + .shifted_immediate = .{ .immediate = stack_size_high, .lsl = .@"12" }, + })); + if (stack_size_low > 0) try isel.emit(.add(.sp, .sp, .{ + .immediate = stack_size_low, + })); + } + wip_mir_log.debug("{f}:\n", .{nav.fqn.fmt(ip)}); + } + return epilogue; +} + +fn fmtDom(isel: *Select, inst: Air.Inst.Index, start: u32, len: u32) struct { + isel: *Select, + inst: Air.Inst.Index, + start: u32, + len: u32, + pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { + try writer.print("%{d} -> {{", .{@intFromEnum(data.inst)}); + var first = true; + for (data.isel.blocks.keys()[0..data.len], 0..) |block_inst_index, dom_index| { + if (@as(u1, @truncate(data.isel.dom.items[ + data.start + dom_index / @bitSizeOf(DomInt) + ] >> @truncate(dom_index))) == 0) continue; + if (first) { + first = false; + } else { + try writer.writeByte(','); + } + switch (block_inst_index) { + Block.main => try writer.writeAll(" %main"), + else => try writer.print(" %{d}", .{@intFromEnum(block_inst_index)}), + } + } + if (!first) try writer.writeByte(' '); + try writer.writeByte('}'); + } +} { + return .{ .isel = isel, .inst = inst, .start = start, .len = len }; +} + +fn fmtLoopLive(isel: *Select, loop_inst: Air.Inst.Index) struct { + isel: *Select, + inst: Air.Inst.Index, + pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { + const loops = data.isel.loops.values(); + const loop_index = data.isel.loops.getIndex(data.inst).?; + const live_insts = + data.isel.loop_live.list.items[loops[loop_index].live..loops[loop_index + 1].live]; + + try writer.print("%{d} <- {{", .{@intFromEnum(data.inst)}); + var first = true; + for (live_insts) |live_inst| { + if (first) { + first = false; + } else { + try writer.writeByte(','); + } + try writer.print(" %{d}", .{@intFromEnum(live_inst)}); + } + if (!first) try writer.writeByte(' '); + try writer.writeByte('}'); + } +} { + return .{ .isel = isel, .inst = loop_inst }; +} + +fn fmtType(isel: *Select, ty: ZigType) ZigType.Formatter { + return ty.fmt(isel.pt); +} + +fn fmtConstant(isel: *Select, constant: Constant) @typeInfo(@TypeOf(Constant.fmtValue)).@"fn".return_type.? { + return constant.fmtValue(isel.pt); +} + +fn emit(isel: *Select, instruction: codegen.aarch64.encoding.Instruction) !void { + wip_mir_log.debug(" | {f}", .{instruction}); + try isel.instructions.append(isel.pt.zcu.gpa, instruction); +} + +fn emitLiteral(isel: *Select, bytes: []const u8) !void { + const words: []align(1) const u32 = @ptrCast(bytes); + const literals = try isel.literals.addManyAsSlice(isel.pt.zcu.gpa, words.len); + switch (isel.target.cpu.arch.endian()) { + .little => @memcpy(literals, words), + .big => for (words, 0..) |word, word_index| { + literals[literals.len - 1 - word_index] = @byteSwap(word); + }, + } +} + +fn fail(isel: *Select, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { + @branchHint(.cold); + return isel.pt.zcu.codegenFail(isel.nav_index, format, args); +} + +/// dst = src +fn movImmediate(isel: *Select, dst_reg: Register, src_imm: u64) !void { + const sf = dst_reg.format.integer; + if (src_imm == 0) { + const zr: Register = switch (sf) { + .word => .wzr, + .doubleword => .xzr, + }; + return isel.emit(.orr(dst_reg, zr, .{ .register = zr })); + } + + const Part = u16; + const min_part: Part = std.math.minInt(Part); + const max_part: Part = std.math.maxInt(Part); + + const parts: [4]Part = @bitCast(switch (sf) { + .word => @as(u32, @intCast(src_imm)), + .doubleword => @as(u64, @intCast(src_imm)), + }); + const width: u7 = switch (sf) { + .word => 32, + .doubleword => 64, + }; + const parts_len: u3 = @intCast(@divExact(width, @bitSizeOf(Part))); + var equal_min_count: u3 = 0; + var equal_max_count: u3 = 0; + for (parts[0..parts_len]) |part| { + equal_min_count += @intFromBool(part == min_part); + equal_max_count += @intFromBool(part == max_part); + } + + const equal_fill_count, const fill_part: Part = if (equal_min_count >= equal_max_count) + .{ equal_min_count, min_part } + else + .{ equal_max_count, max_part }; + var remaining_parts = @max(parts_len - equal_fill_count, 1); + + if (remaining_parts > 1) { + var elem_width: u8 = 2; + while (elem_width <= width) : (elem_width <<= 1) { + const emask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - elem_width); + const rmask = @divExact(@as(u64, switch (sf) { + .word => std.math.maxInt(u32), + .doubleword => std.math.maxInt(u64), + }), emask); + const elem = src_imm & emask; + if (src_imm != elem * rmask) continue; + const imask: u64 = @bitCast(@as(i64, @bitCast(elem << 63)) >> 63); + const lsb0 = elem ^ (imask & emask); + const lsb1 = (lsb0 - 1) | lsb0; + if ((lsb1 +% 1) & lsb1 == 0) { + const lo: u6 = @intCast(@ctz(lsb0)); + const hi: u6 = @intCast(@clz(lsb0) - (64 - elem_width)); + const mid: u6 = @intCast(elem_width - lo - hi); + const smask: u6 = @truncate(imask); + const mid_masked = mid & ~smask; + return isel.emit(.orr( + dst_reg, + switch (sf) { + .word => .wzr, + .doubleword => .xzr, + }, + .{ .immediate = .{ + .N = @enumFromInt(elem_width >> 6), + .immr = hi + mid_masked, + .imms = ((((lo + hi) & smask) | mid_masked) - 1) | -%@as(u6, @truncate(elem_width)) << 1, + } }, + )); + } + } + } + + var part_index = parts_len; + while (part_index > 0) { + part_index -= 1; + if (part_index >= remaining_parts and parts[part_index] == fill_part) continue; + remaining_parts -= 1; + try isel.emit(if (remaining_parts > 0) .movk( + dst_reg, + parts[part_index], + .{ .lsl = @enumFromInt(part_index) }, + ) else switch (fill_part) { + else => unreachable, + min_part => .movz( + dst_reg, + parts[part_index], + .{ .lsl = @enumFromInt(part_index) }, + ), + max_part => .movn( + dst_reg, + ~parts[part_index], + .{ .lsl = @enumFromInt(part_index) }, + ), + }); + } + assert(remaining_parts == 0); +} + +/// elem_ptr = base +- elem_size * index +/// elem_ptr, base, and index may alias +fn elemPtr( + isel: *Select, + elem_ptr_ra: Register.Alias, + base_ra: Register.Alias, + op: codegen.aarch64.encoding.Instruction.AddSubtractOp, + elem_size: u64, + index_vi: Value.Index, +) !void { + const index_mat = try index_vi.matReg(isel); + switch (@popCount(elem_size)) { + 0 => unreachable, + 1 => try isel.emit(switch (op) { + .add => switch (base_ra) { + else => .add(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{ + .register = index_mat.ra.x(), + .shift = .{ .lsl = @intCast(@ctz(elem_size)) }, + } }), + .zr => switch (@ctz(elem_size)) { + 0 => .orr(elem_ptr_ra.x(), .xzr, .{ .register = index_mat.ra.x() }), + else => |shift| .ubfm(elem_ptr_ra.x(), index_mat.ra.x(), .{ + .N = .doubleword, + .immr = @intCast(64 - shift), + .imms = @intCast(63 - shift), + }), + }, + }, + .sub => .sub(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{ + .register = index_mat.ra.x(), + .shift = .{ .lsl = @intCast(@ctz(elem_size)) }, + } }), + }), + 2 => { + const shift: u6 = @intCast(@ctz(elem_size)); + const temp_ra = temp_ra: switch (op) { + .add => switch (base_ra) { + else => { + const temp_ra = try isel.allocIntReg(); + errdefer isel.freeReg(temp_ra); + try isel.emit(.add(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{ + .register = temp_ra.x(), + .shift = .{ .lsl = shift }, + } })); + break :temp_ra temp_ra; + }, + .zr => { + if (shift > 0) try isel.emit(.ubfm(elem_ptr_ra.x(), elem_ptr_ra.x(), .{ + .N = .doubleword, + .immr = -%shift, + .imms = ~shift, + })); + break :temp_ra elem_ptr_ra; + }, + }, + .sub => { + const temp_ra = try isel.allocIntReg(); + errdefer isel.freeReg(temp_ra); + try isel.emit(.sub(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{ + .register = temp_ra.x(), + .shift = .{ .lsl = shift }, + } })); + break :temp_ra temp_ra; + }, + }; + defer if (temp_ra != elem_ptr_ra) isel.freeReg(temp_ra); + try isel.emit(.add(temp_ra.x(), index_mat.ra.x(), .{ .shifted_register = .{ + .register = index_mat.ra.x(), + .shift = .{ .lsl = @intCast(63 - @clz(elem_size) - shift) }, + } })); + }, + else => { + const elem_size_lsb1 = (elem_size - 1) | elem_size; + if ((elem_size_lsb1 +% 1) & elem_size_lsb1 == 0) { + const shift: u6 = @intCast(@ctz(elem_size)); + const temp_ra = temp_ra: switch (op) { + .add => { + const temp_ra = try isel.allocIntReg(); + errdefer isel.freeReg(temp_ra); + try isel.emit(.sub(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{ + .register = temp_ra.x(), + .shift = .{ .lsl = shift }, + } })); + break :temp_ra temp_ra; + }, + .sub => switch (base_ra) { + else => { + const temp_ra = try isel.allocIntReg(); + errdefer isel.freeReg(temp_ra); + try isel.emit(.add(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{ + .register = temp_ra.x(), + .shift = .{ .lsl = shift }, + } })); + break :temp_ra temp_ra; + }, + .zr => { + if (shift > 0) try isel.emit(.ubfm(elem_ptr_ra.x(), elem_ptr_ra.x(), .{ + .N = .doubleword, + .immr = -%shift, + .imms = ~shift, + })); + break :temp_ra elem_ptr_ra; + }, + }, + }; + defer if (temp_ra != elem_ptr_ra) isel.freeReg(temp_ra); + try isel.emit(.sub(temp_ra.x(), index_mat.ra.x(), .{ .shifted_register = .{ + .register = index_mat.ra.x(), + .shift = .{ .lsl = @intCast(64 - @clz(elem_size) - shift) }, + } })); + } else { + try isel.emit(switch (op) { + .add => .madd(elem_ptr_ra.x(), index_mat.ra.x(), elem_ptr_ra.x(), base_ra.x()), + .sub => .msub(elem_ptr_ra.x(), index_mat.ra.x(), elem_ptr_ra.x(), base_ra.x()), + }); + try isel.movImmediate(elem_ptr_ra.x(), elem_size); + } + }, + } + try index_mat.finish(isel); +} + +fn clzLimb( + isel: *Select, + res_ra: Register.Alias, + src_int_info: std.builtin.Type.Int, + src_ra: Register.Alias, +) !void { + switch (src_int_info.bits) { + else => unreachable, + 1...31 => |bits| { + try isel.emit(.sub(res_ra.w(), res_ra.w(), .{ + .immediate = @intCast(32 - bits), + })); + switch (src_int_info.signedness) { + .signed => { + try isel.emit(.clz(res_ra.w(), res_ra.w())); + try isel.emit(.ubfm(res_ra.w(), src_ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(bits - 1), + })); + }, + .unsigned => try isel.emit(.clz(res_ra.w(), src_ra.w())), + } + }, + 32 => try isel.emit(.clz(res_ra.w(), src_ra.w())), + 33...63 => |bits| { + try isel.emit(.sub(res_ra.w(), res_ra.w(), .{ + .immediate = @intCast(64 - bits), + })); + switch (src_int_info.signedness) { + .signed => { + try isel.emit(.clz(res_ra.x(), res_ra.x())); + try isel.emit(.ubfm(res_ra.x(), src_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + })); + }, + .unsigned => try isel.emit(.clz(res_ra.x(), src_ra.x())), + } + }, + 64 => try isel.emit(.clz(res_ra.x(), src_ra.x())), + } +} + +fn ctzLimb( + isel: *Select, + res_ra: Register.Alias, + src_int_info: std.builtin.Type.Int, + src_ra: Register.Alias, +) !void { + switch (src_int_info.bits) { + else => unreachable, + 1...31 => |bits| { + try isel.emit(.clz(res_ra.w(), res_ra.w())); + try isel.emit(.rbit(res_ra.w(), res_ra.w())); + try isel.emit(.orr(res_ra.w(), src_ra.w(), .{ .immediate = .{ + .N = .word, + .immr = @intCast(32 - bits), + .imms = @intCast(32 - bits - 1), + } })); + }, + 32 => { + try isel.emit(.clz(res_ra.w(), res_ra.w())); + try isel.emit(.rbit(res_ra.w(), src_ra.w())); + }, + 33...63 => |bits| { + try isel.emit(.clz(res_ra.x(), res_ra.x())); + try isel.emit(.rbit(res_ra.x(), res_ra.x())); + try isel.emit(.orr(res_ra.x(), src_ra.x(), .{ .immediate = .{ + .N = .doubleword, + .immr = @intCast(64 - bits), + .imms = @intCast(64 - bits - 1), + } })); + }, + 64 => { + try isel.emit(.clz(res_ra.x(), res_ra.x())); + try isel.emit(.rbit(res_ra.x(), src_ra.x())); + }, + } +} + +fn storeReg( + isel: *Select, + ra: Register.Alias, + size: u64, + base_ra: Register.Alias, + offset: i65, +) !void { + switch (size) { + 0 => unreachable, + 1 => { + if (std.math.cast(u12, offset)) |unsigned_offset| return isel.emit(if (ra.isVector()) .str( + ra.b(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + ) else .strb( + ra.w(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + )); + if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector()) + .stur(ra.b(), base_ra.x(), signed_offset) + else + .sturb(ra.w(), base_ra.x(), signed_offset)); + }, + 2 => { + if (std.math.cast(u13, offset)) |unsigned_offset| if (unsigned_offset % 2 == 0) + return isel.emit(if (ra.isVector()) .str( + ra.h(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + ) else .strh( + ra.w(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + )); + if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector()) + .stur(ra.h(), base_ra.x(), signed_offset) + else + .sturh(ra.w(), base_ra.x(), signed_offset)); + }, + 3 => { + const hi8_ra = try isel.allocIntReg(); + defer isel.freeReg(hi8_ra); + try isel.storeReg(hi8_ra, 1, base_ra, offset + 2); + try isel.storeReg(ra, 2, base_ra, offset); + return isel.emit(.ubfm(hi8_ra.w(), ra.w(), .{ + .N = .word, + .immr = 16, + .imms = 16 + 8 - 1, + })); + }, + 4 => { + if (std.math.cast(u14, offset)) |unsigned_offset| if (unsigned_offset % 4 == 0) return isel.emit(.str( + if (ra.isVector()) ra.s() else ra.w(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + )); + if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.stur( + if (ra.isVector()) ra.s() else ra.w(), + base_ra.x(), + signed_offset, + )); + }, + 5 => { + const hi8_ra = try isel.allocIntReg(); + defer isel.freeReg(hi8_ra); + try isel.storeReg(hi8_ra, 1, base_ra, offset + 4); + try isel.storeReg(ra, 4, base_ra, offset); + return isel.emit(.ubfm(hi8_ra.x(), ra.x(), .{ + .N = .doubleword, + .immr = 32, + .imms = 32 + 8 - 1, + })); + }, + 6 => { + const hi16_ra = try isel.allocIntReg(); + defer isel.freeReg(hi16_ra); + try isel.storeReg(hi16_ra, 2, base_ra, offset + 4); + try isel.storeReg(ra, 4, base_ra, offset); + return isel.emit(.ubfm(hi16_ra.x(), ra.x(), .{ + .N = .doubleword, + .immr = 32, + .imms = 32 + 16 - 1, + })); + }, + 7 => { + const hi16_ra = try isel.allocIntReg(); + defer isel.freeReg(hi16_ra); + const hi8_ra = try isel.allocIntReg(); + defer isel.freeReg(hi8_ra); + try isel.storeReg(hi8_ra, 1, base_ra, offset + 6); + try isel.storeReg(hi16_ra, 2, base_ra, offset + 4); + try isel.storeReg(ra, 4, base_ra, offset); + try isel.emit(.ubfm(hi8_ra.x(), ra.x(), .{ + .N = .doubleword, + .immr = 32 + 16, + .imms = 32 + 16 + 8 - 1, + })); + return isel.emit(.ubfm(hi16_ra.x(), ra.x(), .{ + .N = .doubleword, + .immr = 32, + .imms = 32 + 16 - 1, + })); + }, + 8 => { + if (std.math.cast(u15, offset)) |unsigned_offset| if (unsigned_offset % 8 == 0) return isel.emit(.str( + if (ra.isVector()) ra.d() else ra.x(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + )); + if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.stur( + if (ra.isVector()) ra.d() else ra.x(), + base_ra.x(), + signed_offset, + )); + }, + 16 => { + if (std.math.cast(u16, offset)) |unsigned_offset| if (unsigned_offset % 16 == 0) return isel.emit(.str( + ra.q(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + )); + if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.stur(ra.q(), base_ra.x(), signed_offset)); + }, + else => return isel.fail("bad store size: {d}", .{size}), + } + const ptr_ra = try isel.allocIntReg(); + defer isel.freeReg(ptr_ra); + try isel.storeReg(ra, size, ptr_ra, 0); + if (std.math.cast(u24, offset)) |pos_offset| { + const lo12: u12 = @truncate(pos_offset >> 0); + const hi12: u12 = @intCast(pos_offset >> 12); + if (hi12 > 0) try isel.emit(.add( + ptr_ra.x(), + if (lo12 > 0) ptr_ra.x() else base_ra.x(), + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + )); + if (lo12 > 0 or hi12 == 0) try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 })); + } else if (std.math.cast(u24, -offset)) |neg_offset| { + const lo12: u12 = @truncate(neg_offset >> 0); + const hi12: u12 = @intCast(neg_offset >> 12); + if (hi12 > 0) try isel.emit(.sub( + ptr_ra.x(), + if (lo12 > 0) ptr_ra.x() else base_ra.x(), + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + )); + if (lo12 > 0 or hi12 == 0) try isel.emit(.sub(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 })); + } else { + try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .register = ptr_ra.x() })); + try isel.movImmediate(ptr_ra.x(), @truncate(@as(u65, @bitCast(offset)))); + } +} + +const DomInt = u8; + +pub const Value = struct { + refs: u32, + flags: Flags, + offset_from_parent: u64, + parent_payload: Parent.Payload, + location_payload: Location.Payload, + parts: Value.Index, + + /// Must be at least 16 to compute call abi. + /// Must be at least 16, the largest hardware alignment. + pub const max_parts = 16; + pub const PartsLen = std.math.IntFittingRange(0, Value.max_parts); + + comptime { + if (!std.debug.runtime_safety) assert(@sizeOf(Value) == 32); + } + + pub const Flags = packed struct(u32) { + alignment: InternPool.Alignment, + parent_tag: Parent.Tag, + location_tag: Location.Tag, + parts_len_minus_one: std.math.IntFittingRange(0, Value.max_parts - 1), + unused: u18 = 0, + }; + + pub const Parent = union(enum(u3)) { + unallocated: void, + stack_slot: Indirect, + address: Value.Index, + value: Value.Index, + constant: Constant, + + pub const Tag = @typeInfo(Parent).@"union".tag_type.?; + pub const Payload = @Type(.{ .@"union" = .{ + .layout = .auto, + .tag_type = null, + .fields = @typeInfo(Parent).@"union".fields, + .decls = &.{}, + } }); + }; + + pub const Location = union(enum(u1)) { + large: struct { + size: u64, + }, + small: struct { + size: u5, + signedness: std.builtin.Signedness, + is_vector: bool, + hint: Register.Alias, + register: Register.Alias, + }, + + pub const Tag = @typeInfo(Location).@"union".tag_type.?; + pub const Payload = @Type(.{ .@"union" = .{ + .layout = .auto, + .tag_type = null, + .fields = @typeInfo(Location).@"union".fields, + .decls = &.{}, + } }); + }; + + pub const Indirect = packed struct(u32) { + base: Register.Alias, + offset: i25, + + pub fn withOffset(ind: Indirect, offset: i25) Indirect { + return .{ + .base = ind.base, + .offset = ind.offset + offset, + }; + } + }; + + pub const Index = enum(u32) { + allocating = std.math.maxInt(u32) - 1, + free = std.math.maxInt(u32) - 0, + _, + + fn get(vi: Value.Index, isel: *Select) *Value { + return &isel.values.items[@intFromEnum(vi)]; + } + + fn setAlignment(vi: Value.Index, isel: *Select, new_alignment: InternPool.Alignment) void { + vi.get(isel).flags.alignment = new_alignment; + } + + pub fn alignment(vi: Value.Index, isel: *Select) InternPool.Alignment { + return vi.get(isel).flags.alignment; + } + + pub fn setParent(vi: Value.Index, isel: *Select, new_parent: Parent) void { + const value = vi.get(isel); + assert(value.flags.parent_tag == .unallocated); + value.flags.parent_tag = new_parent; + value.parent_payload = switch (new_parent) { + .unallocated => unreachable, + inline else => |payload, tag| @unionInit(Parent.Payload, @tagName(tag), payload), + }; + if (value.refs > 0) switch (new_parent) { + .unallocated => unreachable, + .stack_slot, .constant => {}, + .address, .value => |parent_vi| _ = parent_vi.ref(isel), + }; + } + + pub fn parent(vi: Value.Index, isel: *Select) Parent { + const value = vi.get(isel); + return switch (value.flags.parent_tag) { + inline else => |tag| @unionInit( + Parent, + @tagName(tag), + @field(value.parent_payload, @tagName(tag)), + ), + }; + } + + pub fn valueParent(initial_vi: Value.Index, isel: *Select) struct { u64, Value.Index } { + var offset: u64 = 0; + var vi = initial_vi; + parent: switch (vi.parent(isel)) { + else => return .{ offset, vi }, + .value => |parent_vi| { + offset += vi.position(isel)[0]; + vi = parent_vi; + continue :parent parent_vi.parent(isel); + }, + } + } + + pub fn location(vi: Value.Index, isel: *Select) Location { + const value = vi.get(isel); + return switch (value.flags.location_tag) { + inline else => |tag| @unionInit( + Location, + @tagName(tag), + @field(value.location_payload, @tagName(tag)), + ), + }; + } + + pub fn position(vi: Value.Index, isel: *Select) struct { u64, u64 } { + return .{ vi.get(isel).offset_from_parent, vi.size(isel) }; + } + + pub fn size(vi: Value.Index, isel: *Select) u64 { + return switch (vi.location(isel)) { + inline else => |loc| loc.size, + }; + } + + fn setHint(vi: Value.Index, isel: *Select, new_hint: Register.Alias) void { + vi.get(isel).location_payload.small.hint = new_hint; + } + + pub fn hint(vi: Value.Index, isel: *Select) ?Register.Alias { + return switch (vi.location(isel)) { + .large => null, + .small => |loc| switch (loc.hint) { + .zr => null, + else => |hint_reg| hint_reg, + }, + }; + } + + fn setSignedness(vi: Value.Index, isel: *Select, new_signedness: std.builtin.Signedness) void { + const value = vi.get(isel); + assert(value.location_payload.small.size <= 2); + value.location_payload.small.signedness = new_signedness; + } + + pub fn signedness(vi: Value.Index, isel: *Select) std.builtin.Signedness { + const value = vi.get(isel); + return switch (value.flags.location_tag) { + .large => .unsigned, + .small => value.location_payload.small.signedness, + }; + } + + fn setIsVector(vi: Value.Index, isel: *Select) void { + const is_vector = &vi.get(isel).location_payload.small.is_vector; + assert(!is_vector.*); + is_vector.* = true; + } + + pub fn isVector(vi: Value.Index, isel: *Select) bool { + const value = vi.get(isel); + return switch (value.flags.location_tag) { + .large => false, + .small => value.location_payload.small.is_vector, + }; + } + + pub fn register(vi: Value.Index, isel: *Select) ?Register.Alias { + return switch (vi.location(isel)) { + .large => null, + .small => |loc| switch (loc.register) { + .zr => null, + else => |reg| reg, + }, + }; + } + + pub fn isUsed(vi: Value.Index, isel: *Select) bool { + return vi.valueParent(isel)[1].parent(isel) != .unallocated or vi.hasRegisterRecursive(isel); + } + + fn hasRegisterRecursive(vi: Value.Index, isel: *Select) bool { + if (vi.register(isel)) |_| return true; + var part_it = vi.parts(isel); + if (part_it.only() == null) while (part_it.next()) |part_vi| if (part_vi.hasRegisterRecursive(isel)) return true; + return false; + } + + fn setParts(vi: Value.Index, isel: *Select, parts_len: Value.PartsLen) void { + assert(parts_len > 1); + const value = vi.get(isel); + assert(value.flags.parts_len_minus_one == 0); + value.parts = @enumFromInt(isel.values.items.len); + value.flags.parts_len_minus_one = @intCast(parts_len - 1); + } + + fn addPart(vi: Value.Index, isel: *Select, part_offset: u64, part_size: u64) Value.Index { + const part_vi = isel.initValueAdvanced(vi.alignment(isel), part_offset, part_size); + tracking_log.debug("${d} <- ${d}[{d}]", .{ + @intFromEnum(part_vi), + @intFromEnum(vi), + part_offset, + }); + part_vi.setParent(isel, .{ .value = vi }); + return part_vi; + } + + pub fn parts(vi: Value.Index, isel: *Select) Value.PartIterator { + const value = vi.get(isel); + return switch (value.flags.parts_len_minus_one) { + 0 => .initOne(vi), + else => |parts_len_minus_one| .{ + .vi = value.parts, + .remaining = @as(Value.PartsLen, parts_len_minus_one) + 1, + }, + }; + } + + fn containingParts(vi: Value.Index, isel: *Select, part_offset: u64, part_size: u64) Value.PartIterator { + const start_vi = vi.partAtOffset(isel, part_offset); + const start_offset, const start_size = start_vi.position(isel); + if (part_offset >= start_offset and part_size <= start_size) return .initOne(start_vi); + const end_vi = vi.partAtOffset(isel, part_size - 1 + part_offset); + return .{ + .vi = start_vi, + .remaining = @intCast(@intFromEnum(end_vi) - @intFromEnum(start_vi) + 1), + }; + } + comptime { + _ = containingParts; + } + + fn partAtOffset(vi: Value.Index, isel: *Select, offset: u64) Value.Index { + const SearchPartIndex = std.math.IntFittingRange(0, Value.max_parts * 2 - 1); + const value = vi.get(isel); + var last: SearchPartIndex = value.flags.parts_len_minus_one; + if (last == 0) return vi; + var first: SearchPartIndex = 0; + last += 1; + while (true) { + const mid = (first + last) / 2; + const mid_vi: Value.Index = @enumFromInt(@intFromEnum(value.parts) + mid); + if (mid == first) return mid_vi; + if (offset < mid_vi.get(isel).offset_from_parent) last = mid else first = mid; + } + } + + fn field( + vi: Value.Index, + ty: ZigType, + field_offset: u64, + field_size: u64, + ) Value.FieldPartIterator { + assert(field_size > 0); + return .{ + .vi = vi, + .ty = ty, + .field_offset = field_offset, + .field_size = field_size, + .next_offset = 0, + }; + } + + fn ref(initial_vi: Value.Index, isel: *Select) Value.Index { + var vi = initial_vi; + while (true) { + const refs = &vi.get(isel).refs; + refs.* += 1; + if (refs.* > 1) return initial_vi; + switch (vi.parent(isel)) { + .unallocated, .stack_slot, .constant => {}, + .address, .value => |parent_vi| { + vi = parent_vi; + continue; + }, + } + return initial_vi; + } + } + + pub fn deref(initial_vi: Value.Index, isel: *Select) void { + var vi = initial_vi; + while (true) { + const refs = &vi.get(isel).refs; + refs.* -= 1; + if (refs.* > 0) return; + switch (vi.parent(isel)) { + .unallocated, .constant => {}, + .stack_slot => { + // reuse stack slot + }, + .address, .value => |parent_vi| { + vi = parent_vi; + continue; + }, + } + return; + } + } + + fn move(dst_vi: Value.Index, isel: *Select, src_ref: Air.Inst.Ref) !void { + try dst_vi.copy( + isel, + isel.air.typeOf(src_ref, &isel.pt.zcu.intern_pool), + try isel.use(src_ref), + ); + } + + fn copy(dst_vi: Value.Index, isel: *Select, ty: ZigType, src_vi: Value.Index) !void { + try dst_vi.copyAdvanced(isel, src_vi, .{ + .ty = ty, + .dst_vi = dst_vi, + .dst_offset = 0, + .src_vi = src_vi, + .src_offset = 0, + }); + } + + fn copyAdvanced(dst_vi: Value.Index, isel: *Select, src_vi: Value.Index, root: struct { + ty: ZigType, + dst_vi: Value.Index, + dst_offset: u64, + src_vi: Value.Index, + src_offset: u64, + }) !void { + if (dst_vi == src_vi) return; + var dst_part_it = dst_vi.parts(isel); + if (dst_part_it.only()) |dst_part_vi| { + var src_part_it = src_vi.parts(isel); + if (src_part_it.only()) |src_part_vi| { + try src_part_vi.liveOut(isel, try dst_part_vi.defReg(isel) orelse return); + } else while (src_part_it.next()) |src_part_vi| { + const src_part_offset, const src_part_size = src_part_vi.position(isel); + var dst_field_it = root.dst_vi.field(root.ty, root.dst_offset + src_part_offset, src_part_size); + const dst_field_vi = try dst_field_it.only(isel); + try dst_field_vi.?.copyAdvanced(isel, src_part_vi, .{ + .ty = root.ty, + .dst_vi = root.dst_vi, + .dst_offset = root.dst_offset + src_part_offset, + .src_vi = root.src_vi, + .src_offset = root.src_offset + src_part_offset, + }); + } + } else while (dst_part_it.next()) |dst_part_vi| { + const dst_part_offset, const dst_part_size = dst_part_vi.position(isel); + var src_field_it = root.src_vi.field(root.ty, root.src_offset + dst_part_offset, dst_part_size); + const src_part_vi = try src_field_it.only(isel); + try dst_part_vi.copyAdvanced(isel, src_part_vi.?, .{ + .ty = root.ty, + .dst_vi = root.dst_vi, + .dst_offset = root.dst_offset + dst_part_offset, + .src_vi = root.src_vi, + .src_offset = root.src_offset + dst_part_offset, + }); + } + } + + fn addOrSubtract( + res_vi: Value.Index, + isel: *Select, + ty: ZigType, + lhs_vi: Value.Index, + op: codegen.aarch64.encoding.Instruction.AddSubtractOp, + rhs_vi: Value.Index, + opts: struct { + wrap: bool, + overflow_ra: Register.Alias = .zr, + }, + ) !void { + assert(opts.wrap or opts.overflow_ra == .zr); + const zcu = isel.pt.zcu; + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(op), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(op), isel.fmtType(ty) }); + var part_offset = res_vi.size(isel); + var need_wrap = opts.wrap; + var need_carry = opts.overflow_ra != .zr; + while (part_offset > 0) : (need_wrap = false) { + const part_size = @min(part_offset, 8); + part_offset -= part_size; + var wrapped_res_part_it = res_vi.field(ty, part_offset, part_size); + const wrapped_res_part_vi = try wrapped_res_part_it.only(isel); + const wrapped_res_part_ra = try wrapped_res_part_vi.?.defReg(isel) orelse if (need_carry) .zr else continue; + const unwrapped_res_part_ra = unwrapped_res_part_ra: { + if (!need_wrap) break :unwrapped_res_part_ra wrapped_res_part_ra; + if (int_info.bits % 32 == 0) { + if (opts.overflow_ra != .zr) try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(switch (int_info.signedness) { + .signed => .vs, + .unsigned => switch (op) { + .add => .cs, + .sub => .cc, + }, + }))); + break :unwrapped_res_part_ra wrapped_res_part_ra; + } + const wrapped_part_ra, const unwrapped_part_ra = if (opts.overflow_ra != .zr) part_ra: { + switch (op) { + .add => {}, + .sub => switch (int_info.signedness) { + .signed => {}, + .unsigned => { + try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(.cc))); + break :part_ra .{ wrapped_res_part_ra, wrapped_res_part_ra }; + }, + }, + } + try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(.ne))); + const wrapped_part_ra = switch (wrapped_res_part_ra) { + else => |res_part_ra| res_part_ra, + .zr => try isel.allocIntReg(), + }; + errdefer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra); + const unwrapped_part_ra = unwrapped_part_ra: { + const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) { + else => |res_part_ra| isel.lockReg(res_part_ra), + .zr => .empty, + }; + defer wrapped_res_part_lock.unlock(isel); + break :unwrapped_part_ra try isel.allocIntReg(); + }; + errdefer isel.freeReg(unwrapped_part_ra); + switch (part_size) { + else => unreachable, + 1...4 => try isel.emit(.subs(.wzr, wrapped_part_ra.w(), .{ .register = unwrapped_part_ra.w() })), + 5...8 => try isel.emit(.subs(.xzr, wrapped_part_ra.x(), .{ .register = unwrapped_part_ra.x() })), + } + break :part_ra .{ wrapped_part_ra, unwrapped_part_ra }; + } else .{ wrapped_res_part_ra, wrapped_res_part_ra }; + defer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra); + errdefer if (unwrapped_part_ra != wrapped_res_part_ra) isel.freeReg(unwrapped_part_ra); + if (wrapped_part_ra != .zr) try isel.emit(switch (part_size) { + else => unreachable, + 1...4 => switch (int_info.signedness) { + .signed => .sbfm(wrapped_part_ra.w(), unwrapped_part_ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @truncate(int_info.bits - 1), + }), + .unsigned => .ubfm(wrapped_part_ra.w(), unwrapped_part_ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @truncate(int_info.bits - 1), + }), + }, + 5...8 => switch (int_info.signedness) { + .signed => .sbfm(wrapped_part_ra.x(), unwrapped_part_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @truncate(int_info.bits - 1), + }), + .unsigned => .ubfm(wrapped_part_ra.x(), unwrapped_part_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @truncate(int_info.bits - 1), + }), + }, + }); + break :unwrapped_res_part_ra unwrapped_part_ra; + }; + defer if (unwrapped_res_part_ra != wrapped_res_part_ra) isel.freeReg(unwrapped_res_part_ra); + var lhs_part_it = lhs_vi.field(ty, part_offset, part_size); + const lhs_part_vi = try lhs_part_it.only(isel); + const lhs_part_mat = try lhs_part_vi.?.matReg(isel); + var rhs_part_it = rhs_vi.field(ty, part_offset, part_size); + const rhs_part_vi = try rhs_part_it.only(isel); + const rhs_part_mat = try rhs_part_vi.?.matReg(isel); + try isel.emit(switch (part_size) { + else => unreachable, + 1...4 => switch (op) { + .add => switch (part_offset) { + 0 => switch (need_carry) { + false => .add(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), + true => .adds(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), + }, + else => switch (need_carry) { + false => .adc(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()), + true => .adcs(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()), + }, + }, + .sub => switch (part_offset) { + 0 => switch (need_carry) { + false => .sub(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), + true => .subs(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), + }, + else => switch (need_carry) { + false => .sbc(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()), + true => .sbcs(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()), + }, + }, + }, + 5...8 => switch (op) { + .add => switch (part_offset) { + 0 => switch (need_carry) { + false => .add(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), + true => .adds(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), + }, + else => switch (need_carry) { + false => .adc(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()), + true => .adcs(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()), + }, + }, + .sub => switch (part_offset) { + 0 => switch (need_carry) { + false => .sub(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), + true => .subs(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), + }, + else => switch (need_carry) { + false => .sbc(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()), + true => .sbcs(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()), + }, + }, + }, + }); + try rhs_part_mat.finish(isel); + try lhs_part_mat.finish(isel); + need_carry = true; + } + } + + const MemoryAccessOptions = struct { + root_vi: Value.Index = .free, + offset: u64 = 0, + @"volatile": bool = false, + split: bool = true, + wrap: ?std.builtin.Type.Int = null, + expected_live_registers: *const LiveRegisters = &.initFill(.free), + }; + + fn load( + vi: Value.Index, + isel: *Select, + root_ty: ZigType, + base_ra: Register.Alias, + opts: MemoryAccessOptions, + ) !bool { + const root_vi = switch (opts.root_vi) { + _ => |root_vi| root_vi, + .allocating => unreachable, + .free => vi, + }; + var part_it = vi.parts(isel); + if (part_it.only()) |part_vi| only: { + const part_size = part_vi.size(isel); + const part_is_vector = part_vi.isVector(isel); + if (part_size > @as(@TypeOf(part_size), if (part_is_vector) 16 else 8)) { + if (!opts.split) return false; + var subpart_it = root_vi.field(root_ty, opts.offset, part_size - 1); + _ = try subpart_it.next(isel); + part_it = vi.parts(isel); + assert(part_it.only() == null); + break :only; + } + const part_ra = if (try part_vi.defReg(isel)) |part_ra| + part_ra + else if (opts.@"volatile") + .zr + else + return false; + if (part_ra != .zr) { + const live_vi = isel.live_registers.getPtr(part_ra); + assert(live_vi.* == .free); + live_vi.* = .allocating; + } + if (opts.wrap) |int_info| switch (int_info.bits) { + else => unreachable, + 1...7, 9...15, 17...31 => |bits| try isel.emit(switch (int_info.signedness) { + .signed => .sbfm(part_ra.w(), part_ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(bits - 1), + }), + .unsigned => .ubfm(part_ra.w(), part_ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(bits - 1), + }), + }), + 8, 16, 32 => {}, + 33...63 => |bits| try isel.emit(switch (int_info.signedness) { + .signed => .sbfm(part_ra.x(), part_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + }), + .unsigned => .ubfm(part_ra.x(), part_ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(bits - 1), + }), + }), + 64 => {}, + }; + try isel.emit(emit: switch (part_size) { + else => return isel.fail("bad load size of {d}", .{part_size}), + 1 => if (part_is_vector) .ldr(part_ra.b(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset), + } }) else switch (part_vi.signedness(isel)) { + .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset), + } }), + .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset), + } }), + }, + 2 => if (part_is_vector) .ldr(part_ra.h(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset), + } }) else switch (part_vi.signedness(isel)) { + .signed => .ldrsh(part_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset), + } }), + .unsigned => .ldrh(part_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset), + } }), + }, + 3 => { + const lo16_ra = try isel.allocIntReg(); + defer isel.freeReg(lo16_ra); + try isel.emit(.orr(part_ra.w(), lo16_ra.w(), .{ .shifted_register = .{ + .register = part_ra.w(), + .shift = .{ .lsl = 16 }, + } })); + try isel.emit(switch (part_vi.signedness(isel)) { + .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset + 2), + } }), + .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset + 2), + } }), + }); + break :emit .ldrh(lo16_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset), + } }); + }, + 4 => .ldr(if (part_is_vector) part_ra.s() else part_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset), + } }), + 5 => { + const lo32_ra = try isel.allocIntReg(); + defer isel.freeReg(lo32_ra); + try isel.emit(.orr(part_ra.x(), lo32_ra.x(), .{ .shifted_register = .{ + .register = part_ra.x(), + .shift = .{ .lsl = 32 }, + } })); + try isel.emit(switch (part_vi.signedness(isel)) { + .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset + 4), + } }), + .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset + 4), + } }), + }); + break :emit .ldr(lo32_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset), + } }); + }, + 7 => { + const lo32_ra = try isel.allocIntReg(); + defer isel.freeReg(lo32_ra); + const lo48_ra = try isel.allocIntReg(); + defer isel.freeReg(lo48_ra); + try isel.emit(.orr(part_ra.x(), lo48_ra.x(), .{ .shifted_register = .{ + .register = part_ra.x(), + .shift = .{ .lsl = 32 + 16 }, + } })); + try isel.emit(switch (part_vi.signedness(isel)) { + .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset + 4 + 2), + } }), + .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset + 4 + 2), + } }), + }); + try isel.emit(.orr(lo48_ra.x(), lo32_ra.x(), .{ .shifted_register = .{ + .register = lo48_ra.x(), + .shift = .{ .lsl = 32 }, + } })); + try isel.emit(.ldrh(lo48_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset + 4), + } })); + break :emit .ldr(lo32_ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset), + } }); + }, + 8 => .ldr(if (part_is_vector) part_ra.d() else part_ra.x(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset), + } }), + 16 => .ldr(part_ra.q(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = @intCast(opts.offset), + } }), + }); + if (part_ra != .zr) { + const live_vi = isel.live_registers.getPtr(part_ra); + assert(live_vi.* == .allocating); + switch (opts.expected_live_registers.get(part_ra)) { + _ => {}, + .allocating => unreachable, + .free => live_vi.* = .free, + } + } + return true; + } + var used = false; + while (part_it.next()) |part_vi| used |= try part_vi.load(isel, root_ty, base_ra, .{ + .root_vi = root_vi, + .offset = opts.offset + part_vi.get(isel).offset_from_parent, + .@"volatile" = opts.@"volatile", + .split = opts.split, + .wrap = switch (part_it.remaining) { + else => null, + 0 => if (opts.wrap) |wrap| .{ + .signedness = wrap.signedness, + .bits = @intCast(wrap.bits - 8 * part_vi.position(isel)[0]), + } else null, + }, + .expected_live_registers = opts.expected_live_registers, + }); + return used; + } + + fn store( + vi: Value.Index, + isel: *Select, + root_ty: ZigType, + base_ra: Register.Alias, + opts: MemoryAccessOptions, + ) !void { + const root_vi = switch (opts.root_vi) { + _ => |root_vi| root_vi, + .allocating => unreachable, + .free => vi, + }; + var part_it = vi.parts(isel); + if (part_it.only()) |part_vi| only: { + const part_size = part_vi.size(isel); + const part_is_vector = part_vi.isVector(isel); + if (part_size > @as(@TypeOf(part_size), if (part_is_vector) 16 else 8)) { + if (!opts.split) return; + var subpart_it = root_vi.field(root_ty, opts.offset, part_size - 1); + _ = try subpart_it.next(isel); + part_it = vi.parts(isel); + assert(part_it.only() == null); + break :only; + } + const part_mat = try part_vi.matReg(isel); + try isel.storeReg(part_mat.ra, part_size, base_ra, opts.offset); + return part_mat.finish(isel); + } + while (part_it.next()) |part_vi| try part_vi.store(isel, root_ty, base_ra, .{ + .root_vi = root_vi, + .offset = opts.offset + part_vi.get(isel).offset_from_parent, + .@"volatile" = opts.@"volatile", + .split = opts.split, + .wrap = switch (part_it.remaining) { + else => null, + 0 => if (opts.wrap) |wrap| .{ + .signedness = wrap.signedness, + .bits = @intCast(wrap.bits - 8 * part_vi.position(isel)[0]), + } else null, + }, + .expected_live_registers = opts.expected_live_registers, + }); + } + + fn mat(vi: Value.Index, isel: *Select) !void { + if (false) { + var part_it: Value.PartIterator = if (vi.size(isel) > 8) vi.parts(isel) else .initOne(vi); + if (part_it.only()) |part_vi| only: { + const mat_ra = mat_ra: { + if (part_vi.register(isel)) |mat_ra| { + part_vi.get(isel).location_payload.small.register = .zr; + const live_vi = isel.live_registers.getPtr(mat_ra); + assert(live_vi.* == part_vi); + live_vi.* = .allocating; + break :mat_ra mat_ra; + } + if (part_vi.hint(isel)) |hint_ra| { + const live_vi = isel.live_registers.getPtr(hint_ra); + if (live_vi.* == .free) { + live_vi.* = .allocating; + isel.saved_registers.insert(hint_ra); + break :mat_ra hint_ra; + } + } + const part_size = part_vi.size(isel); + const part_is_vector = part_vi.isVector(isel); + if (part_size <= @as(@TypeOf(part_size), if (part_is_vector) 16 else 8)) + switch (if (part_is_vector) isel.tryAllocVecReg() else isel.tryAllocIntReg()) { + .allocated => |ra| break :mat_ra ra, + .fill_candidate, .out_of_registers => {}, + }; + _, const parent_vi = vi.valueParent(isel); + switch (parent_vi.parent(isel)) { + .unallocated => parent_vi.setParent(isel, .{ .stack_slot = parent_vi.allocStackSlot(isel) }), + else => {}, + } + break :only; + }; + assert(isel.live_registers.get(mat_ra) == .allocating); + try Value.Materialize.finish(.{ .vi = part_vi, .ra = mat_ra }, isel); + } else while (part_it.next()) |part_vi| try part_vi.mat(isel); + } else { + _, const parent_vi = vi.valueParent(isel); + switch (parent_vi.parent(isel)) { + .unallocated => parent_vi.setParent(isel, .{ .stack_slot = parent_vi.allocStackSlot(isel) }), + else => {}, + } + } + } + + fn matReg(vi: Value.Index, isel: *Select) !Value.Materialize { + const mat_ra = mat_ra: { + if (vi.register(isel)) |mat_ra| { + vi.get(isel).location_payload.small.register = .zr; + const live_vi = isel.live_registers.getPtr(mat_ra); + assert(live_vi.* == vi); + live_vi.* = .allocating; + break :mat_ra mat_ra; + } + if (vi.hint(isel)) |hint_ra| { + const live_vi = isel.live_registers.getPtr(hint_ra); + if (live_vi.* == .free) { + live_vi.* = .allocating; + isel.saved_registers.insert(hint_ra); + break :mat_ra hint_ra; + } + } + break :mat_ra if (vi.isVector(isel)) try isel.allocVecReg() else try isel.allocIntReg(); + }; + assert(isel.live_registers.get(mat_ra) == .allocating); + return .{ .vi = vi, .ra = mat_ra }; + } + + fn defAddr( + def_vi: Value.Index, + isel: *Select, + def_ty: ZigType, + wrap: ?std.builtin.Type.Int, + expected_live_registers: *const LiveRegisters, + ) !?void { + if (!def_vi.isUsed(isel)) return null; + const offset_from_parent: i65, const parent_vi = def_vi.valueParent(isel); + const stack_slot, const allocated = switch (parent_vi.parent(isel)) { + .unallocated => .{ parent_vi.allocStackSlot(isel), true }, + .stack_slot => |stack_slot| .{ stack_slot, false }, + else => unreachable, + }; + _ = try def_vi.load(isel, def_ty, stack_slot.base, .{ + .offset = @intCast(stack_slot.offset + offset_from_parent), + .split = false, + .wrap = wrap, + .expected_live_registers = expected_live_registers, + }); + if (allocated) parent_vi.setParent(isel, .{ .stack_slot = stack_slot }); + } + + fn defReg(def_vi: Value.Index, isel: *Select) !?Register.Alias { + var vi = def_vi; + var offset: i65 = 0; + var def_ra: ?Register.Alias = null; + while (true) { + if (vi.register(isel)) |ra| { + vi.get(isel).location_payload.small.register = .zr; + const live_vi = isel.live_registers.getPtr(ra); + assert(live_vi.* == vi); + if (def_ra == null and vi != def_vi) { + var part_it = vi.parts(isel); + assert(part_it.only() == null); + + const first_part_vi = part_it.next().?; + const first_part_value = first_part_vi.get(isel); + assert(first_part_value.offset_from_parent == 0); + first_part_value.location_payload.small.register = ra; + live_vi.* = first_part_vi; + + const vi_size = vi.size(isel); + while (part_it.next()) |part_vi| { + const part_offset, const part_size = part_vi.position(isel); + const part_mat = try part_vi.matReg(isel); + try isel.emit(if (part_vi.isVector(isel)) emit: { + assert(part_offset == 0 and part_size == vi_size); + break :emit size: switch (vi_size) { + else => unreachable, + 2 => if (isel.target.cpu.has(.aarch64, .fullfp16)) + .fmov(ra.h(), .{ .register = part_mat.ra.h() }) + else + continue :size 4, + 4 => .fmov(ra.s(), .{ .register = part_mat.ra.s() }), + 8 => .fmov(ra.d(), .{ .register = part_mat.ra.d() }), + 16 => .orr(ra.@"16b"(), part_mat.ra.@"16b"(), .{ .register = part_mat.ra.@"16b"() }), + }; + } else switch (vi_size) { + else => unreachable, + 1...4 => .bfm(ra.w(), part_mat.ra.w(), .{ + .N = .word, + .immr = @as(u5, @truncate(32 - 8 * part_offset)), + .imms = @intCast(8 * part_size - 1), + }), + 5...8 => .bfm(ra.x(), part_mat.ra.x(), .{ + .N = .doubleword, + .immr = @as(u6, @truncate(64 - 8 * part_offset)), + .imms = @intCast(8 * part_size - 1), + }), + }); + try part_mat.finish(isel); + } + vi = def_vi; + offset = 0; + continue; + } + live_vi.* = .free; + def_ra = ra; + } + offset += vi.get(isel).offset_from_parent; + switch (vi.parent(isel)) { + else => unreachable, + .unallocated => return def_ra, + .stack_slot => |stack_slot| { + offset += stack_slot.offset; + const def_is_vector = def_vi.isVector(isel); + const ra = def_ra orelse if (def_is_vector) try isel.allocVecReg() else try isel.allocIntReg(); + defer if (def_ra == null) isel.freeReg(ra); + try isel.storeReg(ra, def_vi.size(isel), stack_slot.base, offset); + return ra; + }, + .value => |parent_vi| vi = parent_vi, + } + } + } + + pub fn liveIn( + vi: Value.Index, + isel: *Select, + src_ra: Register.Alias, + expected_live_registers: *const LiveRegisters, + ) !void { + const src_live_vi = isel.live_registers.getPtr(src_ra); + if (vi.register(isel)) |dst_ra| { + const dst_live_vi = isel.live_registers.getPtr(dst_ra); + assert(dst_live_vi.* == vi); + if (dst_ra == src_ra) { + src_live_vi.* = .allocating; + return; + } + dst_live_vi.* = .allocating; + if (try isel.fill(src_ra)) { + assert(src_live_vi.* == .free); + src_live_vi.* = .allocating; + } + assert(src_live_vi.* == .allocating); + try isel.emit(switch (dst_ra.isVector()) { + false => switch (src_ra.isVector()) { + false => switch (vi.size(isel)) { + else => unreachable, + 1...4 => .orr(dst_ra.w(), .wzr, .{ .register = src_ra.w() }), + 5...8 => .orr(dst_ra.x(), .xzr, .{ .register = src_ra.x() }), + }, + true => switch (vi.size(isel)) { + else => unreachable, + 2 => .fmov(dst_ra.w(), .{ .register = src_ra.h() }), + 4 => .fmov(dst_ra.w(), .{ .register = src_ra.s() }), + 8 => .fmov(dst_ra.x(), .{ .register = src_ra.d() }), + }, + }, + true => switch (src_ra.isVector()) { + false => switch (vi.size(isel)) { + else => unreachable, + 2 => .fmov(dst_ra.h(), .{ .register = src_ra.w() }), + 4 => .fmov(dst_ra.s(), .{ .register = src_ra.w() }), + 8 => .fmov(dst_ra.d(), .{ .register = src_ra.x() }), + }, + true => switch (vi.size(isel)) { + else => unreachable, + 2 => .fmov(dst_ra.h(), .{ .register = src_ra.h() }), + 4 => .fmov(dst_ra.s(), .{ .register = src_ra.s() }), + 8 => .fmov(dst_ra.d(), .{ .register = src_ra.d() }), + 16 => .orr(dst_ra.@"16b"(), src_ra.@"16b"(), .{ .register = src_ra.@"16b"() }), + }, + }, + }); + assert(dst_live_vi.* == .allocating); + dst_live_vi.* = switch (expected_live_registers.get(dst_ra)) { + _ => .allocating, + .allocating => .allocating, + .free => .free, + }; + } else if (try isel.fill(src_ra)) { + assert(src_live_vi.* == .free); + src_live_vi.* = .allocating; + } + assert(src_live_vi.* == .allocating); + vi.get(isel).location_payload.small.register = src_ra; + } + + pub fn defLiveIn( + vi: Value.Index, + isel: *Select, + src_ra: Register.Alias, + expected_live_registers: *const LiveRegisters, + ) !void { + try vi.liveIn(isel, src_ra, expected_live_registers); + const offset_from_parent: i65, const parent_vi = vi.valueParent(isel); + switch (parent_vi.parent(isel)) { + .unallocated => {}, + .stack_slot => |stack_slot| { + const offset = stack_slot.offset + offset_from_parent; + try isel.emit(switch (vi.size(isel)) { + else => unreachable, + 1 => if (src_ra.isVector()) .str(src_ra.b(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }) else .strb(src_ra.w(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }), + 2 => if (src_ra.isVector()) .str(src_ra.h(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }) else .strh(src_ra.w(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }), + 4 => .str(if (src_ra.isVector()) src_ra.s() else src_ra.w(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }), + 8 => .str(if (src_ra.isVector()) src_ra.d() else src_ra.x(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }), + 16 => .str(src_ra.q(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }), + }); + }, + else => unreachable, + } + try vi.spillReg(isel, src_ra, 0, expected_live_registers); + } + + fn spillReg( + vi: Value.Index, + isel: *Select, + src_ra: Register.Alias, + start_offset: u64, + expected_live_registers: *const LiveRegisters, + ) !void { + assert(isel.live_registers.get(src_ra) == .allocating); + var part_it = vi.parts(isel); + if (part_it.only()) |part_vi| { + const dst_ra = part_vi.register(isel) orelse return; + if (dst_ra == src_ra) return; + const part_size = part_vi.size(isel); + const part_ra = if (part_vi.isVector(isel)) try isel.allocIntReg() else dst_ra; + defer if (part_ra != dst_ra) isel.freeReg(part_ra); + if (part_ra != dst_ra) try isel.emit(switch (part_size) { + else => unreachable, + 2 => .fmov(dst_ra.h(), .{ .register = part_ra.w() }), + 4 => .fmov(dst_ra.s(), .{ .register = part_ra.w() }), + 8 => .fmov(dst_ra.d(), .{ .register = part_ra.x() }), + }); + try isel.emit(switch (start_offset + part_size) { + else => unreachable, + 1...4 => |end_offset| switch (part_vi.signedness(isel)) { + .signed => .sbfm(part_ra.w(), src_ra.w(), .{ + .N = .word, + .immr = @intCast(8 * start_offset), + .imms = @intCast(8 * end_offset - 1), + }), + .unsigned => .ubfm(part_ra.w(), src_ra.w(), .{ + .N = .word, + .immr = @intCast(8 * start_offset), + .imms = @intCast(8 * end_offset - 1), + }), + }, + 5...8 => |end_offset| switch (part_vi.signedness(isel)) { + .signed => .sbfm(part_ra.x(), src_ra.x(), .{ + .N = .doubleword, + .immr = @intCast(8 * start_offset), + .imms = @intCast(8 * end_offset - 1), + }), + .unsigned => .ubfm(part_ra.x(), src_ra.x(), .{ + .N = .doubleword, + .immr = @intCast(8 * start_offset), + .imms = @intCast(8 * end_offset - 1), + }), + }, + }); + const value_ra = &part_vi.get(isel).location_payload.small.register; + assert(value_ra.* == dst_ra); + value_ra.* = .zr; + const dst_live_vi = isel.live_registers.getPtr(dst_ra); + assert(dst_live_vi.* == part_vi); + dst_live_vi.* = switch (expected_live_registers.get(dst_ra)) { + _ => .allocating, + .allocating => unreachable, + .free => .free, + }; + } else while (part_it.next()) |part_vi| try part_vi.spillReg( + isel, + src_ra, + start_offset + part_vi.get(isel).offset_from_parent, + expected_live_registers, + ); + } + + fn liveOut(vi: Value.Index, isel: *Select, ra: Register.Alias) !void { + assert(try isel.fill(ra)); + const live_vi = isel.live_registers.getPtr(ra); + assert(live_vi.* == .free); + live_vi.* = .allocating; + try Value.Materialize.finish(.{ .vi = vi, .ra = ra }, isel); + } + + fn allocStackSlot(vi: Value.Index, isel: *Select) Value.Indirect { + const offset = vi.alignment(isel).forward(isel.stack_size); + isel.stack_size = @intCast(offset + vi.size(isel)); + tracking_log.debug("${d} -> [sp, #0x{x}]", .{ @intFromEnum(vi), @abs(offset) }); + return .{ + .base = .sp, + .offset = @intCast(offset), + }; + } + + fn address(initial_vi: Value.Index, isel: *Select, initial_offset: u64, ptr_ra: Register.Alias) !void { + var vi = initial_vi; + var offset: i65 = vi.get(isel).offset_from_parent + initial_offset; + parent: switch (vi.parent(isel)) { + .unallocated => { + const stack_slot = vi.allocStackSlot(isel); + vi.setParent(isel, .{ .stack_slot = stack_slot }); + continue :parent .{ .stack_slot = stack_slot }; + }, + .stack_slot => |stack_slot| { + offset += stack_slot.offset; + const lo12: u12 = @truncate(@abs(offset) >> 0); + const hi12: u12 = @intCast(@abs(offset) >> 12); + if (hi12 > 0) try isel.emit(if (offset >= 0) .add( + ptr_ra.x(), + if (lo12 > 0) ptr_ra.x() else stack_slot.base.x(), + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + ) else .sub( + ptr_ra.x(), + if (lo12 > 0) ptr_ra.x() else stack_slot.base.x(), + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + )); + if (lo12 > 0 or hi12 == 0) try isel.emit(if (offset >= 0) .add( + ptr_ra.x(), + stack_slot.base.x(), + .{ .immediate = lo12 }, + ) else .sub( + ptr_ra.x(), + stack_slot.base.x(), + .{ .immediate = lo12 }, + )); + }, + .address => |address_vi| try address_vi.liveOut(isel, ptr_ra), + .value => |parent_vi| { + vi = parent_vi; + offset += vi.get(isel).offset_from_parent; + continue :parent vi.parent(isel); + }, + .constant => |constant| { + const pt = isel.pt; + const zcu = pt.zcu; + switch (true) { + false => { + try isel.uav_relocs.append(zcu.gpa, .{ + .uav = .{ + .val = constant.toIntern(), + .orig_ty = (try pt.singleConstPtrType(constant.typeOf(zcu))).toIntern(), + }, + .reloc = .{ + .label = @intCast(isel.instructions.items.len), + .addend = @intCast(offset), + }, + }); + try isel.emit(.adr(ptr_ra.x(), 0)); + }, + true => { + try isel.uav_relocs.append(zcu.gpa, .{ + .uav = .{ + .val = constant.toIntern(), + .orig_ty = (try pt.singleConstPtrType(constant.typeOf(zcu))).toIntern(), + }, + .reloc = .{ + .label = @intCast(isel.instructions.items.len), + .addend = @intCast(offset), + }, + }); + try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 })); + try isel.uav_relocs.append(zcu.gpa, .{ + .uav = .{ + .val = constant.toIntern(), + .orig_ty = (try pt.singleConstPtrType(constant.typeOf(zcu))).toIntern(), + }, + .reloc = .{ + .label = @intCast(isel.instructions.items.len), + .addend = @intCast(offset), + }, + }); + try isel.emit(.adrp(ptr_ra.x(), 0)); + }, + } + }, + } + } + }; + + pub const PartIterator = struct { + vi: Value.Index, + remaining: Value.PartsLen, + + fn initOne(vi: Value.Index) PartIterator { + return .{ .vi = vi, .remaining = 1 }; + } + + pub fn next(it: *PartIterator) ?Value.Index { + if (it.remaining == 0) return null; + it.remaining -= 1; + defer it.vi = @enumFromInt(@intFromEnum(it.vi) + 1); + return it.vi; + } + + pub fn only(it: PartIterator) ?Value.Index { + return if (it.remaining == 1) it.vi else null; + } + }; + + const FieldPartIterator = struct { + vi: Value.Index, + ty: ZigType, + field_offset: u64, + field_size: u64, + next_offset: u64, + + fn next(it: *FieldPartIterator, isel: *Select) !?struct { offset: u64, vi: Value.Index } { + const next_offset = it.next_offset; + const next_part_size = it.field_size - next_offset; + if (next_part_size == 0) return null; + var next_part_offset = it.field_offset + next_offset; + + const zcu = isel.pt.zcu; + const ip = &zcu.intern_pool; + var vi = it.vi; + var ty = it.ty; + var ty_size = vi.size(isel); + assert(ty_size == ty.abiSize(zcu)); + var offset: u64 = 0; + var size = ty_size; + assert(next_part_offset + next_part_size <= size); + while (next_part_offset > 0 or next_part_size < size) { + const part_vi = vi.partAtOffset(isel, next_part_offset); + if (part_vi != vi) { + vi = part_vi; + const part_offset, size = part_vi.position(isel); + assert(part_offset <= next_part_offset and part_offset + size > next_part_offset); + offset += part_offset; + next_part_offset -= part_offset; + continue; + } + try isel.values.ensureUnusedCapacity(zcu.gpa, Value.max_parts); + type_key: switch (ip.indexToKey(ty.toIntern())) { + else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}), + .int_type => |int_type| switch (int_type.bits) { + 0 => unreachable, + 1...64 => unreachable, + 65...256 => |bits| if (offset == 0 and size == ty_size) { + const parts_len = std.math.divCeil(u16, bits, 64) catch unreachable; + vi.setParts(isel, @intCast(parts_len)); + for (0..parts_len) |part_index| _ = vi.addPart(isel, 8 * part_index, 8); + }, + else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}), + }, + .ptr_type => |ptr_type| switch (ptr_type.flags.size) { + .one, .many, .c => unreachable, + .slice => if (offset == 0 and size == ty_size) { + vi.setParts(isel, 2); + _ = vi.addPart(isel, 0, 8); + _ = vi.addPart(isel, 8, 8); + } else unreachable, + }, + .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu)) + continue :type_key ip.indexToKey(child_type) + else switch (ZigType.fromInterned(child_type).abiSize(zcu)) { + 0...8, 16 => |child_size| if (offset == 0 and size == ty_size) { + vi.setParts(isel, 2); + _ = vi.addPart(isel, 0, child_size); + _ = vi.addPart(isel, child_size, 1); + } else unreachable, + 9...15 => |child_size| if (offset == 0 and size == ty_size) { + vi.setParts(isel, 2); + _ = vi.addPart(isel, 0, 8); + _ = vi.addPart(isel, 8, ty_size - 8); + } else if (offset == 8 and size == ty_size - 8) { + vi.setParts(isel, 2); + _ = vi.addPart(isel, 0, child_size - 8); + _ = vi.addPart(isel, child_size - 8, 1); + } else unreachable, + else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}), + }, + .array_type => |array_type| { + const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; + const array_len = array_type.lenIncludingSentinel(); + if (array_len > Value.max_parts and + (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) + return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); + const alignment = vi.alignment(isel); + const Part = struct { offset: u64, size: u64 }; + var parts: [Value.max_parts]Part = undefined; + var parts_len: Value.PartsLen = 0; + const elem_ty: ZigType = .fromInterned(array_type.child); + const elem_size = elem_ty.abiSize(zcu); + const elem_signedness = if (ty.isAbiInt(zcu)) elem_signedness: { + const elem_int_info = elem_ty.intInfo(zcu); + break :elem_signedness if (elem_int_info.bits <= 16) elem_int_info.signedness else null; + } else null; + const elem_is_vector = elem_size <= 16 and + CallAbiIterator.homogeneousAggregateBaseType(zcu, elem_ty.toIntern()) != null; + var elem_end: u64 = 0; + for (0..@intCast(array_len)) |_| { + const elem_begin = elem_end; + if (elem_begin >= offset + size) break; + elem_end = elem_begin + elem_size; + if (elem_end <= offset) continue; + if (offset >= elem_begin and offset + size <= elem_begin + elem_size) { + ty = elem_ty; + ty_size = elem_size; + offset -= elem_begin; + continue :type_key ip.indexToKey(elem_ty.toIntern()); + } + if (parts_len > 0) combine: { + const prev_part = &parts[parts_len - 1]; + const combined_size = elem_end - prev_part.offset; + if (combined_size > @as(u64, 1) << @min( + min_part_log2_stride, + alignment.toLog2Units(), + @ctz(prev_part.offset), + )) break :combine; + prev_part.size = combined_size; + continue; + } + parts[parts_len] = .{ .offset = elem_begin, .size = elem_size }; + parts_len += 1; + } + vi.setParts(isel, parts_len); + for (parts[0..parts_len]) |part| { + const subpart_vi = vi.addPart(isel, part.offset - offset, part.size); + if (elem_signedness) |signedness| subpart_vi.setSignedness(isel, signedness); + if (elem_is_vector) subpart_vi.setIsVector(isel); + } + }, + .anyframe_type => unreachable, + .error_union_type => |error_union_type| { + const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; + if ((std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) + return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); + const alignment = vi.alignment(isel); + const payload_ty: ZigType = .fromInterned(error_union_type.payload_type); + const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu); + const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu); + const Part = struct { offset: u64, size: u64, signedness: ?std.builtin.Signedness, is_vector: bool }; + var parts: [2]Part = undefined; + var parts_len: Value.PartsLen = 0; + var field_end: u64 = 0; + for (0..2) |field_index| { + const field_ty: ZigType, const field_begin = switch (@as(enum { error_set, payload }, switch (field_index) { + 0 => if (error_set_offset < payload_offset) .error_set else .payload, + 1 => if (error_set_offset < payload_offset) .payload else .error_set, + else => unreachable, + })) { + .error_set => .{ .fromInterned(error_union_type.error_set_type), error_set_offset }, + .payload => .{ payload_ty, payload_offset }, + }; + if (field_begin >= offset + size) break; + const field_size = field_ty.abiSize(zcu); + if (field_size == 0) continue; + field_end = field_begin + field_size; + if (field_end <= offset) continue; + if (offset >= field_begin and offset + size <= field_begin + field_size) { + ty = field_ty; + ty_size = field_size; + offset -= field_begin; + continue :type_key ip.indexToKey(field_ty.toIntern()); + } + const field_signedness = if (field_ty.isAbiInt(zcu)) field_signedness: { + const field_int_info = field_ty.intInfo(zcu); + break :field_signedness if (field_int_info.bits <= 16) field_int_info.signedness else null; + } else null; + const field_is_vector = field_size <= 16 and + CallAbiIterator.homogeneousAggregateBaseType(zcu, field_ty.toIntern()) != null; + if (parts_len > 0) combine: { + const prev_part = &parts[parts_len - 1]; + const combined_size = field_end - prev_part.offset; + if (combined_size > @as(u64, 1) << @min( + min_part_log2_stride, + alignment.toLog2Units(), + @ctz(prev_part.offset), + )) break :combine; + prev_part.size = combined_size; + prev_part.signedness = null; + prev_part.is_vector &= field_is_vector; + continue; + } + parts[parts_len] = .{ + .offset = field_begin, + .size = field_size, + .signedness = field_signedness, + .is_vector = field_is_vector, + }; + parts_len += 1; + } + vi.setParts(isel, parts_len); + for (parts[0..parts_len]) |part| { + const subpart_vi = vi.addPart(isel, part.offset - offset, part.size); + if (part.signedness) |signedness| subpart_vi.setSignedness(isel, signedness); + if (part.is_vector) subpart_vi.setIsVector(isel); + } + }, + .simple_type => |simple_type| switch (simple_type) { + .f16, .f32, .f64, .f128, .c_longdouble => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}), + .f80 => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 80 } }, + .usize, + .isize, + .c_char, + .c_short, + .c_ushort, + .c_int, + .c_uint, + .c_long, + .c_ulong, + .c_longlong, + .c_ulonglong, + => continue :type_key .{ .int_type = ty.intInfo(zcu) }, + .anyopaque, + .void, + .type, + .comptime_int, + .comptime_float, + .noreturn, + .null, + .undefined, + .enum_literal, + .adhoc_inferred_error_set, + .generic_poison, + => unreachable, + .bool => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 1 } }, + .anyerror => continue :type_key .{ .int_type = .{ + .signedness = .unsigned, + .bits = zcu.errorSetBits(), + } }, + }, + .struct_type => { + const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; + const loaded_struct = ip.loadStructType(ty.toIntern()); + if (loaded_struct.field_types.len > Value.max_parts and + (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) + return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); + const alignment = vi.alignment(isel); + const Part = struct { offset: u64, size: u64, signedness: ?std.builtin.Signedness, is_vector: bool }; + var parts: [Value.max_parts]Part = undefined; + var parts_len: Value.PartsLen = 0; + var field_end: u64 = 0; + var field_it = loaded_struct.iterateRuntimeOrder(ip); + while (field_it.next()) |field_index| { + const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); + const field_begin = switch (loaded_struct.fieldAlign(ip, field_index)) { + .none => field_ty.abiAlignment(zcu), + else => |field_align| field_align, + }.forward(field_end); + if (field_begin >= offset + size) break; + const field_size = field_ty.abiSize(zcu); + field_end = field_begin + field_size; + if (field_end <= offset) continue; + if (offset >= field_begin and offset + size <= field_begin + field_size) { + ty = field_ty; + ty_size = field_size; + offset -= field_begin; + continue :type_key ip.indexToKey(field_ty.toIntern()); + } + const field_signedness = if (field_ty.isAbiInt(zcu)) field_signedness: { + const field_int_info = field_ty.intInfo(zcu); + break :field_signedness if (field_int_info.bits <= 16) field_int_info.signedness else null; + } else null; + const field_is_vector = field_size <= 16 and + CallAbiIterator.homogeneousAggregateBaseType(zcu, field_ty.toIntern()) != null; + if (parts_len > 0) combine: { + const prev_part = &parts[parts_len - 1]; + const combined_size = field_end - prev_part.offset; + if (combined_size > @as(u64, 1) << @min( + min_part_log2_stride, + alignment.toLog2Units(), + @ctz(prev_part.offset), + )) break :combine; + prev_part.size = combined_size; + prev_part.signedness = null; + prev_part.is_vector &= field_is_vector; + continue; + } + parts[parts_len] = .{ + .offset = field_begin, + .size = field_size, + .signedness = field_signedness, + .is_vector = field_is_vector, + }; + parts_len += 1; + } + vi.setParts(isel, parts_len); + for (parts[0..parts_len]) |part| { + const subpart_vi = vi.addPart(isel, part.offset - offset, part.size); + if (part.signedness) |signedness| subpart_vi.setSignedness(isel, signedness); + if (part.is_vector) subpart_vi.setIsVector(isel); + } + }, + .tuple_type => |tuple_type| { + const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; + if (tuple_type.types.len > Value.max_parts and + (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) + return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); + const alignment = vi.alignment(isel); + const Part = struct { offset: u64, size: u64, is_vector: bool }; + var parts: [Value.max_parts]Part = undefined; + var parts_len: Value.PartsLen = 0; + var field_end: u64 = 0; + for (tuple_type.types.get(ip), tuple_type.values.get(ip)) |field_type, field_value| { + if (field_value != .none) continue; + const field_ty: ZigType = .fromInterned(field_type); + const field_begin = field_ty.abiAlignment(zcu).forward(field_end); + if (field_begin >= offset + size) break; + const field_size = field_ty.abiSize(zcu); + if (field_size == 0) continue; + field_end = field_begin + field_size; + if (field_end <= offset) continue; + if (offset >= field_begin and offset + size <= field_begin + field_size) { + ty = field_ty; + ty_size = field_size; + offset -= field_begin; + continue :type_key ip.indexToKey(field_ty.toIntern()); + } + const field_is_vector = field_size <= 16 and + CallAbiIterator.homogeneousAggregateBaseType(zcu, field_ty.toIntern()) != null; + if (parts_len > 0) combine: { + const prev_part = &parts[parts_len - 1]; + const combined_size = field_end - prev_part.offset; + if (combined_size > @as(u64, 1) << @min( + min_part_log2_stride, + alignment.toLog2Units(), + @ctz(prev_part.offset), + )) break :combine; + prev_part.size = combined_size; + prev_part.is_vector &= field_is_vector; + continue; + } + parts[parts_len] = .{ .offset = field_begin, .size = field_size, .is_vector = field_is_vector }; + parts_len += 1; + } + vi.setParts(isel, parts_len); + for (parts[0..parts_len]) |part| { + const subpart_vi = vi.addPart(isel, part.offset - offset, part.size); + if (part.is_vector) subpart_vi.setIsVector(isel); + } + }, + .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque }, + .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty), + .error_set_type, + .inferred_error_set_type, + => continue :type_key .{ .simple_type = .anyerror }, + .undef, + .simple_value, + .variable, + .@"extern", + .func, + .int, + .err, + .error_union, + .enum_literal, + .enum_tag, + .empty_enum_value, + .float, + .ptr, + .slice, + .opt, + .aggregate, + .un, + .memoized_call, + => unreachable, // values, not types + } + } + it.next_offset = next_offset + size; + return .{ .offset = next_part_offset - next_offset, .vi = vi }; + } + + fn only(it: *FieldPartIterator, isel: *Select) !?Value.Index { + const part = try it.next(isel); + assert(part.?.offset == 0); + return if (try it.next(isel)) |_| null else part.?.vi; + } + }; + + const Materialize = struct { + vi: Value.Index, + ra: Register.Alias, + + fn finish(mat: Value.Materialize, isel: *Select) error{ OutOfMemory, CodegenFail }!void { + const live_vi = isel.live_registers.getPtr(mat.ra); + assert(live_vi.* == .allocating); + var vi = mat.vi; + var offset: i65 = 0; + const size = mat.vi.size(isel); + free: while (true) { + if (vi.register(isel)) |ra| { + if (ra != mat.ra) break :free try isel.emit(if (vi == mat.vi) if (mat.ra.isVector()) switch (size) { + else => unreachable, + 2 => .fmov(mat.ra.h(), .{ .register = ra.h() }), + 4 => .fmov(mat.ra.s(), .{ .register = ra.s() }), + 8 => .fmov(mat.ra.d(), .{ .register = ra.d() }), + 16 => .orr(mat.ra.@"16b"(), ra.@"16b"(), .{ .register = ra.@"16b"() }), + } else switch (size) { + else => unreachable, + 1...4 => .orr(mat.ra.w(), .wzr, .{ .register = ra.w() }), + 5...8 => .orr(mat.ra.x(), .xzr, .{ .register = ra.x() }), + } else switch (offset + size) { + else => unreachable, + 1...4 => |end_offset| switch (mat.vi.signedness(isel)) { + .signed => .sbfm(mat.ra.w(), ra.w(), .{ + .N = .word, + .immr = @intCast(8 * offset), + .imms = @intCast(8 * end_offset - 1), + }), + .unsigned => .ubfm(mat.ra.w(), ra.w(), .{ + .N = .word, + .immr = @intCast(8 * offset), + .imms = @intCast(8 * end_offset - 1), + }), + }, + 5...8 => |end_offset| switch (mat.vi.signedness(isel)) { + .signed => .sbfm(mat.ra.x(), ra.x(), .{ + .N = .doubleword, + .immr = @intCast(8 * offset), + .imms = @intCast(8 * end_offset - 1), + }), + .unsigned => .ubfm(mat.ra.x(), ra.x(), .{ + .N = .doubleword, + .immr = @intCast(8 * offset), + .imms = @intCast(8 * end_offset - 1), + }), + }, + }); + mat.vi.get(isel).location_payload.small.register = mat.ra; + live_vi.* = mat.vi; + return; + } + offset += vi.get(isel).offset_from_parent; + switch (vi.parent(isel)) { + .unallocated => { + mat.vi.get(isel).location_payload.small.register = mat.ra; + live_vi.* = mat.vi; + return; + }, + .stack_slot => |stack_slot| { + offset += stack_slot.offset; + break :free try isel.emit(switch (size) { + else => unreachable, + 1 => if (mat.ra.isVector()) .ldr(mat.ra.b(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }) else switch (mat.vi.signedness(isel)) { + .signed => .ldrsb(mat.ra.w(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }), + .unsigned => .ldrb(mat.ra.w(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }), + }, + 2 => if (mat.ra.isVector()) .ldr(mat.ra.h(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }) else switch (mat.vi.signedness(isel)) { + .signed => .ldrsh(mat.ra.w(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }), + .unsigned => .ldrh(mat.ra.w(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }), + }, + 4 => .ldr(if (mat.ra.isVector()) mat.ra.s() else mat.ra.w(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }), + 8 => .ldr(if (mat.ra.isVector()) mat.ra.d() else mat.ra.x(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }), + 16 => .ldr(mat.ra.q(), .{ .unsigned_offset = .{ + .base = stack_slot.base.x(), + .offset = @intCast(offset), + } }), + }); + }, + .address => |base_vi| { + const base_mat = try base_vi.matReg(isel); + try isel.emit(switch (size) { + else => unreachable, + 1 => if (mat.ra.isVector()) .ldr(mat.ra.b(), .{ .unsigned_offset = .{ + .base = base_mat.ra.x(), + .offset = @intCast(offset), + } }) else switch (mat.vi.signedness(isel)) { + .signed => .ldrsb(mat.ra.w(), .{ .unsigned_offset = .{ + .base = base_mat.ra.x(), + .offset = @intCast(offset), + } }), + .unsigned => .ldrb(mat.ra.w(), .{ .unsigned_offset = .{ + .base = base_mat.ra.x(), + .offset = @intCast(offset), + } }), + }, + 2 => if (mat.ra.isVector()) .ldr(mat.ra.h(), .{ .unsigned_offset = .{ + .base = base_mat.ra.x(), + .offset = @intCast(offset), + } }) else switch (mat.vi.signedness(isel)) { + .signed => .ldrsh(mat.ra.w(), .{ .unsigned_offset = .{ + .base = base_mat.ra.x(), + .offset = @intCast(offset), + } }), + .unsigned => .ldrh(mat.ra.w(), .{ .unsigned_offset = .{ + .base = base_mat.ra.x(), + .offset = @intCast(offset), + } }), + }, + 4 => .ldr(if (mat.ra.isVector()) mat.ra.s() else mat.ra.w(), .{ .unsigned_offset = .{ + .base = base_mat.ra.x(), + .offset = @intCast(offset), + } }), + 8 => .ldr(if (mat.ra.isVector()) mat.ra.d() else mat.ra.x(), .{ .unsigned_offset = .{ + .base = base_mat.ra.x(), + .offset = @intCast(offset), + } }), + 16 => .ldr(mat.ra.q(), .{ .unsigned_offset = .{ + .base = base_mat.ra.x(), + .offset = @intCast(offset), + } }), + }); + break :free try base_mat.finish(isel); + }, + .value => |parent_vi| vi = parent_vi, + .constant => |initial_constant| { + const zcu = isel.pt.zcu; + const ip = &zcu.intern_pool; + var constant = initial_constant.toIntern(); + var constant_key = ip.indexToKey(constant); + while (true) { + constant_key: switch (constant_key) { + .int_type, + .ptr_type, + .array_type, + .vector_type, + .opt_type, + .anyframe_type, + .error_union_type, + .simple_type, + .struct_type, + .tuple_type, + .union_type, + .opaque_type, + .enum_type, + .func_type, + .error_set_type, + .inferred_error_set_type, + + .enum_literal, + .empty_enum_value, + .memoized_call, + => unreachable, // not a runtime value + .undef => break :free try isel.emit(if (mat.ra.isVector()) .movi(switch (size) { + else => unreachable, + 1...8 => mat.ra.@"8b"(), + 9...16 => mat.ra.@"16b"(), + }, 0xaa, .{ .lsl = 0 }) else switch (size) { + else => unreachable, + 1...4 => .orr(mat.ra.w(), .wzr, .{ .immediate = .{ + .N = .word, + .immr = 0b000001, + .imms = 0b111100, + } }), + 5...8 => .orr(mat.ra.x(), .xzr, .{ .immediate = .{ + .N = .word, + .immr = 0b000001, + .imms = 0b111100, + } }), + }), + .simple_value => |simple_value| switch (simple_value) { + .undefined, .void, .null, .empty_tuple, .@"unreachable" => unreachable, + .true => continue :constant_key .{ .int = .{ + .ty = .bool_type, + .storage = .{ .u64 = 1 }, + } }, + .false => continue :constant_key .{ .int = .{ + .ty = .bool_type, + .storage = .{ .u64 = 0 }, + } }, + }, + .int => |int| break :free storage: switch (int.storage) { + .u64 => |imm| try isel.movImmediate(switch (size) { + else => unreachable, + 1...4 => mat.ra.w(), + 5...8 => mat.ra.x(), + }, @bitCast(std.math.shr(u64, imm, 8 * offset))), + .i64 => |imm| switch (size) { + else => unreachable, + 1...4 => try isel.movImmediate(mat.ra.w(), @as(u32, @bitCast(@as(i32, @truncate(std.math.shr(i64, imm, 8 * offset)))))), + 5...8 => try isel.movImmediate(mat.ra.x(), @bitCast(std.math.shr(i64, imm, 8 * offset))), + }, + .big_int => |big_int| { + assert(size == 8); + var imm: u64 = 0; + const limb_bits = @bitSizeOf(std.math.big.Limb); + const limbs = @divExact(64, limb_bits); + var limb_index: usize = @intCast(@divExact(offset, @divExact(limb_bits, 8)) + limbs); + for (0..limbs) |_| { + limb_index -= 1; + if (limb_index >= big_int.limbs.len) continue; + if (limb_bits < 64) imm <<= limb_bits; + imm |= big_int.limbs[limb_index]; + } + if (!big_int.positive) { + limb_index = @min(limb_index, big_int.limbs.len); + imm = while (limb_index > 0) { + limb_index -= 1; + if (big_int.limbs[limb_index] != 0) break ~imm; + } else -%imm; + } + try isel.movImmediate(mat.ra.x(), imm); + }, + .lazy_align => |ty| continue :storage .{ + .u64 = ZigType.fromInterned(ty).abiAlignment(zcu).toByteUnits().?, + }, + .lazy_size => |ty| continue :storage .{ + .u64 = ZigType.fromInterned(ty).abiSize(zcu), + }, + }, + .err => |err| continue :constant_key .{ .int = .{ + .ty = err.ty, + .storage = .{ .u64 = ip.getErrorValueIfExists(err.name).? }, + } }, + .error_union => |error_union| { + const error_union_type = ip.indexToKey(error_union.ty).error_union_type; + const payload_ty: ZigType = .fromInterned(error_union_type.payload_type); + if (!ip.isNoReturn(error_union_type.error_set_type) and + offset == codegen.errUnionErrorOffset(payload_ty, zcu)) + { + offset = 0; + continue :constant_key switch (error_union.val) { + .err_name => |err_name| .{ .err = .{ + .ty = error_union_type.error_set_type, + .name = err_name, + } }, + .payload => .{ .int = .{ + .ty = error_union_type.error_set_type, + .storage = .{ .u64 = 0 }, + } }, + }; + } + assert(payload_ty.hasRuntimeBitsIgnoreComptime(zcu)); + offset -= @intCast(codegen.errUnionPayloadOffset(payload_ty, zcu)); + switch (error_union.val) { + .err_name => continue :constant_key .{ .undef = error_union_type.payload_type }, + .payload => |payload| { + constant = payload; + constant_key = ip.indexToKey(payload); + continue :constant_key constant_key; + }, + } + }, + .enum_tag => |enum_tag| continue :constant_key .{ .int = ip.indexToKey(enum_tag.int).int }, + .float => |float| storage: switch (float.storage) { + .f16 => |imm| { + if (!mat.ra.isVector()) continue :constant_key .{ .int = .{ + .ty = .u16_type, + .storage = .{ .u64 = @as(u16, @bitCast(imm)) }, + } }; + const feat_fp16 = isel.target.cpu.has(.aarch64, .fullfp16); + if (feat_fp16) { + const Repr = std.math.FloatRepr(f16); + const repr: Repr = @bitCast(imm); + if (repr.mantissa & std.math.maxInt(Repr.Mantissa) >> 5 == 0 and switch (repr.exponent) { + .denormal, .infinite => false, + else => std.math.cast(i3, repr.exponent.unbias() - 1) != null, + }) break :free try isel.emit(.fmov(mat.ra.h(), .{ .immediate = imm })); + } + const bits: u16 = @bitCast(imm); + if (bits == 0) break :free try isel.emit(.movi(mat.ra.d(), 0b00000000, .replicate)); + if (bits & std.math.maxInt(u8) == 0) break :free try isel.emit(.movi( + mat.ra.@"4h"(), + @intCast(@shrExact(bits, 8)), + .{ .lsl = 8 }, + )); + const temp_ra = try isel.allocIntReg(); + defer isel.freeReg(temp_ra); + try isel.emit(.fmov(if (feat_fp16) mat.ra.h() else mat.ra.s(), .{ .register = temp_ra.w() })); + break :free try isel.movImmediate(temp_ra.w(), bits); + }, + .f32 => |imm| { + if (!mat.ra.isVector()) continue :constant_key .{ .int = .{ + .ty = .u32_type, + .storage = .{ .u64 = @as(u32, @bitCast(imm)) }, + } }; + const Repr = std.math.FloatRepr(f32); + const repr: Repr = @bitCast(imm); + if (repr.mantissa & std.math.maxInt(Repr.Mantissa) >> 5 == 0 and switch (repr.exponent) { + .denormal, .infinite => false, + else => std.math.cast(i3, repr.exponent.unbias() - 1) != null, + }) break :free try isel.emit(.fmov(mat.ra.s(), .{ .immediate = @floatCast(imm) })); + const bits: u32 = @bitCast(imm); + if (bits == 0) break :free try isel.emit(.movi(mat.ra.d(), 0b00000000, .replicate)); + if (bits & std.math.maxInt(u24) == 0) break :free try isel.emit(.movi( + mat.ra.@"2s"(), + @intCast(@shrExact(bits, 24)), + .{ .lsl = 24 }, + )); + const temp_ra = try isel.allocIntReg(); + defer isel.freeReg(temp_ra); + try isel.emit(.fmov(mat.ra.s(), .{ .register = temp_ra.w() })); + break :free try isel.movImmediate(temp_ra.w(), bits); + }, + .f64 => |imm| { + if (!mat.ra.isVector()) continue :constant_key .{ .int = .{ + .ty = .u64_type, + .storage = .{ .u64 = @as(u64, @bitCast(imm)) }, + } }; + const Repr = std.math.FloatRepr(f64); + const repr: Repr = @bitCast(imm); + if (repr.mantissa & std.math.maxInt(Repr.Mantissa) >> 5 == 0 and switch (repr.exponent) { + .denormal, .infinite => false, + else => std.math.cast(i3, repr.exponent.unbias() - 1) != null, + }) break :free try isel.emit(.fmov(mat.ra.d(), .{ .immediate = @floatCast(imm) })); + const bits: u64 = @bitCast(imm); + if (bits == 0) break :free try isel.emit(.movi(mat.ra.d(), 0b00000000, .replicate)); + const temp_ra = try isel.allocIntReg(); + defer isel.freeReg(temp_ra); + try isel.emit(.fmov(mat.ra.d(), .{ .register = temp_ra.x() })); + break :free try isel.movImmediate(temp_ra.x(), bits); + }, + .f80 => |imm| break :free try isel.movImmediate( + mat.ra.x(), + @truncate(std.math.shr(u80, @bitCast(imm), 8 * offset)), + ), + .f128 => |imm| switch (ZigType.fromInterned(float.ty).floatBits(isel.target)) { + else => unreachable, + 16 => continue :storage .{ .f16 = @floatCast(imm) }, + 32 => continue :storage .{ .f32 = @floatCast(imm) }, + 64 => continue :storage .{ .f64 = @floatCast(imm) }, + 128 => { + const bits: u128 = @bitCast(imm); + const hi64: u64 = @intCast(bits >> 64); + const lo64: u64 = @truncate(bits >> 0); + const temp_ra = try isel.allocIntReg(); + defer isel.freeReg(temp_ra); + switch (hi64) { + 0 => {}, + else => { + try isel.emit(.fmov(mat.ra.@"d[]"(1), .{ .register = temp_ra.x() })); + try isel.movImmediate(temp_ra.x(), hi64); + }, + } + break :free switch (lo64) { + 0 => try isel.emit(.movi(switch (hi64) { + else => mat.ra.d(), + 0 => mat.ra.@"2d"(), + }, 0b00000000, .replicate)), + else => { + try isel.emit(.fmov(mat.ra.d(), .{ .register = temp_ra.x() })); + try isel.movImmediate(temp_ra.x(), lo64); + }, + }; + }, + }, + }, + .ptr => |ptr| { + assert(offset == 0 and size == 8); + break :free switch (ptr.base_addr) { + .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) { + false => { + try isel.nav_relocs.append(zcu.gpa, .{ + .nav = nav, + .reloc = .{ + .label = @intCast(isel.instructions.items.len), + .addend = ptr.byte_offset, + }, + }); + try isel.emit(.adr(mat.ra.x(), 0)); + }, + true => { + try isel.nav_relocs.append(zcu.gpa, .{ + .nav = nav, + .reloc = .{ + .label = @intCast(isel.instructions.items.len), + .addend = ptr.byte_offset, + }, + }); + try isel.emit(.add(mat.ra.x(), mat.ra.x(), .{ .immediate = 0 })); + try isel.nav_relocs.append(zcu.gpa, .{ + .nav = nav, + .reloc = .{ + .label = @intCast(isel.instructions.items.len), + .addend = ptr.byte_offset, + }, + }); + try isel.emit(.adrp(mat.ra.x(), 0)); + }, + } else continue :constant_key .{ .int = .{ + .ty = .usize_type, + .storage = .{ .u64 = isel.pt.navAlignment(nav).forward(0xaaaaaaaaaaaaaaaa) }, + } }, + .uav => |uav| if (ZigType.fromInterned(ip.typeOf(uav.val)).isFnOrHasRuntimeBits(zcu)) switch (true) { + false => { + try isel.uav_relocs.append(zcu.gpa, .{ + .uav = uav, + .reloc = .{ + .label = @intCast(isel.instructions.items.len), + .addend = ptr.byte_offset, + }, + }); + try isel.emit(.adr(mat.ra.x(), 0)); + }, + true => { + try isel.uav_relocs.append(zcu.gpa, .{ + .uav = uav, + .reloc = .{ + .label = @intCast(isel.instructions.items.len), + .addend = ptr.byte_offset, + }, + }); + try isel.emit(.add(mat.ra.x(), mat.ra.x(), .{ .immediate = 0 })); + try isel.uav_relocs.append(zcu.gpa, .{ + .uav = uav, + .reloc = .{ + .label = @intCast(isel.instructions.items.len), + .addend = ptr.byte_offset, + }, + }); + try isel.emit(.adrp(mat.ra.x(), 0)); + }, + } else continue :constant_key .{ .int = .{ + .ty = .usize_type, + .storage = .{ .u64 = ZigType.fromInterned(uav.orig_ty).ptrAlignment(zcu).forward(0xaaaaaaaaaaaaaaaa) }, + } }, + .int => continue :constant_key .{ .int = .{ + .ty = .usize_type, + .storage = .{ .u64 = ptr.byte_offset }, + } }, + .eu_payload => |base| { + var base_ptr = ip.indexToKey(base).ptr; + const eu_ty = ip.indexToKey(base_ptr.ty).ptr_type.child; + const payload_ty = ip.indexToKey(eu_ty).error_union_type.payload_type; + base_ptr.byte_offset += codegen.errUnionPayloadOffset(.fromInterned(payload_ty), zcu); + continue :constant_key .{ .ptr = base_ptr }; + }, + .opt_payload => |base| continue :constant_key .{ .ptr = ip.indexToKey(base).ptr }, + .field => |field| { + var base_ptr = ip.indexToKey(field.base).ptr; + const agg_ty: ZigType = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child); + base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field.index), zcu); + continue :constant_key .{ .ptr = base_ptr }; + }, + .comptime_alloc, .comptime_field, .arr_elem => unreachable, + }; + }, + .slice => |slice| switch (offset) { + 0 => continue :constant_key .{ .ptr = ip.indexToKey(slice.ptr).ptr }, + else => { + assert(offset == @divExact(isel.target.ptrBitWidth(), 8)); + offset = 0; + continue :constant_key .{ .int = ip.indexToKey(slice.len).int }; + }, + }, + .opt => |opt| { + const child_ty = ip.indexToKey(opt.ty).opt_type; + const child_size = ZigType.fromInterned(child_ty).abiSize(zcu); + if (offset == child_size and size == 1) { + offset = 0; + continue :constant_key .{ .simple_value = switch (opt.val) { + .none => .false, + else => .true, + } }; + } + const opt_ty: ZigType = .fromInterned(opt.ty); + if (offset + size <= child_size) continue :constant_key switch (opt.val) { + .none => if (opt_ty.optionalReprIsPayload(zcu)) .{ .int = .{ + .ty = opt.ty, + .storage = .{ .u64 = 0 }, + } } else .{ .undef = child_ty }, + else => |child| { + constant = child; + constant_key = ip.indexToKey(child); + continue :constant_key constant_key; + }, + }; + }, + .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) { + else => unreachable, + .array_type => |array_type| { + const elem_size = ZigType.fromInterned(array_type.child).abiSize(zcu); + const elem_offset = @mod(offset, elem_size); + if (size <= elem_size - elem_offset) { + defer offset = elem_offset; + continue :constant_key switch (aggregate.storage) { + .bytes => |bytes| .{ .int = .{ .ty = .u8_type, .storage = .{ + .u64 = bytes.toSlice(array_type.lenIncludingSentinel(), ip)[@intCast(@divFloor(offset, elem_size))], + } } }, + .elems => |elems| { + constant = elems[@intCast(@divFloor(offset, elem_size))]; + constant_key = ip.indexToKey(constant); + continue :constant_key constant_key; + }, + .repeated_elem => |repeated_elem| { + constant = repeated_elem; + constant_key = ip.indexToKey(repeated_elem); + continue :constant_key constant_key; + }, + }; + } + }, + .vector_type => {}, + .struct_type => { + const loaded_struct = ip.loadStructType(aggregate.ty); + switch (loaded_struct.layout) { + .auto => { + var field_offset: u64 = 0; + var field_it = loaded_struct.iterateRuntimeOrder(ip); + while (field_it.next()) |field_index| { + if (loaded_struct.fieldIsComptime(ip, field_index)) continue; + const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); + field_offset = field_ty.structFieldAlignment( + loaded_struct.fieldAlign(ip, field_index), + loaded_struct.layout, + zcu, + ).forward(field_offset); + const field_size = field_ty.abiSize(zcu); + if (offset >= field_offset and offset + size <= field_offset + field_size) { + offset -= field_offset; + constant = switch (aggregate.storage) { + .bytes => unreachable, + .elems => |elems| elems[field_index], + .repeated_elem => |repeated_elem| repeated_elem, + }; + constant_key = ip.indexToKey(constant); + continue :constant_key constant_key; + } + field_offset += field_size; + } + }, + .@"extern", .@"packed" => {}, + } + }, + .tuple_type => |tuple_type| { + var field_offset: u64 = 0; + for (tuple_type.types.get(ip), tuple_type.values.get(ip), 0..) |field_type, field_value, field_index| { + if (field_value != .none) continue; + const field_ty: ZigType = .fromInterned(field_type); + field_offset = field_ty.abiAlignment(zcu).forward(field_offset); + const field_size = field_ty.abiSize(zcu); + if (offset >= field_offset and offset + size <= field_offset + field_size) { + offset -= field_offset; + constant = switch (aggregate.storage) { + .bytes => unreachable, + .elems => |elems| elems[field_index], + .repeated_elem => |repeated_elem| repeated_elem, + }; + constant_key = ip.indexToKey(constant); + continue :constant_key constant_key; + } + field_offset += field_size; + } + }, + }, + else => {}, + } + var buffer: [16]u8 = @splat(0); + if (ZigType.fromInterned(constant_key.typeOf()).abiSize(zcu) <= buffer.len and + try isel.writeToMemory(.fromInterned(constant), &buffer)) + { + constant_key = if (mat.ra.isVector()) .{ .float = switch (size) { + else => unreachable, + 2 => .{ .ty = .f16_type, .storage = .{ .f16 = @bitCast(std.mem.readInt( + u16, + buffer[@intCast(offset)..][0..2], + isel.target.cpu.arch.endian(), + )) } }, + 4 => .{ .ty = .f32_type, .storage = .{ .f32 = @bitCast(std.mem.readInt( + u32, + buffer[@intCast(offset)..][0..4], + isel.target.cpu.arch.endian(), + )) } }, + 8 => .{ .ty = .f64_type, .storage = .{ .f64 = @bitCast(std.mem.readInt( + u64, + buffer[@intCast(offset)..][0..8], + isel.target.cpu.arch.endian(), + )) } }, + 16 => .{ .ty = .f128_type, .storage = .{ .f128 = @bitCast(std.mem.readInt( + u128, + buffer[@intCast(offset)..][0..16], + isel.target.cpu.arch.endian(), + )) } }, + } } else .{ .int = .{ + .ty = .u64_type, + .storage = .{ .u64 = switch (size) { + else => unreachable, + inline 1...8 => |ct_size| std.mem.readInt( + @Type(.{ .int = .{ .signedness = .unsigned, .bits = 8 * ct_size } }), + buffer[@intCast(offset)..][0..ct_size], + isel.target.cpu.arch.endian(), + ), + } }, + } }; + offset = 0; + continue; + } + return isel.fail("unsupported value <{f}, {f}>", .{ + isel.fmtType(.fromInterned(constant_key.typeOf())), + isel.fmtConstant(.fromInterned(constant)), + }); + } + }, + } + } + live_vi.* = .free; + } + }; +}; +fn initValue(isel: *Select, ty: ZigType) Value.Index { + const zcu = isel.pt.zcu; + return isel.initValueAdvanced(ty.abiAlignment(zcu), 0, ty.abiSize(zcu)); +} +fn initValueAdvanced( + isel: *Select, + parent_alignment: InternPool.Alignment, + offset_from_parent: u64, + size: u64, +) Value.Index { + defer isel.values.addOneAssumeCapacity().* = .{ + .refs = 0, + .flags = .{ + .alignment = .fromLog2Units(@min(parent_alignment.toLog2Units(), @ctz(offset_from_parent))), + .parent_tag = .unallocated, + .location_tag = if (size > 16) .large else .small, + .parts_len_minus_one = 0, + }, + .offset_from_parent = offset_from_parent, + .parent_payload = .{ .unallocated = {} }, + .location_payload = if (size > 16) .{ .large = .{ + .size = size, + } } else .{ .small = .{ + .size = @intCast(size), + .signedness = .unsigned, + .is_vector = false, + .hint = .zr, + .register = .zr, + } }, + .parts = undefined, + }; + return @enumFromInt(isel.values.items.len); +} +pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void { + errdefer |err| @panic(@errorName(err)); + const stderr = std.debug.lockStderrWriter(&.{}); + defer std.debug.unlockStderrWriter(); + + const zcu = isel.pt.zcu; + const gpa = zcu.gpa; + const ip = &zcu.intern_pool; + const nav = ip.getNav(isel.nav_index); + + var reverse_live_values: std.AutoArrayHashMapUnmanaged(Value.Index, std.ArrayListUnmanaged(Air.Inst.Index)) = .empty; + defer { + for (reverse_live_values.values()) |*list| list.deinit(gpa); + reverse_live_values.deinit(gpa); + } + { + try reverse_live_values.ensureTotalCapacity(gpa, isel.live_values.count()); + var live_val_it = isel.live_values.iterator(); + while (live_val_it.next()) |live_val_entry| switch (live_val_entry.value_ptr.*) { + _ => { + const gop = reverse_live_values.getOrPutAssumeCapacity(live_val_entry.value_ptr.*); + if (!gop.found_existing) gop.value_ptr.* = .empty; + try gop.value_ptr.append(gpa, live_val_entry.key_ptr.*); + }, + .allocating, .free => unreachable, + }; + } + + var reverse_live_registers: std.AutoHashMapUnmanaged(Value.Index, Register.Alias) = .empty; + defer reverse_live_registers.deinit(gpa); + { + try reverse_live_registers.ensureTotalCapacity(gpa, @typeInfo(Register.Alias).@"enum".fields.len); + var live_reg_it = isel.live_registers.iterator(); + while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) { + _ => reverse_live_registers.putAssumeCapacityNoClobber(live_reg_entry.value.*, live_reg_entry.key), + .allocating, .free => {}, + }; + } + + var roots: std.AutoArrayHashMapUnmanaged(Value.Index, u32) = .empty; + defer roots.deinit(gpa); + { + try roots.ensureTotalCapacity(gpa, isel.values.items.len); + var vi: Value.Index = @enumFromInt(isel.values.items.len); + while (@intFromEnum(vi) > 0) { + vi = @enumFromInt(@intFromEnum(vi) - 1); + if (which == .only_referenced and vi.get(isel).refs == 0) continue; + while (true) switch (vi.parent(isel)) { + .unallocated, .stack_slot, .constant => break, + .value => |parent_vi| vi = parent_vi, + .address => |address_vi| break roots.putAssumeCapacity(address_vi, 0), + }; + roots.putAssumeCapacity(vi, 0); + } + } + + try stderr.print("# Begin {s} Value Dump: {f}:\n", .{ @typeName(Select), nav.fqn.fmt(ip) }); + while (roots.pop()) |root_entry| { + const vi = root_entry.key; + const value = vi.get(isel); + try stderr.splatByteAll(' ', 2 * (@as(usize, 1) + root_entry.value)); + try stderr.print("${d}", .{@intFromEnum(vi)}); + { + var first = true; + if (reverse_live_values.get(vi)) |aiis| for (aiis.items) |aii| { + if (aii == Block.main) { + try stderr.print("{s}%main", .{if (first) " <- " else ", "}); + } else { + try stderr.print("{s}%{d}", .{ if (first) " <- " else ", ", @intFromEnum(aii) }); + } + first = false; + }; + if (reverse_live_registers.get(vi)) |ra| { + try stderr.print("{s}{s}", .{ if (first) " <- " else ", ", @tagName(ra) }); + first = false; + } + } + try stderr.writeByte(':'); + switch (value.flags.parent_tag) { + .unallocated => if (value.offset_from_parent != 0) try stderr.print(" +0x{x}", .{value.offset_from_parent}), + .stack_slot => { + try stderr.print(" [{s}, #{s}0x{x}", .{ + @tagName(value.parent_payload.stack_slot.base), + if (value.parent_payload.stack_slot.offset < 0) "-" else "", + @abs(value.parent_payload.stack_slot.offset), + }); + if (value.offset_from_parent != 0) try stderr.print("+0x{x}", .{value.offset_from_parent}); + try stderr.writeByte(']'); + }, + .value => try stderr.print(" ${d}+0x{x}", .{ @intFromEnum(value.parent_payload.value), value.offset_from_parent }), + .address => try stderr.print(" ${d}[0x{x}]", .{ @intFromEnum(value.parent_payload.address), value.offset_from_parent }), + .constant => try stderr.print(" <{f}, {f}>", .{ + isel.fmtType(value.parent_payload.constant.typeOf(zcu)), + isel.fmtConstant(value.parent_payload.constant), + }), + } + try stderr.print(" align({s})", .{@tagName(value.flags.alignment)}); + switch (value.flags.location_tag) { + .large => try stderr.print(" size=0x{x} large", .{value.location_payload.large.size}), + .small => { + const loc = value.location_payload.small; + try stderr.print(" size=0x{x}", .{loc.size}); + switch (loc.signedness) { + .unsigned => {}, + .signed => try stderr.writeAll(" signed"), + } + if (loc.hint != .zr) try stderr.print(" hint={s}", .{@tagName(loc.hint)}); + if (loc.register != .zr) try stderr.print(" loc={s}", .{@tagName(loc.register)}); + }, + } + try stderr.print(" refs={d}\n", .{value.refs}); + + var part_index = value.flags.parts_len_minus_one; + if (part_index > 0) while (true) : (part_index -= 1) { + roots.putAssumeCapacityNoClobber( + @enumFromInt(@intFromEnum(value.parts) + part_index), + root_entry.value + 1, + ); + if (part_index == 0) break; + }; + } + try stderr.print("# End {s} Value Dump: {f}\n\n", .{ @typeName(Select), nav.fqn.fmt(ip) }); +} + +fn hasRepeatedByteRepr(isel: *Select, constant: Constant) error{OutOfMemory}!?u8 { + const zcu = isel.pt.zcu; + const ty = constant.typeOf(zcu); + const abi_size = std.math.cast(usize, ty.abiSize(zcu)) orelse return null; + const byte_buffer = try zcu.gpa.alloc(u8, abi_size); + defer zcu.gpa.free(byte_buffer); + return if (try isel.writeToMemory(constant, byte_buffer) and + std.mem.allEqual(u8, byte_buffer[1..], byte_buffer[0])) byte_buffer[0] else null; +} + +fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMemory}!bool { + const zcu = isel.pt.zcu; + const ip = &zcu.intern_pool; + switch (ip.indexToKey(constant.toIntern())) { + .int_type, + .ptr_type, + .array_type, + .vector_type, + .opt_type, + .anyframe_type, + .error_union_type, + .simple_type, + .struct_type, + .tuple_type, + .union_type, + .opaque_type, + .enum_type, + .func_type, + .error_set_type, + .inferred_error_set_type, + + .enum_literal, + .empty_enum_value, + .memoized_call, + => unreachable, // not a runtime value + .opt => |opt| { + const child_size: usize = @intCast(ZigType.fromInterned(ip.indexToKey(opt.ty).opt_type).abiSize(zcu)); + switch (opt.val) { + .none => if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) { + buffer[child_size] = @intFromBool(false); + } else @memset(buffer[0..child_size], 0x00), + else => |child_constant| { + if (!try isel.writeToMemory(.fromInterned(child_constant), buffer[0..child_size])) return false; + if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) buffer[child_size] = @intFromBool(true); + }, + } + return true; + }, + .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) { + else => unreachable, + .array_type => |array_type| { + var elem_offset: usize = 0; + const elem_size: usize = @intCast(ZigType.fromInterned(array_type.child).abiSize(zcu)); + const len_including_sentinel: usize = @intCast(array_type.lenIncludingSentinel()); + switch (aggregate.storage) { + .bytes => |bytes| @memcpy(buffer[0..len_including_sentinel], bytes.toSlice(len_including_sentinel, ip)), + .elems => |elems| for (elems) |elem| { + if (!try isel.writeToMemory(.fromInterned(elem), buffer[elem_offset..][0..elem_size])) return false; + elem_offset += elem_size; + }, + .repeated_elem => |repeated_elem| for (0..len_including_sentinel) |_| { + if (!try isel.writeToMemory(.fromInterned(repeated_elem), buffer[elem_offset..][0..elem_size])) return false; + elem_offset += elem_size; + }, + } + return true; + }, + .vector_type => {}, + .struct_type => { + const loaded_struct = ip.loadStructType(aggregate.ty); + switch (loaded_struct.layout) { + .auto => { + var field_offset: u64 = 0; + var field_it = loaded_struct.iterateRuntimeOrder(ip); + while (field_it.next()) |field_index| { + if (loaded_struct.fieldIsComptime(ip, field_index)) continue; + const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); + field_offset = field_ty.structFieldAlignment( + loaded_struct.fieldAlign(ip, field_index), + loaded_struct.layout, + zcu, + ).forward(field_offset); + const field_size = field_ty.abiSize(zcu); + if (!try isel.writeToMemory(.fromInterned(switch (aggregate.storage) { + .bytes => unreachable, + .elems => |elems| elems[field_index], + .repeated_elem => |repeated_elem| repeated_elem, + }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false; + field_offset += field_size; + } + return true; + }, + .@"extern", .@"packed" => {}, + } + }, + .tuple_type => |tuple_type| { + var field_offset: u64 = 0; + for (tuple_type.types.get(ip), tuple_type.values.get(ip), 0..) |field_type, field_value, field_index| { + if (field_value != .none) continue; + const field_ty: ZigType = .fromInterned(field_type); + field_offset = field_ty.abiAlignment(zcu).forward(field_offset); + const field_size = field_ty.abiSize(zcu); + if (!try isel.writeToMemory(.fromInterned(switch (aggregate.storage) { + .bytes => unreachable, + .elems => |elems| elems[field_index], + .repeated_elem => |repeated_elem| repeated_elem, + }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false; + field_offset += field_size; + } + return true; + }, + }, + else => {}, + } + constant.writeToMemory(isel.pt, buffer) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.ReinterpretDeclRef, error.Unimplemented, error.IllDefinedMemoryLayout => return false, + }; + return true; +} + +const TryAllocRegResult = union(enum) { + allocated: Register.Alias, + fill_candidate: Register.Alias, + out_of_registers, +}; + +fn tryAllocIntReg(isel: *Select) TryAllocRegResult { + var failed_result: TryAllocRegResult = .out_of_registers; + var ra: Register.Alias = .r0; + while (true) : (ra = @enumFromInt(@intFromEnum(ra) + 1)) { + if (ra == .r18) continue; // The Platform Register + if (ra == Register.Alias.fp) continue; + const live_vi = isel.live_registers.getPtr(ra); + switch (live_vi.*) { + _ => switch (failed_result) { + .allocated => unreachable, + .fill_candidate => {}, + .out_of_registers => failed_result = .{ .fill_candidate = ra }, + }, + .allocating => {}, + .free => { + live_vi.* = .allocating; + isel.saved_registers.insert(ra); + return .{ .allocated = ra }; + }, + } + if (ra == Register.Alias.lr) return failed_result; + } +} + +fn allocIntReg(isel: *Select) !Register.Alias { + switch (isel.tryAllocIntReg()) { + .allocated => |ra| return ra, + .fill_candidate => |ra| { + assert(try isel.fillMemory(ra)); + const live_vi = isel.live_registers.getPtr(ra); + assert(live_vi.* == .free); + live_vi.* = .allocating; + return ra; + }, + .out_of_registers => return isel.fail("ran out of registers", .{}), + } +} + +fn tryAllocVecReg(isel: *Select) TryAllocRegResult { + var failed_result: TryAllocRegResult = .out_of_registers; + var ra: Register.Alias = .v0; + while (true) : (ra = @enumFromInt(@intFromEnum(ra) + 1)) { + const live_vi = isel.live_registers.getPtr(ra); + switch (live_vi.*) { + _ => switch (failed_result) { + .allocated => unreachable, + .fill_candidate => {}, + .out_of_registers => failed_result = .{ .fill_candidate = ra }, + }, + .allocating => {}, + .free => { + live_vi.* = .allocating; + isel.saved_registers.insert(ra); + return .{ .allocated = ra }; + }, + } + if (ra == Register.Alias.v31) return failed_result; + } +} + +fn allocVecReg(isel: *Select) !Register.Alias { + switch (isel.tryAllocVecReg()) { + .allocated => |ra| return ra, + .fill_candidate => |ra| { + assert(try isel.fillMemory(ra)); + return ra; + }, + .out_of_registers => return isel.fail("ran out of registers", .{}), + } +} + +const RegLock = struct { + ra: Register.Alias, + const empty: RegLock = .{ .ra = .zr }; + fn unlock(lock: RegLock, isel: *Select) void { + switch (lock.ra) { + else => |ra| isel.freeReg(ra), + .zr => {}, + } + } +}; +fn lockReg(isel: *Select, ra: Register.Alias) RegLock { + assert(ra != .zr); + const live_vi = isel.live_registers.getPtr(ra); + assert(live_vi.* == .free); + live_vi.* = .allocating; + return .{ .ra = ra }; +} +fn tryLockReg(isel: *Select, ra: Register.Alias) RegLock { + assert(ra != .zr); + const live_vi = isel.live_registers.getPtr(ra); + switch (live_vi.*) { + _ => unreachable, + .allocating => return .{ .ra = .zr }, + .free => { + live_vi.* = .allocating; + return .{ .ra = ra }; + }, + } +} + +fn freeReg(isel: *Select, ra: Register.Alias) void { + assert(ra != .zr); + const live_vi = isel.live_registers.getPtr(ra); + assert(live_vi.* == .allocating); + live_vi.* = .free; +} + +fn use(isel: *Select, air_ref: Air.Inst.Ref) !Value.Index { + const zcu = isel.pt.zcu; + const ip = &zcu.intern_pool; + try isel.values.ensureUnusedCapacity(zcu.gpa, 1); + const vi, const ty = if (air_ref.toIndex()) |air_inst_index| vi_ty: { + const live_gop = try isel.live_values.getOrPut(zcu.gpa, air_inst_index); + if (live_gop.found_existing) return live_gop.value_ptr.*; + const ty = isel.air.typeOf(air_ref, ip); + const vi = isel.initValue(ty); + tracking_log.debug("${d} <- %{d}", .{ + @intFromEnum(vi), + @intFromEnum(air_inst_index), + }); + live_gop.value_ptr.* = vi.ref(isel); + break :vi_ty .{ vi, ty }; + } else vi_ty: { + const constant: Constant = .fromInterned(air_ref.toInterned().?); + const ty = constant.typeOf(zcu); + const vi = isel.initValue(ty); + tracking_log.debug("${d} <- <{f}, {f}>", .{ + @intFromEnum(vi), + isel.fmtType(ty), + isel.fmtConstant(constant), + }); + vi.setParent(isel, .{ .constant = constant }); + break :vi_ty .{ vi, ty }; + }; + if (ty.isAbiInt(zcu)) { + const int_info = ty.intInfo(zcu); + if (int_info.bits <= 16) vi.setSignedness(isel, int_info.signedness); + } else if (vi.size(isel) <= 16 and + CallAbiIterator.homogeneousAggregateBaseType(zcu, ty.toIntern()) != null) vi.setIsVector(isel); + return vi; +} + +fn fill(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, CodegenFail }!bool { + switch (dst_ra) { + else => {}, + Register.Alias.fp, .zr, .sp, .pc, .fpcr, .fpsr, .ffr => return false, + } + const dst_live_vi = isel.live_registers.getPtr(dst_ra); + const dst_vi = switch (dst_live_vi.*) { + _ => |dst_vi| dst_vi, + .allocating => return false, + .free => return true, + }; + const src_ra = src_ra: { + if (dst_vi.hint(isel)) |hint_ra| { + assert(dst_live_vi.* == dst_vi); + dst_live_vi.* = .allocating; + defer dst_live_vi.* = dst_vi; + if (try isel.fill(hint_ra)) { + isel.saved_registers.insert(hint_ra); + break :src_ra hint_ra; + } + } + switch (if (dst_vi.isVector(isel)) isel.tryAllocVecReg() else isel.tryAllocIntReg()) { + .allocated => |ra| break :src_ra ra, + .fill_candidate, .out_of_registers => return isel.fillMemory(dst_ra), + } + }; + try dst_vi.liveIn(isel, src_ra, comptime &.initFill(.free)); + const src_live_vi = isel.live_registers.getPtr(src_ra); + assert(src_live_vi.* == .allocating); + src_live_vi.* = dst_vi; + return true; +} + +fn fillMemory(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, CodegenFail }!bool { + const dst_live_vi = isel.live_registers.getPtr(dst_ra); + const dst_vi = switch (dst_live_vi.*) { + _ => |dst_vi| dst_vi, + .allocating => return false, + .free => return true, + }; + const dst_vi_ra = &dst_vi.get(isel).location_payload.small.register; + assert(dst_vi_ra.* == dst_ra); + const base_ra = if (dst_ra.isVector()) try isel.allocIntReg() else dst_ra; + defer if (base_ra != dst_ra) isel.freeReg(base_ra); + try isel.emit(switch (dst_vi.size(isel)) { + else => unreachable, + 1 => if (dst_ra.isVector()) + .ldr(dst_ra.b(), .{ .base = base_ra.x() }) + else switch (dst_vi.signedness(isel)) { + .signed => .ldrsb(dst_ra.w(), .{ .base = base_ra.x() }), + .unsigned => .ldrb(dst_ra.w(), .{ .base = base_ra.x() }), + }, + 2 => if (dst_ra.isVector()) + .ldr(dst_ra.h(), .{ .base = base_ra.x() }) + else switch (dst_vi.signedness(isel)) { + .signed => .ldrsh(dst_ra.w(), .{ .base = base_ra.x() }), + .unsigned => .ldrh(dst_ra.w(), .{ .base = base_ra.x() }), + }, + 4 => .ldr(if (dst_ra.isVector()) dst_ra.s() else dst_ra.w(), .{ .base = base_ra.x() }), + 8 => .ldr(if (dst_ra.isVector()) dst_ra.d() else dst_ra.x(), .{ .base = base_ra.x() }), + 16 => .ldr(dst_ra.q(), .{ .base = base_ra.x() }), + }); + dst_vi_ra.* = .zr; + try dst_vi.address(isel, 0, base_ra); + dst_live_vi.* = .free; + return true; +} + +/// Merges possibly differing value tracking into a consistent state. +/// +/// At a conditional branch, if a value is expected in the same register on both +/// paths, or only expected in a register on only one path, tracking is updated: +/// +/// $0 -> r0 // final state is now consistent with both paths +/// b.cond else +/// then: +/// $0 -> r0 // updated if not already consistent with else +/// ... +/// b end +/// else: +/// $0 -> r0 +/// ... +/// end: +/// +/// At a conditional branch, if a value is expected in different registers on +/// each path, mov instructions are emitted: +/// +/// $0 -> r0 // final state is now consistent with both paths +/// b.cond else +/// then: +/// $0 -> r0 // updated to be consistent with else +/// mov x1, x0 // emitted to merge the inconsistent states +/// $0 -> r1 +/// ... +/// b end +/// else: +/// $0 -> r0 +/// ... +/// end: +/// +/// At a loop, a value that is expected in a register at the repeats is updated: +/// +/// $0 -> r0 // final state is now consistent with all paths +/// loop: +/// $0 -> r0 // updated to be consistent with the repeats +/// ... +/// $0 -> r0 +/// b.cond loop +/// ... +/// $0 -> r0 +/// b loop +/// +/// At a loop, a value that is expected in a register at the top is filled: +/// +/// $0 -> [sp, #A] // final state is now consistent with all paths +/// loop: +/// $0 -> [sp, #A] // updated to be consistent with the repeats +/// ldr x0, [sp, #A] // emitted to merge the inconsistent states +/// $0 -> r0 +/// ... +/// $0 -> [sp, #A] +/// b.cond loop +/// ... +/// $0 -> [sp, #A] +/// b loop +/// +/// At a loop, if a value that is expected in different registers on each path, +/// mov instructions are emitted: +/// +/// $0 -> r0 // final state is now consistent with all paths +/// loop: +/// $0 -> r0 // updated to be consistent with the repeats +/// mov x1, x0 // emitted to merge the inconsistent states +/// $0 -> r1 +/// ... +/// $0 -> r0 +/// b.cond loop +/// ... +/// $0 -> r0 +/// b loop +fn merge( + isel: *Select, + expected_live_registers: *const LiveRegisters, + comptime opts: struct { fill_extra: bool = false }, +) !void { + var live_reg_it = isel.live_registers.iterator(); + while (live_reg_it.next()) |live_reg_entry| { + const ra = live_reg_entry.key; + const actual_vi = live_reg_entry.value; + const expected_vi = expected_live_registers.get(ra); + switch (expected_vi) { + else => switch (actual_vi.*) { + _ => {}, + .allocating => unreachable, + .free => actual_vi.* = .allocating, + }, + .free => {}, + } + } + live_reg_it = isel.live_registers.iterator(); + while (live_reg_it.next()) |live_reg_entry| { + const ra = live_reg_entry.key; + const actual_vi = live_reg_entry.value; + const expected_vi = expected_live_registers.get(ra); + switch (expected_vi) { + _ => { + switch (actual_vi.*) { + _ => _ = if (opts.fill_extra) { + assert(try isel.fillMemory(ra)); + assert(actual_vi.* == .free); + }, + .allocating => actual_vi.* = .free, + .free => unreachable, + } + try expected_vi.liveIn(isel, ra, expected_live_registers); + }, + .allocating => if (if (opts.fill_extra) try isel.fillMemory(ra) else try isel.fill(ra)) { + assert(actual_vi.* == .free); + actual_vi.* = .allocating; + }, + .free => if (opts.fill_extra) assert(try isel.fillMemory(ra) and actual_vi.* == .free), + } + } + live_reg_it = isel.live_registers.iterator(); + while (live_reg_it.next()) |live_reg_entry| { + const ra = live_reg_entry.key; + const actual_vi = live_reg_entry.value; + const expected_vi = expected_live_registers.get(ra); + switch (expected_vi) { + _ => { + assert(actual_vi.* == .allocating and expected_vi.register(isel) == ra); + actual_vi.* = expected_vi; + }, + .allocating => assert(actual_vi.* == .allocating), + .free => if (opts.fill_extra) assert(actual_vi.* == .free), + } + } +} + +const call = struct { + const param_reg: Value.Index = @enumFromInt(@intFromEnum(Value.Index.allocating) - 2); + const callee_clobbered_reg: Value.Index = @enumFromInt(@intFromEnum(Value.Index.allocating) - 1); + const caller_saved_regs: LiveRegisters = .init(.{ + .r0 = param_reg, + .r1 = param_reg, + .r2 = param_reg, + .r3 = param_reg, + .r4 = param_reg, + .r5 = param_reg, + .r6 = param_reg, + .r7 = param_reg, + .r8 = param_reg, + .r9 = callee_clobbered_reg, + .r10 = callee_clobbered_reg, + .r11 = callee_clobbered_reg, + .r12 = callee_clobbered_reg, + .r13 = callee_clobbered_reg, + .r14 = callee_clobbered_reg, + .r15 = callee_clobbered_reg, + .r16 = callee_clobbered_reg, + .r17 = callee_clobbered_reg, + .r18 = callee_clobbered_reg, + .r19 = .free, + .r20 = .free, + .r21 = .free, + .r22 = .free, + .r23 = .free, + .r24 = .free, + .r25 = .free, + .r26 = .free, + .r27 = .free, + .r28 = .free, + .r29 = .free, + .r30 = callee_clobbered_reg, + .zr = .free, + .sp = .free, + + .pc = .free, + + .v0 = param_reg, + .v1 = param_reg, + .v2 = param_reg, + .v3 = param_reg, + .v4 = param_reg, + .v5 = param_reg, + .v6 = param_reg, + .v7 = param_reg, + .v8 = .free, + .v9 = .free, + .v10 = .free, + .v11 = .free, + .v12 = .free, + .v13 = .free, + .v14 = .free, + .v15 = .free, + .v16 = callee_clobbered_reg, + .v17 = callee_clobbered_reg, + .v18 = callee_clobbered_reg, + .v19 = callee_clobbered_reg, + .v20 = callee_clobbered_reg, + .v21 = callee_clobbered_reg, + .v22 = callee_clobbered_reg, + .v23 = callee_clobbered_reg, + .v24 = callee_clobbered_reg, + .v25 = callee_clobbered_reg, + .v26 = callee_clobbered_reg, + .v27 = callee_clobbered_reg, + .v28 = callee_clobbered_reg, + .v29 = callee_clobbered_reg, + .v30 = callee_clobbered_reg, + .v31 = callee_clobbered_reg, + + .fpcr = .free, + .fpsr = .free, + + .p0 = callee_clobbered_reg, + .p1 = callee_clobbered_reg, + .p2 = callee_clobbered_reg, + .p3 = callee_clobbered_reg, + .p4 = callee_clobbered_reg, + .p5 = callee_clobbered_reg, + .p6 = callee_clobbered_reg, + .p7 = callee_clobbered_reg, + .p8 = callee_clobbered_reg, + .p9 = callee_clobbered_reg, + .p10 = callee_clobbered_reg, + .p11 = callee_clobbered_reg, + .p12 = callee_clobbered_reg, + .p13 = callee_clobbered_reg, + .p14 = callee_clobbered_reg, + .p15 = callee_clobbered_reg, + + .ffr = .free, + }); + fn prepareReturn(isel: *Select) !void { + var live_reg_it = isel.live_registers.iterator(); + while (live_reg_it.next()) |live_reg_entry| switch (caller_saved_regs.get(live_reg_entry.key)) { + else => unreachable, + param_reg, callee_clobbered_reg => switch (live_reg_entry.value.*) { + _ => {}, + .allocating => unreachable, + .free => live_reg_entry.value.* = .allocating, + }, + .free => {}, + }; + } + fn returnFill(isel: *Select, ra: Register.Alias) !void { + const live_vi = isel.live_registers.getPtr(ra); + if (try isel.fill(ra)) { + assert(live_vi.* == .free); + live_vi.* = .allocating; + } + assert(live_vi.* == .allocating); + } + fn returnLiveIn(isel: *Select, vi: Value.Index, ra: Register.Alias) !void { + try vi.defLiveIn(isel, ra, &caller_saved_regs); + } + fn finishReturn(isel: *Select) !void { + var live_reg_it = isel.live_registers.iterator(); + while (live_reg_it.next()) |live_reg_entry| { + switch (live_reg_entry.value.*) { + _ => |live_vi| switch (live_vi.size(isel)) { + else => unreachable, + 1, 2, 4, 8 => {}, + 16 => { + assert(try isel.fillMemory(live_reg_entry.key)); + assert(live_reg_entry.value.* == .free); + switch (caller_saved_regs.get(live_reg_entry.key)) { + else => unreachable, + param_reg, callee_clobbered_reg => live_reg_entry.value.* = .allocating, + .free => {}, + } + continue; + }, + }, + .allocating, .free => {}, + } + switch (caller_saved_regs.get(live_reg_entry.key)) { + else => unreachable, + param_reg, callee_clobbered_reg => switch (live_reg_entry.value.*) { + _ => { + assert(try isel.fill(live_reg_entry.key)); + assert(live_reg_entry.value.* == .free); + live_reg_entry.value.* = .allocating; + }, + .allocating => {}, + .free => unreachable, + }, + .free => {}, + } + } + } + fn prepareCallee(isel: *Select) !void { + var live_reg_it = isel.live_registers.iterator(); + while (live_reg_it.next()) |live_reg_entry| switch (caller_saved_regs.get(live_reg_entry.key)) { + else => unreachable, + param_reg => assert(live_reg_entry.value.* == .allocating), + callee_clobbered_reg => isel.freeReg(live_reg_entry.key), + .free => {}, + }; + } + fn finishCallee(_: *Select) !void {} + fn prepareParams(_: *Select) !void {} + fn paramLiveOut(isel: *Select, vi: Value.Index, ra: Register.Alias) !void { + isel.freeReg(ra); + try vi.liveOut(isel, ra); + const live_vi = isel.live_registers.getPtr(ra); + if (live_vi.* == .free) live_vi.* = .allocating; + } + fn paramAddress(isel: *Select, vi: Value.Index, ra: Register.Alias) !void { + isel.freeReg(ra); + try vi.address(isel, 0, ra); + const live_vi = isel.live_registers.getPtr(ra); + if (live_vi.* == .free) live_vi.* = .allocating; + } + fn finishParams(isel: *Select) !void { + var live_reg_it = isel.live_registers.iterator(); + while (live_reg_it.next()) |live_reg_entry| switch (caller_saved_regs.get(live_reg_entry.key)) { + else => unreachable, + param_reg => switch (live_reg_entry.value.*) { + _ => {}, + .allocating => live_reg_entry.value.* = .free, + .free => unreachable, + }, + callee_clobbered_reg, .free => {}, + }; + } +}; + +pub const CallAbiIterator = struct { + /// Next General-purpose Register Number + ngrn: Register.Alias, + /// Next SIMD and Floating-point Register Number + nsrn: Register.Alias, + /// next stacked argument address + nsaa: u24, + + pub const ngrn_start: Register.Alias = .r0; + pub const ngrn_end: Register.Alias = .r8; + pub const nsrn_start: Register.Alias = .v0; + pub const nsrn_end: Register.Alias = .v8; + pub const nsaa_start: u42 = 0; + + pub const init: CallAbiIterator = .{ + // A.1 + .ngrn = ngrn_start, + // A.2 + .nsrn = nsrn_start, + // A.3 + .nsaa = nsaa_start, + }; + + pub fn param(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index { + const zcu = isel.pt.zcu; + const ip = &zcu.intern_pool; + + if (ty.isNoReturn(zcu) or !ty.hasRuntimeBitsIgnoreComptime(zcu)) return null; + try isel.values.ensureUnusedCapacity(zcu.gpa, Value.max_parts); + const wip_vi = isel.initValue(ty); + type_key: switch (ip.indexToKey(ty.toIntern())) { + else => return isel.fail("CallAbiIterator.param({f})", .{isel.fmtType(ty)}), + .int_type => |int_type| switch (int_type.bits) { + 0 => unreachable, + 1...16 => { + wip_vi.setSignedness(isel, int_type.signedness); + // C.7 + it.integer(isel, wip_vi); + }, + // C.7 + 17...64 => it.integer(isel, wip_vi), + // C.9 + 65...128 => it.integers(isel, wip_vi, @splat(@divExact(wip_vi.size(isel), 2))), + else => it.indirect(isel, wip_vi), + }, + .array_type => switch (wip_vi.size(isel)) { + 0 => unreachable, + 1...8 => it.integer(isel, wip_vi), + 9...16 => |size| it.integers(isel, wip_vi, .{ 8, size - 8 }), + else => it.indirect(isel, wip_vi), + }, + .ptr_type => |ptr_type| switch (ptr_type.flags.size) { + .one, .many, .c => continue :type_key .{ .int_type = .{ + .signedness = .unsigned, + .bits = 64, + } }, + .slice => it.integers(isel, wip_vi, @splat(8)), + }, + .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu)) + continue :type_key ip.indexToKey(child_type) + else switch (ZigType.fromInterned(child_type).abiSize(zcu)) { + 0 => continue :type_key .{ .simple_type = .bool }, + 1...7 => it.integer(isel, wip_vi), + 8...15 => |child_size| it.integers(isel, wip_vi, .{ 8, child_size - 7 }), + else => return isel.fail("CallAbiIterator.param({f})", .{isel.fmtType(ty)}), + }, + .anyframe_type => unreachable, + .error_union_type => |error_union_type| switch (wip_vi.size(isel)) { + 0 => unreachable, + 1...8 => it.integer(isel, wip_vi), + 9...16 => { + var sizes: [2]u64 = @splat(0); + const payload_ty: ZigType = .fromInterned(error_union_type.payload_type); + { + const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type); + const offset = codegen.errUnionErrorOffset(payload_ty, zcu); + const size = error_set_ty.abiSize(zcu); + const end = offset % 8 + size; + const part_index: usize = @intCast(offset / 8); + sizes[part_index] = @max(sizes[part_index], @min(end, 8)); + if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8); + } + { + const offset = codegen.errUnionPayloadOffset(payload_ty, zcu); + const size = payload_ty.abiSize(zcu); + const end = offset % 8 + size; + const part_index: usize = @intCast(offset / 8); + sizes[part_index] = @max(sizes[part_index], @min(end, 8)); + if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8); + } + it.integers(isel, wip_vi, sizes); + }, + else => it.indirect(isel, wip_vi), + }, + .simple_type => |simple_type| switch (simple_type) { + .f16, .f32, .f64, .f128, .c_longdouble => it.vector(isel, wip_vi), + .f80 => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 80 } }, + .usize, + .isize, + .c_char, + .c_short, + .c_ushort, + .c_int, + .c_uint, + .c_long, + .c_ulong, + .c_longlong, + .c_ulonglong, + => continue :type_key .{ .int_type = ty.intInfo(zcu) }, + // B.1 + .anyopaque => it.indirect(isel, wip_vi), + .bool => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 1 } }, + .anyerror => continue :type_key .{ .int_type = .{ + .signedness = .unsigned, + .bits = zcu.errorSetBits(), + } }, + .void, + .type, + .comptime_int, + .comptime_float, + .noreturn, + .null, + .undefined, + .enum_literal, + .adhoc_inferred_error_set, + .generic_poison, + => unreachable, + }, + .struct_type => { + const size = wip_vi.size(isel); + const loaded_struct = ip.loadStructType(ty.toIntern()); + if (size <= 16 * 4) homogeneous_aggregate: { + const fdt = homogeneousStructBaseType(zcu, &loaded_struct) orelse break :homogeneous_aggregate; + const parts_len = @shrExact(size, fdt.log2Size()); + if (parts_len > 4) break :homogeneous_aggregate; + it.vectors(isel, wip_vi, fdt, @intCast(parts_len)); + break :type_key; + } + switch (size) { + 0 => unreachable, + 1...8 => it.integer(isel, wip_vi), + 9...16 => { + var part_offset: u64 = 0; + var part_sizes: [2]u64 = undefined; + var parts_len: Value.PartsLen = 0; + var next_field_end: u64 = 0; + var field_it = loaded_struct.iterateRuntimeOrder(ip); + while (part_offset < size) { + const field_end = next_field_end; + const next_field_begin = if (field_it.next()) |field_index| next_field_begin: { + const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); + const next_field_begin = switch (loaded_struct.fieldAlign(ip, field_index)) { + .none => field_ty.abiAlignment(zcu), + else => |field_align| field_align, + }.forward(field_end); + next_field_end = next_field_begin + field_ty.abiSize(zcu); + break :next_field_begin next_field_begin; + } else std.mem.alignForward(u64, size, 8); + while (next_field_begin - part_offset >= 8) { + const part_size = field_end - part_offset; + part_sizes[parts_len] = part_size; + assert(part_offset + part_size <= size); + parts_len += 1; + part_offset = next_field_begin; + } + } + assert(parts_len == part_sizes.len); + it.integers(isel, wip_vi, part_sizes); + }, + else => it.indirect(isel, wip_vi), + } + }, + .tuple_type => |tuple_type| { + const size = wip_vi.size(isel); + if (size <= 16 * 4) homogeneous_aggregate: { + const fdt = homogeneousTupleBaseType(zcu, tuple_type) orelse break :homogeneous_aggregate; + const parts_len = @shrExact(size, fdt.log2Size()); + if (parts_len > 4) break :homogeneous_aggregate; + it.vectors(isel, wip_vi, fdt, @intCast(parts_len)); + break :type_key; + } + switch (size) { + 0 => unreachable, + 1...8 => it.integer(isel, wip_vi), + 9...16 => { + var part_offset: u64 = 0; + var part_sizes: [2]u64 = undefined; + var parts_len: Value.PartsLen = 0; + var next_field_end: u64 = 0; + var field_index: usize = 0; + while (part_offset < size) { + const field_end = next_field_end; + const next_field_begin = while (field_index < tuple_type.types.len) { + defer field_index += 1; + if (tuple_type.values.get(ip)[field_index] != .none) continue; + const field_ty: ZigType = .fromInterned(tuple_type.types.get(ip)[field_index]); + const next_field_begin = field_ty.abiAlignment(zcu).forward(field_end); + next_field_end = next_field_begin + field_ty.abiSize(zcu); + break next_field_begin; + } else std.mem.alignForward(u64, size, 8); + while (next_field_begin - part_offset >= 8) { + const part_size = @min(field_end - part_offset, 8); + part_sizes[parts_len] = part_size; + assert(part_offset + part_size <= size); + parts_len += 1; + part_offset += part_size; + if (part_offset >= field_end) part_offset = next_field_begin; + } + } + assert(parts_len == part_sizes.len); + it.integers(isel, wip_vi, part_sizes); + }, + else => it.indirect(isel, wip_vi), + } + }, + .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque }, + .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty), + .error_set_type, + .inferred_error_set_type, + => continue :type_key .{ .simple_type = .anyerror }, + .undef, + .simple_value, + .variable, + .@"extern", + .func, + .int, + .err, + .error_union, + .enum_literal, + .enum_tag, + .empty_enum_value, + .float, + .ptr, + .slice, + .opt, + .aggregate, + .un, + .memoized_call, + => unreachable, // values, not types + } + return wip_vi.ref(isel); + } + + pub fn ret(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index { + const wip_vi = try it.param(isel, ty) orelse return null; + switch (wip_vi.parent(isel)) { + .unallocated, .stack_slot => {}, + .value, .constant => unreachable, + .address => |address_vi| { + assert(address_vi.hint(isel) == ngrn_start); + address_vi.setHint(isel, ngrn_end); + }, + } + return wip_vi; + } + + pub const FundamentalDataType = enum { + half, + single, + double, + quad, + vector64, + vector128, + fn log2Size(fdt: FundamentalDataType) u3 { + return switch (fdt) { + .half => 1, + .single => 2, + .double, .vector64 => 3, + .quad, .vector128 => 4, + }; + } + fn size(fdt: FundamentalDataType) u64 { + return @as(u64, 1) << fdt.log2Size(); + } + }; + fn homogeneousAggregateBaseType(zcu: *Zcu, initial_ty: InternPool.Index) ?FundamentalDataType { + const ip = &zcu.intern_pool; + var ty = initial_ty; + return type_key: switch (ip.indexToKey(ty)) { + else => null, + .array_type => |array_type| { + ty = array_type.child; + continue :type_key ip.indexToKey(ty); + }, + .vector_type => switch (ZigType.fromInterned(ty).abiSize(zcu)) { + else => null, + 8 => .vector64, + 16 => .vector128, + }, + .simple_type => |simple_type| switch (simple_type) { + .f16 => .half, + .f32 => .single, + .f64 => .double, + .f128 => .quad, + .c_longdouble => switch (zcu.getTarget().cTypeBitSize(.longdouble)) { + else => unreachable, + 16 => .half, + 32 => .single, + 64 => .double, + 80 => null, + 128 => .quad, + }, + else => null, + }, + .struct_type => homogeneousStructBaseType(zcu, &ip.loadStructType(ty)), + .tuple_type => |tuple_type| homogeneousTupleBaseType(zcu, tuple_type), + }; + } + fn homogeneousStructBaseType(zcu: *Zcu, loaded_struct: *const InternPool.LoadedStructType) ?FundamentalDataType { + const ip = &zcu.intern_pool; + var common_fdt: ?FundamentalDataType = null; + for (0.., loaded_struct.field_types.get(ip)) |field_index, field_ty| { + if (loaded_struct.fieldIsComptime(ip, field_index)) continue; + if (loaded_struct.fieldAlign(ip, field_index) != .none) return null; + if (!ZigType.fromInterned(field_ty).hasRuntimeBits(zcu)) continue; + const fdt = homogeneousAggregateBaseType(zcu, field_ty); + if (common_fdt == null) common_fdt = fdt else if (fdt != common_fdt) return null; + } + return common_fdt; + } + fn homogeneousTupleBaseType(zcu: *Zcu, tuple_type: InternPool.Key.TupleType) ?FundamentalDataType { + const ip = &zcu.intern_pool; + var common_fdt: ?FundamentalDataType = null; + for (tuple_type.values.get(ip), tuple_type.types.get(ip)) |field_val, field_ty| { + if (field_val != .none) continue; + const fdt = homogeneousAggregateBaseType(zcu, field_ty); + if (common_fdt == null) common_fdt = fdt else if (fdt != common_fdt) return null; + } + return common_fdt; + } + + const Spec = struct { + offset: u64, + size: u64, + }; + + fn stack(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void { + // C.12 + it.nsaa = @intCast(wip_vi.alignment(isel).forward(it.nsaa)); + const parent_vi = switch (wip_vi.parent(isel)) { + .unallocated, .stack_slot => wip_vi, + .address, .constant => unreachable, + .value => |parent_vi| parent_vi, + }; + switch (parent_vi.parent(isel)) { + .unallocated => parent_vi.setParent(isel, .{ .stack_slot = .{ + .base = .sp, + .offset = it.nsaa, + } }), + .stack_slot => {}, + .address, .value, .constant => unreachable, + } + it.nsaa += @intCast(wip_vi.size(isel)); + } + + fn integer(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void { + assert(wip_vi.size(isel) <= 8); + const natural_alignment = wip_vi.alignment(isel); + assert(natural_alignment.order(.@"16").compare(.lte)); + wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8")); + if (it.ngrn == ngrn_end) return it.stack(isel, wip_vi); + wip_vi.setHint(isel, it.ngrn); + it.ngrn = @enumFromInt(@intFromEnum(it.ngrn) + 1); + } + + fn integers(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index, part_sizes: [2]u64) void { + assert(wip_vi.size(isel) <= 16); + const natural_alignment = wip_vi.alignment(isel); + assert(natural_alignment.order(.@"16").compare(.lte)); + wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8")); + // C.8 + if (natural_alignment == .@"16") it.ngrn = @enumFromInt(std.mem.alignForward( + @typeInfo(Register.Alias).@"enum".tag_type, + @intFromEnum(it.ngrn), + 2, + )); + if (it.ngrn == ngrn_end) return it.stack(isel, wip_vi); + wip_vi.setParts(isel, part_sizes.len); + for (0.., part_sizes) |part_index, part_size| + it.integer(isel, wip_vi.addPart(isel, 8 * part_index, part_size)); + } + + fn vector(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void { + assert(wip_vi.size(isel) <= 16); + const natural_alignment = wip_vi.alignment(isel); + assert(natural_alignment.order(.@"16").compare(.lte)); + wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8")); + wip_vi.setIsVector(isel); + if (it.nsrn == nsrn_end) return it.stack(isel, wip_vi); + wip_vi.setHint(isel, it.nsrn); + it.nsrn = @enumFromInt(@intFromEnum(it.nsrn) + 1); + } + + fn vectors( + it: *CallAbiIterator, + isel: *Select, + wip_vi: Value.Index, + fdt: FundamentalDataType, + parts_len: Value.PartsLen, + ) void { + const fdt_log2_size = fdt.log2Size(); + assert(wip_vi.size(isel) == @shlExact(@as(u9, parts_len), fdt_log2_size)); + const natural_alignment = wip_vi.alignment(isel); + assert(natural_alignment.order(.@"16").compare(.lte)); + wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8")); + if (@intFromEnum(it.nsrn) > @intFromEnum(nsrn_end) - parts_len) return it.stack(isel, wip_vi); + if (parts_len == 1) return it.vector(isel, wip_vi); + wip_vi.setParts(isel, parts_len); + const fdt_size = @as(u64, 1) << fdt_log2_size; + for (0..parts_len) |part_index| + it.vector(isel, wip_vi.addPart(isel, part_index << fdt_log2_size, fdt_size)); + } + + fn indirect(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void { + const wip_address_vi = isel.initValue(.usize); + wip_vi.setParent(isel, .{ .address = wip_address_vi }); + it.integer(isel, wip_address_vi); + } +}; + +const Air = @import("../../Air.zig"); +const assert = std.debug.assert; +const codegen = @import("../../codegen.zig"); +const Constant = @import("../../Value.zig"); +const InternPool = @import("../../InternPool.zig"); +const Package = @import("../../Package.zig"); +const Register = codegen.aarch64.encoding.Register; +const Select = @This(); +const std = @import("std"); +const tracking_log = std.log.scoped(.tracking); +const wip_mir_log = std.log.scoped(.@"wip-mir"); +const Zcu = @import("../../Zcu.zig"); +const ZigType = @import("../../Type.zig"); diff --git a/src/codegen/aarch64/abi.zig b/src/codegen/aarch64/abi.zig index 0cd0b389b1..9587415287 100644 --- a/src/codegen/aarch64/abi.zig +++ b/src/codegen/aarch64/abi.zig @@ -1,7 +1,5 @@ +const assert = @import("std").debug.assert; const std = @import("std"); -const builtin = @import("builtin"); -const bits = @import("../../arch/aarch64/bits.zig"); -const Register = bits.Register; const Type = @import("../../Type.zig"); const Zcu = @import("../../Zcu.zig"); @@ -15,7 +13,7 @@ pub const Class = union(enum) { /// For `float_array` the second element will be the amount of floats. pub fn classifyType(ty: Type, zcu: *Zcu) Class { - std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(zcu)); + assert(ty.hasRuntimeBitsIgnoreComptime(zcu)); var maybe_float_bits: ?u16 = null; switch (ty.zigTypeTag(zcu)) { @@ -47,11 +45,11 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { return .byval; }, .optional => { - std.debug.assert(ty.isPtrLikeOptional(zcu)); + assert(ty.isPtrLikeOptional(zcu)); return .byval; }, .pointer => { - std.debug.assert(!ty.isSlice(zcu)); + assert(!ty.isSlice(zcu)); return .byval; }, .error_union, @@ -138,13 +136,3 @@ pub fn getFloatArrayType(ty: Type, zcu: *Zcu) ?Type { else => return null, } } - -pub const callee_preserved_regs = [_]Register{ - .x19, .x20, .x21, .x22, .x23, - .x24, .x25, .x26, .x27, .x28, -}; - -pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; -pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; - -const allocatable_registers = callee_preserved_regs; diff --git a/src/codegen/aarch64/encoding.zig b/src/codegen/aarch64/encoding.zig new file mode 100644 index 0000000000..1aef2f40c2 --- /dev/null +++ b/src/codegen/aarch64/encoding.zig @@ -0,0 +1,11799 @@ +/// B1.2 Registers in AArch64 Execution state +pub const Register = struct { + alias: Alias, + format: Format, + + pub const Format = union(enum) { + alias, + integer: IntegerSize, + scalar: VectorSize, + vector: Arrangement, + element: struct { size: VectorSize, index: u4 }, + }; + + pub const IntegerSize = enum(u1) { + word = 0b0, + doubleword = 0b1, + + pub fn prefix(is: IntegerSize) u8 { + return (comptime std.enums.EnumArray(IntegerSize, u8).init(.{ + .word = 'w', + .doubleword = 'x', + })).get(is); + } + }; + + pub const VectorSize = enum(u3) { + byte = 0, + half = 1, + single = 2, + double = 3, + quad = 4, + scalable, + predicate, + + pub fn prefix(vs: VectorSize) u8 { + return (comptime std.enums.EnumArray(VectorSize, u8).init(.{ + .byte = 'b', + .half = 'h', + .single = 's', + .double = 'd', + .quad = 'q', + .scalable = 'z', + .predicate = 'p', + })).get(vs); + } + }; + + pub const Arrangement = enum { + @"2d", + @"4s", + @"8h", + @"16b", + + @"1d", + @"2s", + @"4h", + @"8b", + + pub fn len(arrangement: Arrangement) u5 { + return switch (arrangement) { + .@"1d" => 1, + .@"2d", .@"2s" => 2, + .@"4s", .@"4h" => 4, + .@"8h", .@"8b" => 8, + .@"16b" => 16, + }; + } + + pub fn size(arrangement: Arrangement) Instruction.DataProcessingVector.Q { + return switch (arrangement) { + .@"2d", .@"4s", .@"8h", .@"16b" => .quad, + .@"1d", .@"2s", .@"4h", .@"8b" => .double, + }; + } + + pub fn elemSize(arrangement: Arrangement) Instruction.DataProcessingVector.Size { + return switch (arrangement) { + .@"2d", .@"1d" => .double, + .@"4s", .@"2s" => .single, + .@"8h", .@"4h" => .half, + .@"16b", .@"8b" => .byte, + }; + } + }; + + pub const x0: Register = .{ .alias = .r0, .format = .{ .integer = .doubleword } }; + pub const x1: Register = .{ .alias = .r1, .format = .{ .integer = .doubleword } }; + pub const x2: Register = .{ .alias = .r2, .format = .{ .integer = .doubleword } }; + pub const x3: Register = .{ .alias = .r3, .format = .{ .integer = .doubleword } }; + pub const x4: Register = .{ .alias = .r4, .format = .{ .integer = .doubleword } }; + pub const x5: Register = .{ .alias = .r5, .format = .{ .integer = .doubleword } }; + pub const x6: Register = .{ .alias = .r6, .format = .{ .integer = .doubleword } }; + pub const x7: Register = .{ .alias = .r7, .format = .{ .integer = .doubleword } }; + pub const x8: Register = .{ .alias = .r8, .format = .{ .integer = .doubleword } }; + pub const x9: Register = .{ .alias = .r9, .format = .{ .integer = .doubleword } }; + pub const x10: Register = .{ .alias = .r10, .format = .{ .integer = .doubleword } }; + pub const x11: Register = .{ .alias = .r11, .format = .{ .integer = .doubleword } }; + pub const x12: Register = .{ .alias = .r12, .format = .{ .integer = .doubleword } }; + pub const x13: Register = .{ .alias = .r13, .format = .{ .integer = .doubleword } }; + pub const x14: Register = .{ .alias = .r14, .format = .{ .integer = .doubleword } }; + pub const x15: Register = .{ .alias = .r15, .format = .{ .integer = .doubleword } }; + pub const x16: Register = .{ .alias = .r16, .format = .{ .integer = .doubleword } }; + pub const x17: Register = .{ .alias = .r17, .format = .{ .integer = .doubleword } }; + pub const x18: Register = .{ .alias = .r18, .format = .{ .integer = .doubleword } }; + pub const x19: Register = .{ .alias = .r19, .format = .{ .integer = .doubleword } }; + pub const x20: Register = .{ .alias = .r20, .format = .{ .integer = .doubleword } }; + pub const x21: Register = .{ .alias = .r21, .format = .{ .integer = .doubleword } }; + pub const x22: Register = .{ .alias = .r22, .format = .{ .integer = .doubleword } }; + pub const x23: Register = .{ .alias = .r23, .format = .{ .integer = .doubleword } }; + pub const x24: Register = .{ .alias = .r24, .format = .{ .integer = .doubleword } }; + pub const x25: Register = .{ .alias = .r25, .format = .{ .integer = .doubleword } }; + pub const x26: Register = .{ .alias = .r26, .format = .{ .integer = .doubleword } }; + pub const x27: Register = .{ .alias = .r27, .format = .{ .integer = .doubleword } }; + pub const x28: Register = .{ .alias = .r28, .format = .{ .integer = .doubleword } }; + pub const x29: Register = .{ .alias = .r29, .format = .{ .integer = .doubleword } }; + pub const x30: Register = .{ .alias = .r30, .format = .{ .integer = .doubleword } }; + pub const xzr: Register = .{ .alias = .zr, .format = .{ .integer = .doubleword } }; + pub const sp: Register = .{ .alias = .sp, .format = .{ .integer = .doubleword } }; + + pub const w0: Register = .{ .alias = .r0, .format = .{ .integer = .word } }; + pub const w1: Register = .{ .alias = .r1, .format = .{ .integer = .word } }; + pub const w2: Register = .{ .alias = .r2, .format = .{ .integer = .word } }; + pub const w3: Register = .{ .alias = .r3, .format = .{ .integer = .word } }; + pub const w4: Register = .{ .alias = .r4, .format = .{ .integer = .word } }; + pub const w5: Register = .{ .alias = .r5, .format = .{ .integer = .word } }; + pub const w6: Register = .{ .alias = .r6, .format = .{ .integer = .word } }; + pub const w7: Register = .{ .alias = .r7, .format = .{ .integer = .word } }; + pub const w8: Register = .{ .alias = .r8, .format = .{ .integer = .word } }; + pub const w9: Register = .{ .alias = .r9, .format = .{ .integer = .word } }; + pub const w10: Register = .{ .alias = .r10, .format = .{ .integer = .word } }; + pub const w11: Register = .{ .alias = .r11, .format = .{ .integer = .word } }; + pub const w12: Register = .{ .alias = .r12, .format = .{ .integer = .word } }; + pub const w13: Register = .{ .alias = .r13, .format = .{ .integer = .word } }; + pub const w14: Register = .{ .alias = .r14, .format = .{ .integer = .word } }; + pub const w15: Register = .{ .alias = .r15, .format = .{ .integer = .word } }; + pub const w16: Register = .{ .alias = .r16, .format = .{ .integer = .word } }; + pub const w17: Register = .{ .alias = .r17, .format = .{ .integer = .word } }; + pub const w18: Register = .{ .alias = .r18, .format = .{ .integer = .word } }; + pub const w19: Register = .{ .alias = .r19, .format = .{ .integer = .word } }; + pub const w20: Register = .{ .alias = .r20, .format = .{ .integer = .word } }; + pub const w21: Register = .{ .alias = .r21, .format = .{ .integer = .word } }; + pub const w22: Register = .{ .alias = .r22, .format = .{ .integer = .word } }; + pub const w23: Register = .{ .alias = .r23, .format = .{ .integer = .word } }; + pub const w24: Register = .{ .alias = .r24, .format = .{ .integer = .word } }; + pub const w25: Register = .{ .alias = .r25, .format = .{ .integer = .word } }; + pub const w26: Register = .{ .alias = .r26, .format = .{ .integer = .word } }; + pub const w27: Register = .{ .alias = .r27, .format = .{ .integer = .word } }; + pub const w28: Register = .{ .alias = .r28, .format = .{ .integer = .word } }; + pub const w29: Register = .{ .alias = .r29, .format = .{ .integer = .word } }; + pub const w30: Register = .{ .alias = .r30, .format = .{ .integer = .word } }; + pub const wzr: Register = .{ .alias = .zr, .format = .{ .integer = .word } }; + pub const wsp: Register = .{ .alias = .sp, .format = .{ .integer = .word } }; + + pub const ip0 = x16; + pub const ip1 = x17; + pub const fp = x29; + pub const lr = x30; + pub const pc: Register = .{ .alias = .pc, .format = .{ .integer = .doubleword } }; + + pub const q0: Register = .{ .alias = .v0, .format = .{ .scalar = .quad } }; + pub const q1: Register = .{ .alias = .v1, .format = .{ .scalar = .quad } }; + pub const q2: Register = .{ .alias = .v2, .format = .{ .scalar = .quad } }; + pub const q3: Register = .{ .alias = .v3, .format = .{ .scalar = .quad } }; + pub const q4: Register = .{ .alias = .v4, .format = .{ .scalar = .quad } }; + pub const q5: Register = .{ .alias = .v5, .format = .{ .scalar = .quad } }; + pub const q6: Register = .{ .alias = .v6, .format = .{ .scalar = .quad } }; + pub const q7: Register = .{ .alias = .v7, .format = .{ .scalar = .quad } }; + pub const q8: Register = .{ .alias = .v8, .format = .{ .scalar = .quad } }; + pub const q9: Register = .{ .alias = .v9, .format = .{ .scalar = .quad } }; + pub const q10: Register = .{ .alias = .v10, .format = .{ .scalar = .quad } }; + pub const q11: Register = .{ .alias = .v11, .format = .{ .scalar = .quad } }; + pub const q12: Register = .{ .alias = .v12, .format = .{ .scalar = .quad } }; + pub const q13: Register = .{ .alias = .v13, .format = .{ .scalar = .quad } }; + pub const q14: Register = .{ .alias = .v14, .format = .{ .scalar = .quad } }; + pub const q15: Register = .{ .alias = .v15, .format = .{ .scalar = .quad } }; + pub const q16: Register = .{ .alias = .v16, .format = .{ .scalar = .quad } }; + pub const q17: Register = .{ .alias = .v17, .format = .{ .scalar = .quad } }; + pub const q18: Register = .{ .alias = .v18, .format = .{ .scalar = .quad } }; + pub const q19: Register = .{ .alias = .v19, .format = .{ .scalar = .quad } }; + pub const q20: Register = .{ .alias = .v20, .format = .{ .scalar = .quad } }; + pub const q21: Register = .{ .alias = .v21, .format = .{ .scalar = .quad } }; + pub const q22: Register = .{ .alias = .v22, .format = .{ .scalar = .quad } }; + pub const q23: Register = .{ .alias = .v23, .format = .{ .scalar = .quad } }; + pub const q24: Register = .{ .alias = .v24, .format = .{ .scalar = .quad } }; + pub const q25: Register = .{ .alias = .v25, .format = .{ .scalar = .quad } }; + pub const q26: Register = .{ .alias = .v26, .format = .{ .scalar = .quad } }; + pub const q27: Register = .{ .alias = .v27, .format = .{ .scalar = .quad } }; + pub const q28: Register = .{ .alias = .v28, .format = .{ .scalar = .quad } }; + pub const q29: Register = .{ .alias = .v29, .format = .{ .scalar = .quad } }; + pub const q30: Register = .{ .alias = .v30, .format = .{ .scalar = .quad } }; + pub const q31: Register = .{ .alias = .v31, .format = .{ .scalar = .quad } }; + + pub const d0: Register = .{ .alias = .v0, .format = .{ .scalar = .double } }; + pub const d1: Register = .{ .alias = .v1, .format = .{ .scalar = .double } }; + pub const d2: Register = .{ .alias = .v2, .format = .{ .scalar = .double } }; + pub const d3: Register = .{ .alias = .v3, .format = .{ .scalar = .double } }; + pub const d4: Register = .{ .alias = .v4, .format = .{ .scalar = .double } }; + pub const d5: Register = .{ .alias = .v5, .format = .{ .scalar = .double } }; + pub const d6: Register = .{ .alias = .v6, .format = .{ .scalar = .double } }; + pub const d7: Register = .{ .alias = .v7, .format = .{ .scalar = .double } }; + pub const d8: Register = .{ .alias = .v8, .format = .{ .scalar = .double } }; + pub const d9: Register = .{ .alias = .v9, .format = .{ .scalar = .double } }; + pub const d10: Register = .{ .alias = .v10, .format = .{ .scalar = .double } }; + pub const d11: Register = .{ .alias = .v11, .format = .{ .scalar = .double } }; + pub const d12: Register = .{ .alias = .v12, .format = .{ .scalar = .double } }; + pub const d13: Register = .{ .alias = .v13, .format = .{ .scalar = .double } }; + pub const d14: Register = .{ .alias = .v14, .format = .{ .scalar = .double } }; + pub const d15: Register = .{ .alias = .v15, .format = .{ .scalar = .double } }; + pub const d16: Register = .{ .alias = .v16, .format = .{ .scalar = .double } }; + pub const d17: Register = .{ .alias = .v17, .format = .{ .scalar = .double } }; + pub const d18: Register = .{ .alias = .v18, .format = .{ .scalar = .double } }; + pub const d19: Register = .{ .alias = .v19, .format = .{ .scalar = .double } }; + pub const d20: Register = .{ .alias = .v20, .format = .{ .scalar = .double } }; + pub const d21: Register = .{ .alias = .v21, .format = .{ .scalar = .double } }; + pub const d22: Register = .{ .alias = .v22, .format = .{ .scalar = .double } }; + pub const d23: Register = .{ .alias = .v23, .format = .{ .scalar = .double } }; + pub const d24: Register = .{ .alias = .v24, .format = .{ .scalar = .double } }; + pub const d25: Register = .{ .alias = .v25, .format = .{ .scalar = .double } }; + pub const d26: Register = .{ .alias = .v26, .format = .{ .scalar = .double } }; + pub const d27: Register = .{ .alias = .v27, .format = .{ .scalar = .double } }; + pub const d28: Register = .{ .alias = .v28, .format = .{ .scalar = .double } }; + pub const d29: Register = .{ .alias = .v29, .format = .{ .scalar = .double } }; + pub const d30: Register = .{ .alias = .v30, .format = .{ .scalar = .double } }; + pub const d31: Register = .{ .alias = .v31, .format = .{ .scalar = .double } }; + + pub const s0: Register = .{ .alias = .v0, .format = .{ .scalar = .single } }; + pub const s1: Register = .{ .alias = .v1, .format = .{ .scalar = .single } }; + pub const s2: Register = .{ .alias = .v2, .format = .{ .scalar = .single } }; + pub const s3: Register = .{ .alias = .v3, .format = .{ .scalar = .single } }; + pub const s4: Register = .{ .alias = .v4, .format = .{ .scalar = .single } }; + pub const s5: Register = .{ .alias = .v5, .format = .{ .scalar = .single } }; + pub const s6: Register = .{ .alias = .v6, .format = .{ .scalar = .single } }; + pub const s7: Register = .{ .alias = .v7, .format = .{ .scalar = .single } }; + pub const s8: Register = .{ .alias = .v8, .format = .{ .scalar = .single } }; + pub const s9: Register = .{ .alias = .v9, .format = .{ .scalar = .single } }; + pub const s10: Register = .{ .alias = .v10, .format = .{ .scalar = .single } }; + pub const s11: Register = .{ .alias = .v11, .format = .{ .scalar = .single } }; + pub const s12: Register = .{ .alias = .v12, .format = .{ .scalar = .single } }; + pub const s13: Register = .{ .alias = .v13, .format = .{ .scalar = .single } }; + pub const s14: Register = .{ .alias = .v14, .format = .{ .scalar = .single } }; + pub const s15: Register = .{ .alias = .v15, .format = .{ .scalar = .single } }; + pub const s16: Register = .{ .alias = .v16, .format = .{ .scalar = .single } }; + pub const s17: Register = .{ .alias = .v17, .format = .{ .scalar = .single } }; + pub const s18: Register = .{ .alias = .v18, .format = .{ .scalar = .single } }; + pub const s19: Register = .{ .alias = .v19, .format = .{ .scalar = .single } }; + pub const s20: Register = .{ .alias = .v20, .format = .{ .scalar = .single } }; + pub const s21: Register = .{ .alias = .v21, .format = .{ .scalar = .single } }; + pub const s22: Register = .{ .alias = .v22, .format = .{ .scalar = .single } }; + pub const s23: Register = .{ .alias = .v23, .format = .{ .scalar = .single } }; + pub const s24: Register = .{ .alias = .v24, .format = .{ .scalar = .single } }; + pub const s25: Register = .{ .alias = .v25, .format = .{ .scalar = .single } }; + pub const s26: Register = .{ .alias = .v26, .format = .{ .scalar = .single } }; + pub const s27: Register = .{ .alias = .v27, .format = .{ .scalar = .single } }; + pub const s28: Register = .{ .alias = .v28, .format = .{ .scalar = .single } }; + pub const s29: Register = .{ .alias = .v29, .format = .{ .scalar = .single } }; + pub const s30: Register = .{ .alias = .v30, .format = .{ .scalar = .single } }; + pub const s31: Register = .{ .alias = .v31, .format = .{ .scalar = .single } }; + + pub const h0: Register = .{ .alias = .v0, .format = .{ .scalar = .half } }; + pub const h1: Register = .{ .alias = .v1, .format = .{ .scalar = .half } }; + pub const h2: Register = .{ .alias = .v2, .format = .{ .scalar = .half } }; + pub const h3: Register = .{ .alias = .v3, .format = .{ .scalar = .half } }; + pub const h4: Register = .{ .alias = .v4, .format = .{ .scalar = .half } }; + pub const h5: Register = .{ .alias = .v5, .format = .{ .scalar = .half } }; + pub const h6: Register = .{ .alias = .v6, .format = .{ .scalar = .half } }; + pub const h7: Register = .{ .alias = .v7, .format = .{ .scalar = .half } }; + pub const h8: Register = .{ .alias = .v8, .format = .{ .scalar = .half } }; + pub const h9: Register = .{ .alias = .v9, .format = .{ .scalar = .half } }; + pub const h10: Register = .{ .alias = .v10, .format = .{ .scalar = .half } }; + pub const h11: Register = .{ .alias = .v11, .format = .{ .scalar = .half } }; + pub const h12: Register = .{ .alias = .v12, .format = .{ .scalar = .half } }; + pub const h13: Register = .{ .alias = .v13, .format = .{ .scalar = .half } }; + pub const h14: Register = .{ .alias = .v14, .format = .{ .scalar = .half } }; + pub const h15: Register = .{ .alias = .v15, .format = .{ .scalar = .half } }; + pub const h16: Register = .{ .alias = .v16, .format = .{ .scalar = .half } }; + pub const h17: Register = .{ .alias = .v17, .format = .{ .scalar = .half } }; + pub const h18: Register = .{ .alias = .v18, .format = .{ .scalar = .half } }; + pub const h19: Register = .{ .alias = .v19, .format = .{ .scalar = .half } }; + pub const h20: Register = .{ .alias = .v20, .format = .{ .scalar = .half } }; + pub const h21: Register = .{ .alias = .v21, .format = .{ .scalar = .half } }; + pub const h22: Register = .{ .alias = .v22, .format = .{ .scalar = .half } }; + pub const h23: Register = .{ .alias = .v23, .format = .{ .scalar = .half } }; + pub const h24: Register = .{ .alias = .v24, .format = .{ .scalar = .half } }; + pub const h25: Register = .{ .alias = .v25, .format = .{ .scalar = .half } }; + pub const h26: Register = .{ .alias = .v26, .format = .{ .scalar = .half } }; + pub const h27: Register = .{ .alias = .v27, .format = .{ .scalar = .half } }; + pub const h28: Register = .{ .alias = .v28, .format = .{ .scalar = .half } }; + pub const h29: Register = .{ .alias = .v29, .format = .{ .scalar = .half } }; + pub const h30: Register = .{ .alias = .v30, .format = .{ .scalar = .half } }; + pub const h31: Register = .{ .alias = .v31, .format = .{ .scalar = .half } }; + + pub const b0: Register = .{ .alias = .v0, .format = .{ .scalar = .byte } }; + pub const b1: Register = .{ .alias = .v1, .format = .{ .scalar = .byte } }; + pub const b2: Register = .{ .alias = .v2, .format = .{ .scalar = .byte } }; + pub const b3: Register = .{ .alias = .v3, .format = .{ .scalar = .byte } }; + pub const b4: Register = .{ .alias = .v4, .format = .{ .scalar = .byte } }; + pub const b5: Register = .{ .alias = .v5, .format = .{ .scalar = .byte } }; + pub const b6: Register = .{ .alias = .v6, .format = .{ .scalar = .byte } }; + pub const b7: Register = .{ .alias = .v7, .format = .{ .scalar = .byte } }; + pub const b8: Register = .{ .alias = .v8, .format = .{ .scalar = .byte } }; + pub const b9: Register = .{ .alias = .v9, .format = .{ .scalar = .byte } }; + pub const b10: Register = .{ .alias = .v10, .format = .{ .scalar = .byte } }; + pub const b11: Register = .{ .alias = .v11, .format = .{ .scalar = .byte } }; + pub const b12: Register = .{ .alias = .v12, .format = .{ .scalar = .byte } }; + pub const b13: Register = .{ .alias = .v13, .format = .{ .scalar = .byte } }; + pub const b14: Register = .{ .alias = .v14, .format = .{ .scalar = .byte } }; + pub const b15: Register = .{ .alias = .v15, .format = .{ .scalar = .byte } }; + pub const b16: Register = .{ .alias = .v16, .format = .{ .scalar = .byte } }; + pub const b17: Register = .{ .alias = .v17, .format = .{ .scalar = .byte } }; + pub const b18: Register = .{ .alias = .v18, .format = .{ .scalar = .byte } }; + pub const b19: Register = .{ .alias = .v19, .format = .{ .scalar = .byte } }; + pub const b20: Register = .{ .alias = .v20, .format = .{ .scalar = .byte } }; + pub const b21: Register = .{ .alias = .v21, .format = .{ .scalar = .byte } }; + pub const b22: Register = .{ .alias = .v22, .format = .{ .scalar = .byte } }; + pub const b23: Register = .{ .alias = .v23, .format = .{ .scalar = .byte } }; + pub const b24: Register = .{ .alias = .v24, .format = .{ .scalar = .byte } }; + pub const b25: Register = .{ .alias = .v25, .format = .{ .scalar = .byte } }; + pub const b26: Register = .{ .alias = .v26, .format = .{ .scalar = .byte } }; + pub const b27: Register = .{ .alias = .v27, .format = .{ .scalar = .byte } }; + pub const b28: Register = .{ .alias = .v28, .format = .{ .scalar = .byte } }; + pub const b29: Register = .{ .alias = .v29, .format = .{ .scalar = .byte } }; + pub const b30: Register = .{ .alias = .v30, .format = .{ .scalar = .byte } }; + pub const b31: Register = .{ .alias = .v31, .format = .{ .scalar = .byte } }; + + pub const fpcr: Register = .{ .alias = .fpcr, .format = .{ .integer = .doubleword } }; + pub const fpsr: Register = .{ .alias = .fpsr, .format = .{ .integer = .doubleword } }; + + pub const z0: Register = .{ .alias = .v0, .format = .{ .scalar = .scalable } }; + pub const z1: Register = .{ .alias = .v1, .format = .{ .scalar = .scalable } }; + pub const z2: Register = .{ .alias = .v2, .format = .{ .scalar = .scalable } }; + pub const z3: Register = .{ .alias = .v3, .format = .{ .scalar = .scalable } }; + pub const z4: Register = .{ .alias = .v4, .format = .{ .scalar = .scalable } }; + pub const z5: Register = .{ .alias = .v5, .format = .{ .scalar = .scalable } }; + pub const z6: Register = .{ .alias = .v6, .format = .{ .scalar = .scalable } }; + pub const z7: Register = .{ .alias = .v7, .format = .{ .scalar = .scalable } }; + pub const z8: Register = .{ .alias = .v8, .format = .{ .scalar = .scalable } }; + pub const z9: Register = .{ .alias = .v9, .format = .{ .scalar = .scalable } }; + pub const z10: Register = .{ .alias = .v10, .format = .{ .scalar = .scalable } }; + pub const z11: Register = .{ .alias = .v11, .format = .{ .scalar = .scalable } }; + pub const z12: Register = .{ .alias = .v12, .format = .{ .scalar = .scalable } }; + pub const z13: Register = .{ .alias = .v13, .format = .{ .scalar = .scalable } }; + pub const z14: Register = .{ .alias = .v14, .format = .{ .scalar = .scalable } }; + pub const z15: Register = .{ .alias = .v15, .format = .{ .scalar = .scalable } }; + pub const z16: Register = .{ .alias = .v16, .format = .{ .scalar = .scalable } }; + pub const z17: Register = .{ .alias = .v17, .format = .{ .scalar = .scalable } }; + pub const z18: Register = .{ .alias = .v18, .format = .{ .scalar = .scalable } }; + pub const z19: Register = .{ .alias = .v19, .format = .{ .scalar = .scalable } }; + pub const z20: Register = .{ .alias = .v20, .format = .{ .scalar = .scalable } }; + pub const z21: Register = .{ .alias = .v21, .format = .{ .scalar = .scalable } }; + pub const z22: Register = .{ .alias = .v22, .format = .{ .scalar = .scalable } }; + pub const z23: Register = .{ .alias = .v23, .format = .{ .scalar = .scalable } }; + pub const z24: Register = .{ .alias = .v24, .format = .{ .scalar = .scalable } }; + pub const z25: Register = .{ .alias = .v25, .format = .{ .scalar = .scalable } }; + pub const z26: Register = .{ .alias = .v26, .format = .{ .scalar = .scalable } }; + pub const z27: Register = .{ .alias = .v27, .format = .{ .scalar = .scalable } }; + pub const z28: Register = .{ .alias = .v28, .format = .{ .scalar = .scalable } }; + pub const z29: Register = .{ .alias = .v29, .format = .{ .scalar = .scalable } }; + pub const z30: Register = .{ .alias = .v30, .format = .{ .scalar = .scalable } }; + pub const z31: Register = .{ .alias = .v31, .format = .{ .scalar = .scalable } }; + + pub const p0: Register = .{ .alias = .v0, .format = .{ .scalar = .predicate } }; + pub const p1: Register = .{ .alias = .v1, .format = .{ .scalar = .predicate } }; + pub const p2: Register = .{ .alias = .v2, .format = .{ .scalar = .predicate } }; + pub const p3: Register = .{ .alias = .v3, .format = .{ .scalar = .predicate } }; + pub const p4: Register = .{ .alias = .v4, .format = .{ .scalar = .predicate } }; + pub const p5: Register = .{ .alias = .v5, .format = .{ .scalar = .predicate } }; + pub const p6: Register = .{ .alias = .v6, .format = .{ .scalar = .predicate } }; + pub const p7: Register = .{ .alias = .v7, .format = .{ .scalar = .predicate } }; + pub const p8: Register = .{ .alias = .v8, .format = .{ .scalar = .predicate } }; + pub const p9: Register = .{ .alias = .v9, .format = .{ .scalar = .predicate } }; + pub const p10: Register = .{ .alias = .v10, .format = .{ .scalar = .predicate } }; + pub const p11: Register = .{ .alias = .v11, .format = .{ .scalar = .predicate } }; + pub const p12: Register = .{ .alias = .v12, .format = .{ .scalar = .predicate } }; + pub const p13: Register = .{ .alias = .v13, .format = .{ .scalar = .predicate } }; + pub const p14: Register = .{ .alias = .v14, .format = .{ .scalar = .predicate } }; + pub const p15: Register = .{ .alias = .v15, .format = .{ .scalar = .predicate } }; + + pub const ffr: Register = .{ .alias = .ffr, .format = .{ .integer = .doubleword } }; + + pub const Encoded = enum(u5) { + _, + + pub fn decodeInteger(enc: Encoded, sf_enc: IntegerSize, opts: struct { sp: bool = false }) Register { + return switch (sf_enc) { + .word => switch (@intFromEnum(enc)) { + 0 => .w0, + 1 => .w1, + 2 => .w2, + 3 => .w3, + 4 => .w4, + 5 => .w5, + 6 => .w6, + 7 => .w7, + 8 => .w8, + 9 => .w9, + 10 => .w10, + 11 => .w11, + 12 => .w12, + 13 => .w13, + 14 => .w14, + 15 => .w15, + 16 => .w16, + 17 => .w17, + 18 => .w18, + 19 => .w19, + 20 => .w20, + 21 => .w21, + 22 => .w22, + 23 => .w23, + 24 => .w24, + 25 => .w25, + 26 => .w26, + 27 => .w27, + 28 => .w28, + 29 => .w29, + 30 => .w30, + 31 => if (opts.sp) .wsp else .wzr, + }, + .doubleword => switch (@intFromEnum(enc)) { + 0 => .x0, + 1 => .x1, + 2 => .x2, + 3 => .x3, + 4 => .x4, + 5 => .x5, + 6 => .x6, + 7 => .x7, + 8 => .x8, + 9 => .x9, + 10 => .x10, + 11 => .x11, + 12 => .x12, + 13 => .x13, + 14 => .x14, + 15 => .x15, + 16 => .x16, + 17 => .x17, + 18 => .x18, + 19 => .x19, + 20 => .x20, + 21 => .x21, + 22 => .x22, + 23 => .x23, + 24 => .x24, + 25 => .x25, + 26 => .x26, + 27 => .x27, + 28 => .x28, + 29 => .x29, + 30 => .x30, + 31 => if (opts.sp) .sp else .xzr, + }, + }; + } + + pub fn decodeVector(enc: Encoded, vs_enc: VectorSize) Register { + return switch (vs_enc) { + .byte => switch (@intFromEnum(enc)) { + 0 => .b0, + 1 => .b1, + 2 => .b2, + 3 => .b3, + 4 => .b4, + 5 => .b5, + 6 => .b6, + 7 => .b7, + 8 => .b8, + 9 => .b9, + 10 => .b10, + 11 => .b11, + 12 => .b12, + 13 => .b13, + 14 => .b14, + 15 => .b15, + 16 => .b16, + 17 => .b17, + 18 => .b18, + 19 => .b19, + 20 => .b20, + 21 => .b21, + 22 => .b22, + 23 => .b23, + 24 => .b24, + 25 => .b25, + 26 => .b26, + 27 => .b27, + 28 => .b28, + 29 => .b29, + 30 => .b30, + 31 => .b31, + }, + .half => switch (@intFromEnum(enc)) { + 0 => .h0, + 1 => .h1, + 2 => .h2, + 3 => .h3, + 4 => .h4, + 5 => .h5, + 6 => .h6, + 7 => .h7, + 8 => .h8, + 9 => .h9, + 10 => .h10, + 11 => .h11, + 12 => .h12, + 13 => .h13, + 14 => .h14, + 15 => .h15, + 16 => .h16, + 17 => .h17, + 18 => .h18, + 19 => .h19, + 20 => .h20, + 21 => .h21, + 22 => .h22, + 23 => .h23, + 24 => .h24, + 25 => .h25, + 26 => .h26, + 27 => .h27, + 28 => .h28, + 29 => .h29, + 30 => .h30, + 31 => .h31, + }, + .single => switch (@intFromEnum(enc)) { + 0 => .s0, + 1 => .s1, + 2 => .s2, + 3 => .s3, + 4 => .s4, + 5 => .s5, + 6 => .s6, + 7 => .s7, + 8 => .s8, + 9 => .s9, + 10 => .s10, + 11 => .s11, + 12 => .s12, + 13 => .s13, + 14 => .s14, + 15 => .s15, + 16 => .s16, + 17 => .s17, + 18 => .s18, + 19 => .s19, + 20 => .s20, + 21 => .s21, + 22 => .s22, + 23 => .s23, + 24 => .s24, + 25 => .s25, + 26 => .s26, + 27 => .s27, + 28 => .s28, + 29 => .s29, + 30 => .s30, + 31 => .s31, + }, + .double => switch (@intFromEnum(enc)) { + 0 => .d0, + 1 => .d1, + 2 => .d2, + 3 => .d3, + 4 => .d4, + 5 => .d5, + 6 => .d6, + 7 => .d7, + 8 => .d8, + 9 => .d9, + 10 => .d10, + 11 => .d11, + 12 => .d12, + 13 => .d13, + 14 => .d14, + 15 => .d15, + 16 => .d16, + 17 => .d17, + 18 => .d18, + 19 => .d19, + 20 => .d20, + 21 => .d21, + 22 => .d22, + 23 => .d23, + 24 => .d24, + 25 => .d25, + 26 => .d26, + 27 => .d27, + 28 => .d28, + 29 => .d29, + 30 => .d30, + 31 => .d31, + }, + .quad => switch (@intFromEnum(enc)) { + 0 => .q0, + 1 => .q1, + 2 => .q2, + 3 => .q3, + 4 => .q4, + 5 => .q5, + 6 => .q6, + 7 => .q7, + 8 => .q8, + 9 => .q9, + 10 => .q10, + 11 => .q11, + 12 => .q12, + 13 => .q13, + 14 => .q14, + 15 => .q15, + 16 => .q16, + 17 => .q17, + 18 => .q18, + 19 => .q19, + 20 => .q20, + 21 => .q21, + 22 => .q22, + 23 => .q23, + 24 => .q24, + 25 => .q25, + 26 => .q26, + 27 => .q27, + 28 => .q28, + 29 => .q29, + 30 => .q30, + 31 => .q31, + }, + .scalable => switch (@intFromEnum(enc)) { + 0 => .z0, + 1 => .z1, + 2 => .z2, + 3 => .z3, + 4 => .z4, + 5 => .z5, + 6 => .z6, + 7 => .z7, + 8 => .z8, + 9 => .z9, + 10 => .z10, + 11 => .z11, + 12 => .z12, + 13 => .z13, + 14 => .z14, + 15 => .z15, + 16 => .z16, + 17 => .z17, + 18 => .z18, + 19 => .z19, + 20 => .z20, + 21 => .z21, + 22 => .z22, + 23 => .z23, + 24 => .z24, + 25 => .z25, + 26 => .z26, + 27 => .z27, + 28 => .z28, + 29 => .z29, + 30 => .z30, + 31 => .z31, + }, + .predicate => switch (@as(u4, @intCast(@intFromEnum(enc)))) { + 0 => .p0, + 1 => .p1, + 2 => .p2, + 3 => .p3, + 4 => .p4, + 5 => .p5, + 6 => .p6, + 7 => .p7, + 8 => .p8, + 9 => .p9, + 10 => .p10, + 11 => .p11, + 12 => .p12, + 13 => .p13, + 14 => .p14, + 15 => .p15, + }, + }; + } + }; + + /// One tag per set of aliasing registers. + pub const Alias = enum(u7) { + r0, + r1, + r2, + r3, + r4, + r5, + r6, + r7, + r8, + r9, + r10, + r11, + r12, + r13, + r14, + r15, + r16, + r17, + r18, + r19, + r20, + r21, + r22, + r23, + r24, + r25, + r26, + r27, + r28, + r29, + r30, + zr, + sp, + + pc, + + v0, + v1, + v2, + v3, + v4, + v5, + v6, + v7, + v8, + v9, + v10, + v11, + v12, + v13, + v14, + v15, + v16, + v17, + v18, + v19, + v20, + v21, + v22, + v23, + v24, + v25, + v26, + v27, + v28, + v29, + v30, + v31, + + fpcr, + fpsr, + + p0, + p1, + p2, + p3, + p4, + p5, + p6, + p7, + p8, + p9, + p10, + p11, + p12, + p13, + p14, + p15, + + ffr, + + pub const ip0: Alias = .r16; + pub const ip1: Alias = .r17; + pub const fp: Alias = .r29; + pub const lr: Alias = .r30; + + pub fn r(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.pc)); + return .{ .alias = ra, .format = .alias }; + } + pub fn x(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.sp)); + return .{ .alias = ra, .format = .{ .integer = .doubleword } }; + } + pub fn w(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.sp)); + return .{ .alias = ra, .format = .{ .integer = .word } }; + } + pub fn v(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .alias }; + } + pub fn q(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .scalar = .quad } }; + } + pub fn d(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .scalar = .double } }; + } + pub fn s(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .scalar = .single } }; + } + pub fn h(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .scalar = .half } }; + } + pub fn b(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .scalar = .byte } }; + } + pub fn z(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .scalar = .scalable } }; + } + pub fn p(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.p0) and @intFromEnum(ra) <= @intFromEnum(Alias.p15)); + return .{ .alias = ra, .format = .{ .scalar = .predicate } }; + } + pub fn @"2d"(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .vector = .@"2d" } }; + } + pub fn @"4s"(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .vector = .@"4s" } }; + } + pub fn @"8h"(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .vector = .@"8h" } }; + } + pub fn @"16b"(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .vector = .@"16b" } }; + } + pub fn @"1d"(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .vector = .@"1d" } }; + } + pub fn @"2s"(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .vector = .@"2s" } }; + } + pub fn @"4h"(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .vector = .@"4h" } }; + } + pub fn @"8b"(ra: Alias) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .vector = .@"8b" } }; + } + pub fn @"d[]"(ra: Alias, index: u1) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .element = .{ .size = .double, .index = index } } }; + } + pub fn @"s[]"(ra: Alias, index: u2) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .element = .{ .size = .single, .index = index } } }; + } + pub fn @"h[]"(ra: Alias, index: u3) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .element = .{ .size = .half, .index = index } } }; + } + pub fn @"b[]"(ra: Alias, index: u4) Register { + assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); + return .{ .alias = ra, .format = .{ .element = .{ .size = .byte, .index = index } } }; + } + + pub fn isVector(ra: Alias) bool { + return switch (ra) { + .r0, + .r1, + .r2, + .r3, + .r4, + .r5, + .r6, + .r7, + .r8, + .r9, + .r10, + .r11, + .r12, + .r13, + .r14, + .r15, + .r16, + .r17, + .r18, + .r19, + .r20, + .r21, + .r22, + .r23, + .r24, + .r25, + .r26, + .r27, + .r28, + .r29, + .r30, + .zr, + .sp, + + .pc, + + .fpcr, + .fpsr, + + .ffr, + => false, + + .v0, + .v1, + .v2, + .v3, + .v4, + .v5, + .v6, + .v7, + .v8, + .v9, + .v10, + .v11, + .v12, + .v13, + .v14, + .v15, + .v16, + .v17, + .v18, + .v19, + .v20, + .v21, + .v22, + .v23, + .v24, + .v25, + .v26, + .v27, + .v28, + .v29, + .v30, + .v31, + + .p0, + .p1, + .p2, + .p3, + .p4, + .p5, + .p6, + .p7, + .p8, + .p9, + .p10, + .p11, + .p12, + .p13, + .p14, + .p15, + => true, + }; + } + + pub fn encode(ra: Alias, comptime opts: struct { sp: bool = false, V: bool = false }) Encoded { + return @enumFromInt(@as(u5, switch (ra) { + .r0 => if (opts.V) unreachable else 0, + .r1 => if (opts.V) unreachable else 1, + .r2 => if (opts.V) unreachable else 2, + .r3 => if (opts.V) unreachable else 3, + .r4 => if (opts.V) unreachable else 4, + .r5 => if (opts.V) unreachable else 5, + .r6 => if (opts.V) unreachable else 6, + .r7 => if (opts.V) unreachable else 7, + .r8 => if (opts.V) unreachable else 8, + .r9 => if (opts.V) unreachable else 9, + .r10 => if (opts.V) unreachable else 10, + .r11 => if (opts.V) unreachable else 11, + .r12 => if (opts.V) unreachable else 12, + .r13 => if (opts.V) unreachable else 13, + .r14 => if (opts.V) unreachable else 14, + .r15 => if (opts.V) unreachable else 15, + .r16 => if (opts.V) unreachable else 16, + .r17 => if (opts.V) unreachable else 17, + .r18 => if (opts.V) unreachable else 18, + .r19 => if (opts.V) unreachable else 19, + .r20 => if (opts.V) unreachable else 20, + .r21 => if (opts.V) unreachable else 21, + .r22 => if (opts.V) unreachable else 22, + .r23 => if (opts.V) unreachable else 23, + .r24 => if (opts.V) unreachable else 24, + .r25 => if (opts.V) unreachable else 25, + .r26 => if (opts.V) unreachable else 26, + .r27 => if (opts.V) unreachable else 27, + .r28 => if (opts.V) unreachable else 28, + .r29 => if (opts.V) unreachable else 29, + .r30 => if (opts.V) unreachable else 30, + .zr => if (opts.sp or opts.V) unreachable else 31, + .sp => if (opts.sp and !opts.V) 31 else unreachable, + .pc => unreachable, + .v0 => if (opts.V) 0 else unreachable, + .v1 => if (opts.V) 1 else unreachable, + .v2 => if (opts.V) 2 else unreachable, + .v3 => if (opts.V) 3 else unreachable, + .v4 => if (opts.V) 4 else unreachable, + .v5 => if (opts.V) 5 else unreachable, + .v6 => if (opts.V) 6 else unreachable, + .v7 => if (opts.V) 7 else unreachable, + .v8 => if (opts.V) 8 else unreachable, + .v9 => if (opts.V) 9 else unreachable, + .v10 => if (opts.V) 10 else unreachable, + .v11 => if (opts.V) 11 else unreachable, + .v12 => if (opts.V) 12 else unreachable, + .v13 => if (opts.V) 13 else unreachable, + .v14 => if (opts.V) 14 else unreachable, + .v15 => if (opts.V) 15 else unreachable, + .v16 => if (opts.V) 16 else unreachable, + .v17 => if (opts.V) 17 else unreachable, + .v18 => if (opts.V) 18 else unreachable, + .v19 => if (opts.V) 19 else unreachable, + .v20 => if (opts.V) 20 else unreachable, + .v21 => if (opts.V) 21 else unreachable, + .v22 => if (opts.V) 22 else unreachable, + .v23 => if (opts.V) 23 else unreachable, + .v24 => if (opts.V) 24 else unreachable, + .v25 => if (opts.V) 25 else unreachable, + .v26 => if (opts.V) 26 else unreachable, + .v27 => if (opts.V) 27 else unreachable, + .v28 => if (opts.V) 28 else unreachable, + .v29 => if (opts.V) 29 else unreachable, + .v30 => if (opts.V) 30 else unreachable, + .v31 => if (opts.V) 31 else unreachable, + .fpcr, .fpsr => unreachable, + .p0, .p1, .p2, .p3, .p4, .p5, .p6, .p7, .p8, .p9, .p10, .p11, .p12, .p13, .p14, .p15 => unreachable, + .ffr => unreachable, + })); + } + }; + + pub fn isVector(reg: Register) bool { + return reg.alias.isVector(); + } + + pub fn size(reg: Register) ?u5 { + return format: switch (reg.format) { + .alias => unreachable, + .integer => |sf| switch (sf) { + .word => 4, + .doubleword => 8, + }, + .vector => |vs| switch (vs) { + .byte => 1, + .word => 2, + .single => 4, + .double => 8, + .quad => 16, + .scalable, .predicate => null, + }, + .arrangement => |arrangement| switch (arrangement) { + .@"2d", .@"4s", .@"8h", .@"16b" => 16, + .@"1d", .@"2s", .@"4h", .@"8b" => 8, + }, + .element => |element| continue :format .{ .vector = element.size }, + }; + } + + pub fn parse(reg: []const u8) ?Register { + return if (reg.len == 0) null else switch (reg[0]) { + else => null, + 'r' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) { + 0...30 => .{ + .alias = @enumFromInt(@intFromEnum(Alias.r0) + n), + .format = .alias, + }, + 31 => null, + } else |_| null, + 'x' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) { + 0...30 => .{ + .alias = @enumFromInt(@intFromEnum(Alias.r0) + n), + .format = .{ .integer = .doubleword }, + }, + 31 => null, + } else |_| if (std.mem.eql(u8, reg, "xzr")) .xzr else null, + 'w' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) { + 0...30 => .{ + .alias = @enumFromInt(@intFromEnum(Alias.r0) + n), + .format = .{ .integer = .word }, + }, + 31 => null, + } else |_| if (std.mem.eql(u8, reg, "wzr")) + .wzr + else if (std.mem.eql(u8, reg, "wsp")) + .wsp + else + null, + 'i' => return if (std.mem.eql(u8, reg, "ip") or std.mem.eql(u8, reg, "ip0")) + .ip0 + else if (std.mem.eql(u8, reg, "ip1")) + .ip1 + else + null, + 'f' => return if (std.mem.eql(u8, reg, "fp")) .fp else null, + 'p' => return if (std.mem.eql(u8, reg, "pc")) .pc else null, + 'v' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ + .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), + .format = .alias, + } else |_| null, + 'q' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ + .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), + .format = .{ .scalar = .quad }, + } else |_| null, + 'd' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ + .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), + .format = .{ .scalar = .double }, + } else |_| null, + 's' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ + .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), + .format = .{ .scalar = .single }, + } else |_| if (std.mem.eql(u8, reg, "sp")) .sp else null, + 'h' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ + .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), + .format = .{ .scalar = .half }, + } else |_| null, + 'b' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ + .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), + .format = .{ .scalar = .byte }, + } else |_| null, + }; + } + + pub fn fmt(reg: Register) aarch64.Disassemble.RegisterFormatter { + return reg.fmtCase(.lower); + } + pub fn fmtCase(reg: Register, case: aarch64.Disassemble.Case) aarch64.Disassemble.RegisterFormatter { + return .{ .reg = reg, .case = case }; + } +}; + +/// C1.2.4 Condition code +pub const ConditionCode = enum(u4) { + /// integer: Equal + /// floating-point: Equal + /// Z == 1 + eq = 0b0000, + /// integer: Not equal + /// floating-point: Not equal or unordered + /// Z == 0 + ne = 0b0001, + /// integer: Unsigned higher or same + /// floating-point: Greater than, equal, or unordered + /// C == 1 + hs = 0b0010, + /// integer: Unsigned lower + /// floating-point: Less than + /// C == 0 + lo = 0b0011, + /// integer: Minus, negative + /// floating-point: Less than + /// N == 1 + mi = 0b0100, + /// integer: Plus, positive or zero + /// floating-point: Greater than, equal, or unordered + /// N == 0 + pl = 0b0101, + /// integer: Overflow + /// floating-point: Unordered + /// V == 1 + vs = 0b0110, + /// integer: No overflow + /// floating-point: Ordered + /// V == 0 + vc = 0b0111, + /// integer: Unsigned higher + /// floating-point: Greater than, or unordered + /// C == 1 and Z == 0 + hi = 0b1000, + /// integer: Unsigned lower or same + /// floating-point: Less than or equal + /// C == 0 or Z == 1 + ls = 0b1001, + /// integer: Signed greater than or equal + /// floating-point: Greater than or equal + /// N == V + ge = 0b1010, + /// integer: Signed less than + /// floating-point: Less than, or unordered + /// N != V + lt = 0b1011, + /// integer: Signed greater than + /// floating-point: Greater than + /// Z == 0 and N == V + gt = 0b1100, + /// integer: Signed less than or equal + /// floating-point: Less than, equal, or unordered + /// Z == 1 or N != V + le = 0b1101, + /// integer: Always + /// floating-point: Always + /// true + al = 0b1110, + /// integer: Always + /// floating-point: Always + /// true + nv = 0b1111, + /// Carry set + /// C == 1 + pub const cs: ConditionCode = .hs; + /// Carry clear + /// C == 0 + pub const cc: ConditionCode = .lo; + + pub fn invert(cond: ConditionCode) ConditionCode { + return @enumFromInt(@intFromEnum(cond) ^ 0b0001); + } +}; + +/// C4.1 A64 instruction set encoding +pub const Instruction = packed union { + group: Group, + reserved: Reserved, + sme: Sme, + sve: Sve, + data_processing_immediate: DataProcessingImmediate, + branch_exception_generating_system: BranchExceptionGeneratingSystem, + load_store: LoadStore, + data_processing_register: DataProcessingRegister, + data_processing_vector: DataProcessingVector, + + /// Table C4-1 Main encoding table for the A64 instruction set + pub const Group = packed struct { + encoded0: u25, + op1: u4, + encoded29: u2, + op0: u1, + }; + + /// C4.1.1 Reserved + pub const Reserved = packed union { + group: @This().Group, + udf: Udf, + + /// Table C4-2 Encoding table for the Reserved group + pub const Group = packed struct { + encoded0: u16, + op1: u9, + decoded25: u4 = 0b0000, + op0: u2, + decoded31: u1 = 0b0, + }; + + /// C6.2.387 UDF + pub const Udf = packed struct { + imm16: u16, + decoded16: u16 = 0b0000000000000000, + }; + + pub const Decoded = union(enum) { + unallocated, + udf: Udf, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.op0) { + 0b00 => switch (inst.group.op1) { + 0b000000000 => .{ .udf = inst.udf }, + else => .unallocated, + }, + else => .unallocated, + }; + } + }; + + /// C4.1.2 SME encodings + pub const Sme = packed union { + group: @This().Group, + + /// Table C4-3 Encodings table for the SME encodings group + pub const Group = packed struct { + encoded0: u2, + op2: u3, + encoded5: u5, + op1: u15, + decoded25: u4 = 0b0000, + op0: u2, + decoded31: u1 = 0b1, + }; + }; + + /// C4.1.30 SVE encodings + pub const Sve = packed union { + group: @This().Group, + + /// Table C4-31 Encoding table for the SVE encodings group + pub const Group = packed struct { + encoded0: u4, + op2: u1, + encoded5: u5, + op1: u15, + decoded25: u4 = 0b0010, + op0: u3, + }; + }; + + /// C4.1.86 Data Processing -- Immediate + pub const DataProcessingImmediate = packed union { + group: @This().Group, + pc_relative_addressing: PcRelativeAddressing, + add_subtract_immediate: AddSubtractImmediate, + add_subtract_immediate_with_tags: AddSubtractImmediateWithTags, + logical_immediate: LogicalImmediate, + move_wide_immediate: MoveWideImmediate, + bitfield: Bitfield, + extract: Extract, + + /// Table C4-87 Encoding table for the Data Processing -- Immediate group + pub const Group = packed struct { + encoded0: u23, + op0: u3, + decoded26: u3 = 0b100, + encoded29: u3, + }; + + /// PC-rel. addressing + pub const PcRelativeAddressing = packed union { + group: @This().Group, + adr: Adr, + adrp: Adrp, + + pub const Group = packed struct { + Rd: Register.Encoded, + immhi: i19, + decoded24: u5 = 0b10000, + immlo: u2, + op: Op, + }; + + /// C6.2.10 ADR + pub const Adr = packed struct { + Rd: Register.Encoded, + immhi: i19, + decoded24: u5 = 0b10000, + immlo: u2, + op: Op = .adr, + }; + + /// C6.2.11 ADRP + pub const Adrp = packed struct { + Rd: Register.Encoded, + immhi: i19, + decoded24: u5 = 0b10000, + immlo: u2, + op: Op = .adrp, + }; + + pub const Op = enum(u1) { + adr = 0b0, + adrp = 0b1, + }; + }; + + /// Add/subtract (immediate) + pub const AddSubtractImmediate = packed union { + group: @This().Group, + add: Add, + adds: Adds, + sub: Sub, + subs: Subs, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + sh: Shift, + decoded23: u6 = 0b100010, + S: bool, + op: AddSubtractOp, + sf: Register.IntegerSize, + }; + + /// C6.2.4 ADD (immediate) + pub const Add = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + sh: Shift, + decoded23: u6 = 0b100010, + S: bool = false, + op: AddSubtractOp = .add, + sf: Register.IntegerSize, + }; + + /// C6.2.8 ADDS (immediate) + pub const Adds = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + sh: Shift, + decoded23: u6 = 0b100010, + S: bool = true, + op: AddSubtractOp = .add, + sf: Register.IntegerSize, + }; + + /// C6.2.357 SUB (immediate) + pub const Sub = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + sh: Shift, + decoded23: u6 = 0b100010, + S: bool = false, + op: AddSubtractOp = .sub, + sf: Register.IntegerSize, + }; + + /// C6.2.363 SUBS (immediate) + pub const Subs = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + sh: Shift, + decoded23: u6 = 0b100010, + S: bool = true, + op: AddSubtractOp = .sub, + sf: Register.IntegerSize, + }; + + pub const Shift = enum(u1) { + @"0" = 0b0, + @"12" = 0b1, + }; + }; + + /// Add/subtract (immediate, with tags) + pub const AddSubtractImmediateWithTags = packed union { + group: @This().Group, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + uimm4: u4, + op3: u2, + uimm6: u6, + o2: u1, + decoded23: u6 = 0b100011, + S: bool, + op: AddSubtractOp, + sf: Register.IntegerSize, + }; + }; + + /// Logical (immediate) + pub const LogicalImmediate = packed union { + group: @This().Group, + @"and": And, + orr: Orr, + eor: Eor, + ands: Ands, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm: Bitmask, + decoded23: u6 = 0b100100, + opc: LogicalOpc, + sf: Register.IntegerSize, + }; + + /// C6.2.12 AND (immediate) + pub const And = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm: Bitmask, + decoded23: u6 = 0b100100, + opc: LogicalOpc = .@"and", + sf: Register.IntegerSize, + }; + + /// C6.2.240 ORR (immediate) + pub const Orr = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm: Bitmask, + decoded23: u6 = 0b100100, + opc: LogicalOpc = .orr, + sf: Register.IntegerSize, + }; + + /// C6.2.119 EOR (immediate) + pub const Eor = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm: Bitmask, + decoded23: u6 = 0b100100, + opc: LogicalOpc = .eor, + sf: Register.IntegerSize, + }; + + /// C6.2.14 ANDS (immediate) + pub const Ands = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm: Bitmask, + decoded23: u6 = 0b100100, + opc: LogicalOpc = .ands, + sf: Register.IntegerSize, + }; + + pub const Decoded = union(enum) { + unallocated, + @"and": And, + orr: Orr, + eor: Eor, + ands: Ands, + }; + pub fn decode(inst: @This()) @This().Decoded { + return if (!inst.group.imm.validImmediate(inst.group.sf)) + .unallocated + else switch (inst.group.opc) { + .@"and" => .{ .@"and" = inst.@"and" }, + .orr => .{ .orr = inst.orr }, + .eor => .{ .eor = inst.eor }, + .ands => .{ .ands = inst.ands }, + }; + } + }; + + /// Move wide (immediate) + pub const MoveWideImmediate = packed union { + group: @This().Group, + movn: Movn, + movz: Movz, + movk: Movk, + + pub const Group = packed struct { + Rd: Register.Encoded, + imm16: u16, + hw: Hw, + decoded23: u6 = 0b100101, + opc: Opc, + sf: Register.IntegerSize, + }; + + /// C6.2.226 MOVN + pub const Movn = packed struct { + Rd: Register.Encoded, + imm16: u16, + hw: Hw, + decoded23: u6 = 0b100101, + opc: Opc = .movn, + sf: Register.IntegerSize, + }; + + /// C6.2.227 MOVZ + pub const Movz = packed struct { + Rd: Register.Encoded, + imm16: u16, + hw: Hw, + decoded23: u6 = 0b100101, + opc: Opc = .movz, + sf: Register.IntegerSize, + }; + + /// C6.2.225 MOVK + pub const Movk = packed struct { + Rd: Register.Encoded, + imm16: u16, + hw: Hw, + decoded23: u6 = 0b100101, + opc: Opc = .movk, + sf: Register.IntegerSize, + }; + + pub const Hw = enum(u2) { + @"0" = 0b00, + @"16" = 0b01, + @"32" = 0b10, + @"48" = 0b11, + + pub fn int(hw: Hw) u6 { + return switch (hw) { + .@"0" => 0, + .@"16" => 16, + .@"32" => 32, + .@"48" => 48, + }; + } + + pub fn sf(hw: Hw) Register.IntegerSize { + return switch (hw) { + .@"0", .@"16" => .word, + .@"32", .@"48" => .doubleword, + }; + } + }; + + pub const Opc = enum(u2) { + movn = 0b00, + movz = 0b10, + movk = 0b11, + _, + }; + + pub const Decoded = union(enum) { + unallocated, + movn: Movn, + movz: Movz, + movk: Movk, + }; + pub fn decode(inst: @This()) @This().Decoded { + return if (inst.group.sf == .word and inst.group.hw.sf() == .doubleword) + .unallocated + else switch (inst.group.opc) { + _ => .unallocated, + .movn => .{ .movn = inst.movn }, + .movz => .{ .movz = inst.movz }, + .movk => .{ .movk = inst.movk }, + }; + } + }; + + /// Bitfield + pub const Bitfield = packed union { + group: @This().Group, + sbfm: Sbfm, + bfm: Bfm, + ubfm: Ubfm, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm: Bitmask, + decoded23: u6 = 0b100110, + opc: Opc, + sf: Register.IntegerSize, + }; + + pub const Sbfm = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm: Bitmask, + decoded23: u6 = 0b100110, + opc: Opc = .sbfm, + sf: Register.IntegerSize, + }; + + pub const Bfm = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm: Bitmask, + decoded23: u6 = 0b100110, + opc: Opc = .bfm, + sf: Register.IntegerSize, + }; + + pub const Ubfm = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm: Bitmask, + decoded23: u6 = 0b100110, + opc: Opc = .ubfm, + sf: Register.IntegerSize, + }; + + pub const Opc = enum(u2) { + sbfm = 0b00, + bfm = 0b01, + ubfm = 0b10, + _, + }; + + pub const Decoded = union(enum) { + unallocated, + sbfm: Sbfm, + bfm: Bfm, + ubfm: Ubfm, + }; + pub fn decode(inst: @This()) @This().Decoded { + return if (!inst.group.imm.validBitfield(inst.group.sf)) + .unallocated + else switch (inst.group.opc) { + _ => .unallocated, + .sbfm => .{ .sbfm = inst.sbfm }, + .bfm => .{ .bfm = inst.bfm }, + .ubfm => .{ .ubfm = inst.ubfm }, + }; + } + }; + + /// Extract + pub const Extract = packed union { + group: @This().Group, + extr: Extr, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imms: u6, + Rm: Register.Encoded, + o0: u1, + N: Register.IntegerSize, + decoded23: u6 = 0b100111, + op21: u2, + sf: Register.IntegerSize, + }; + + pub const Extr = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imms: u6, + Rm: Register.Encoded, + o0: u1 = 0b0, + N: Register.IntegerSize, + decoded23: u6 = 0b100111, + op21: u2 = 0b00, + sf: Register.IntegerSize, + }; + + pub const Decoded = union(enum) { + unallocated, + extr: Extr, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.op21) { + 0b01, 0b10...0b11 => .unallocated, + 0b00 => switch (inst.group.o0) { + 0b1 => .unallocated, + 0b0 => if ((inst.group.sf == .word and @as(u1, @truncate(inst.group.imms >> 5)) == 0b1) or + inst.group.sf != inst.group.N) + .unallocated + else + .{ .extr = inst.extr }, + }, + }; + } + }; + + pub const Bitmask = packed struct { + imms: u6, + immr: u6, + N: Register.IntegerSize, + + fn lenHsb(bitmask: Bitmask) u7 { + return @bitCast(packed struct { + not_imms: u6, + N: Register.IntegerSize, + }{ .not_imms = ~bitmask.imms, .N = bitmask.N }); + } + + fn validImmediate(bitmask: Bitmask, sf: Register.IntegerSize) bool { + if (sf == .word and bitmask.N == .doubleword) return false; + const len_hsb = bitmask.lenHsb(); + return (len_hsb -% 1) & len_hsb != 0b0_000000; + } + + fn validBitfield(bitmask: Bitmask, sf: Register.IntegerSize) bool { + if (sf != bitmask.N) return false; + if (sf == .word and (@as(u1, @truncate(bitmask.immr >> 5)) != 0b0 or + @as(u1, @truncate(bitmask.imms >> 5)) != 0b0)) return false; + const len_hsb = bitmask.lenHsb(); + return len_hsb >= 0b0_000010; + } + + fn decode(bitmask: Bitmask, sf: Register.IntegerSize) struct { u64, u64 } { + const esize = @as(u7, 1 << 6) >> @clz(bitmask.lenHsb()); + const levels: u6 = @intCast(esize - 1); + const s = bitmask.imms & levels; + const r = bitmask.immr & levels; + const d = (s -% r) & levels; + const welem = @as(u64, std.math.maxInt(u64)) >> (63 - s); + const telem = @as(u64, std.math.maxInt(u64)) >> (63 - d); + const emask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - esize); + const rmask = @divExact(std.math.maxInt(u64), emask); + const wmask = std.math.rotr(u64, welem * rmask, r); + const tmask = telem * rmask; + return switch (sf) { + .word => .{ @as(u32, @truncate(wmask)), @as(u32, @truncate(tmask)) }, + .doubleword => .{ wmask, tmask }, + }; + } + + pub fn decodeImmediate(bitmask: Bitmask, sf: Register.IntegerSize) u64 { + assert(bitmask.validImmediate(sf)); + const imm, _ = bitmask.decode(sf); + return imm; + } + + pub fn decodeBitfield(bitmask: Bitmask, sf: Register.IntegerSize) struct { u64, u64 } { + assert(bitmask.validBitfield(sf)); + return bitmask.decode(sf); + } + + pub fn moveWidePreferred(bitmask: Bitmask, sf: Register.IntegerSize) bool { + const s = bitmask.imms; + const r = bitmask.immr; + const width: u7 = switch (sf) { + .word => 32, + .doubleword => 64, + }; + if (sf != bitmask.N) return false; + if (sf == .word and @as(u1, @truncate(s >> 5)) != 0b0) return false; + if (s < 16) return (-%r % 16) <= (15 - s); + if (s >= width - 15) return (r % 16) <= (s - (width - 15)); + return false; + } + }; + + pub const Decoded = union(enum) { + unallocated, + pc_relative_addressing: PcRelativeAddressing, + add_subtract_immediate: AddSubtractImmediate, + add_subtract_immediate_with_tags: AddSubtractImmediateWithTags, + logical_immediate: LogicalImmediate, + move_wide_immediate: MoveWideImmediate, + bitfield: Bitfield, + extract: Extract, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.op0) { + 0b000, 0b001 => .{ .pc_relative_addressing = inst.pc_relative_addressing }, + 0b010 => .{ .add_subtract_immediate = inst.add_subtract_immediate }, + 0b011 => .{ .add_subtract_immediate_with_tags = inst.add_subtract_immediate_with_tags }, + 0b100 => .{ .logical_immediate = inst.logical_immediate }, + 0b101 => .{ .move_wide_immediate = inst.move_wide_immediate }, + 0b110 => .{ .bitfield = inst.bitfield }, + 0b111 => .{ .extract = inst.extract }, + }; + } + }; + + /// C4.1.87 Branches, Exception Generating and System instructions + pub const BranchExceptionGeneratingSystem = packed union { + group: @This().Group, + conditional_branch_immediate: ConditionalBranchImmediate, + exception_generating: ExceptionGenerating, + system_register_argument: SystemRegisterArgument, + hints: Hints, + barriers: Barriers, + pstate: Pstate, + system_result: SystemResult, + system: System, + system_register_move: SystemRegisterMove, + unconditional_branch_register: UnconditionalBranchRegister, + unconditional_branch_immediate: UnconditionalBranchImmediate, + compare_branch_immediate: CompareBranchImmediate, + test_branch_immediate: TestBranchImmediate, + + /// Table C4-88 Encoding table for the Branches, Exception Generating and System instructions group + pub const Group = packed struct { + op2: u5, + encoded5: u7, + op1: u14, + decoded26: u3 = 0b101, + op0: u3, + }; + + /// Conditional branch (immediate) + pub const ConditionalBranchImmediate = packed union { + group: @This().Group, + b: B, + bc: Bc, + + pub const Group = packed struct { + cond: ConditionCode, + o0: u1, + imm19: i19, + o1: u1, + decoded25: u7 = 0b0101010, + }; + + /// C6.2.26 B.cond + pub const B = packed struct { + cond: ConditionCode, + o0: u1 = 0b0, + imm19: i19, + o1: u1 = 0b0, + decoded25: u7 = 0b0101010, + }; + + /// C6.2.27 BC.cond + pub const Bc = packed struct { + cond: ConditionCode, + o0: u1 = 0b1, + imm19: i19, + o1: u1 = 0b0, + decoded25: u7 = 0b0101010, + }; + + pub const Decoded = union(enum) { + unallocated, + b: B, + bc: Bc, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.o1) { + 0b0 => switch (inst.group.o0) { + 0b0 => .{ .b = inst.b }, + 0b1 => .{ .bc = inst.bc }, + }, + 0b1 => .unallocated, + }; + } + }; + + /// Exception generating + pub const ExceptionGenerating = packed union { + group: @This().Group, + svc: Svc, + hvc: Hvc, + smc: Smc, + brk: Brk, + hlt: Hlt, + tcancel: Tcancel, + dcps1: Dcps1, + dcps2: Dcps2, + dcps3: Dcps3, + + pub const Group = packed struct { + LL: u2, + op2: u3, + imm16: u16, + opc: u3, + decoded24: u8 = 0b11010100, + }; + + /// C6.2.365 SVC + pub const Svc = packed struct { + decoded0: u2 = 0b01, + decoded2: u3 = 0b000, + imm16: u16, + decoded21: u3 = 0b000, + decoded24: u8 = 0b11010100, + }; + + /// C6.2.128 HVC + pub const Hvc = packed struct { + decoded0: u2 = 0b10, + decoded2: u3 = 0b000, + imm16: u16, + decoded21: u3 = 0b000, + decoded24: u8 = 0b11010100, + }; + + /// C6.2.283 SMC + pub const Smc = packed struct { + decoded0: u2 = 0b11, + decoded2: u3 = 0b000, + imm16: u16, + decoded21: u3 = 0b000, + decoded24: u8 = 0b11010100, + }; + + /// C6.2.40 BRK + pub const Brk = packed struct { + decoded0: u2 = 0b00, + decoded2: u3 = 0b000, + imm16: u16, + decoded21: u3 = 0b001, + decoded24: u8 = 0b11010100, + }; + + /// C6.2.127 HLT + pub const Hlt = packed struct { + decoded0: u2 = 0b00, + decoded2: u3 = 0b000, + imm16: u16, + decoded21: u3 = 0b010, + decoded24: u8 = 0b11010100, + }; + + /// C6.2.376 TCANCEL + pub const Tcancel = packed struct { + decoded0: u2 = 0b00, + decoded2: u3 = 0b000, + imm16: u16, + decoded21: u3 = 0b011, + decoded24: u8 = 0b11010100, + }; + + /// C6.2.110 DCPS1 + pub const Dcps1 = packed struct { + LL: u2 = 0b01, + decoded2: u3 = 0b000, + imm16: u16, + decoded21: u3 = 0b101, + decoded24: u8 = 0b11010100, + }; + + /// C6.2.110 DCPS2 + pub const Dcps2 = packed struct { + LL: u2 = 0b10, + decoded2: u3 = 0b000, + imm16: u16, + decoded21: u3 = 0b101, + decoded24: u8 = 0b11010100, + }; + + /// C6.2.110 DCPS3 + pub const Dcps3 = packed struct { + LL: u2 = 0b11, + decoded2: u3 = 0b000, + imm16: u16, + decoded21: u3 = 0b101, + decoded24: u8 = 0b11010100, + }; + + pub const Decoded = union(enum) { + unallocated, + svc: Svc, + hvc: Hvc, + smc: Smc, + brk: Brk, + hlt: Hlt, + tcancel: Tcancel, + dcps1: Dcps1, + dcps2: Dcps2, + dcps3: Dcps3, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.op2) { + 0b001 => .unallocated, + 0b010...0b011 => .unallocated, + 0b100...0b111 => .unallocated, + 0b000 => switch (inst.group.opc) { + 0b000 => switch (inst.group.LL) { + 0b00 => .unallocated, + 0b01 => .{ .svc = inst.svc }, + 0b10 => .{ .hvc = inst.hvc }, + 0b11 => .{ .smc = inst.smc }, + }, + 0b001 => switch (inst.group.LL) { + 0b01 => .unallocated, + 0b00 => .{ .brk = inst.brk }, + 0b10...0b11 => .unallocated, + }, + 0b010 => switch (inst.group.LL) { + 0b01 => .unallocated, + 0b00 => .{ .hlt = inst.hlt }, + 0b10...0b11 => .unallocated, + }, + 0b011 => switch (inst.group.LL) { + 0b00 => .{ .tcancel = inst.tcancel }, + 0b01 => .unallocated, + 0b10...0b11 => .unallocated, + }, + 0b100 => .unallocated, + 0b101 => switch (inst.group.LL) { + 0b00 => .unallocated, + 0b01 => .{ .dcps1 = inst.dcps1 }, + 0b10 => .{ .dcps2 = inst.dcps2 }, + 0b11 => .{ .dcps3 = inst.dcps3 }, + }, + 0b110 => .unallocated, + 0b111 => .unallocated, + }, + }; + } + }; + + /// System instructions with register argument + pub const SystemRegisterArgument = packed struct { + Rt: Register.Encoded, + op2: u3, + CRm: u4, + decoded12: u20 = 0b11010101000000110001, + }; + + /// Hints + pub const Hints = packed union { + group: @This().Group, + hint: Hint, + nop: Nop, + yield: Yield, + wfe: Wfe, + wfi: Wfi, + sev: Sev, + sevl: Sevl, + + pub const Group = packed struct { + decoded0: u5 = 0b11111, + op2: u3, + CRm: u4, + decoded12: u20 = 0b11010101000000110010, + }; + + /// C6.2.126 HINT + pub const Hint = packed struct { + decoded0: u5 = 0b11111, + op2: u3, + CRm: u4, + decoded12: u4 = 0b0010, + decoded16: u3 = 0b011, + decoded19: u2 = 0b00, + decoded21: u1 = 0b0, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.238 NOP + pub const Nop = packed struct { + decoded0: u5 = 0b11111, + op2: u3 = 0b000, + CRm: u4 = 0b0000, + decoded12: u4 = 0b0010, + decoded16: u3 = 0b011, + decoded19: u2 = 0b00, + decoded21: u1 = 0b0, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.402 YIELD + pub const Yield = packed struct { + decoded0: u5 = 0b11111, + op2: u3 = 0b001, + CRm: u4 = 0b0000, + decoded12: u4 = 0b0010, + decoded16: u3 = 0b011, + decoded19: u2 = 0b00, + decoded21: u1 = 0b0, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.396 WFE + pub const Wfe = packed struct { + decoded0: u5 = 0b11111, + op2: u3 = 0b010, + CRm: u4 = 0b0000, + decoded12: u4 = 0b0010, + decoded16: u3 = 0b011, + decoded19: u2 = 0b00, + decoded21: u1 = 0b0, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.398 WFI + pub const Wfi = packed struct { + decoded0: u5 = 0b11111, + op2: u3 = 0b011, + CRm: u4 = 0b0000, + decoded12: u4 = 0b0010, + decoded16: u3 = 0b011, + decoded19: u2 = 0b00, + decoded21: u1 = 0b0, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.280 SEV + pub const Sev = packed struct { + decoded0: u5 = 0b11111, + op2: u3 = 0b100, + CRm: u4 = 0b0000, + decoded12: u4 = 0b0010, + decoded16: u3 = 0b011, + decoded19: u2 = 0b00, + decoded21: u1 = 0b0, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.280 SEVL + pub const Sevl = packed struct { + decoded0: u5 = 0b11111, + op2: u3 = 0b101, + CRm: u4 = 0b0000, + decoded12: u4 = 0b0010, + decoded16: u3 = 0b011, + decoded19: u2 = 0b00, + decoded21: u1 = 0b0, + decoded22: u10 = 0b1101010100, + }; + + pub const Decoded = union(enum) { + hint: Hint, + nop: Nop, + yield: Yield, + wfe: Wfe, + wfi: Wfi, + sev: Sev, + sevl: Sevl, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.CRm) { + else => .{ .hint = inst.hint }, + 0b0000 => switch (inst.group.op2) { + else => .{ .hint = inst.hint }, + 0b000 => .{ .nop = inst.nop }, + 0b001 => .{ .yield = inst.yield }, + 0b010 => .{ .wfe = inst.wfe }, + 0b011 => .{ .wfi = inst.wfi }, + 0b100 => .{ .sev = inst.sev }, + 0b101 => .{ .sevl = inst.sevl }, + }, + }; + } + }; + + /// Barriers + pub const Barriers = packed union { + group: @This().Group, + clrex: Clrex, + dsb: Dsb, + dmb: Dmb, + isb: Isb, + sb: Sb, + + pub const Group = packed struct { + Rt: Register.Encoded, + op2: u3, + CRm: u4, + decoded12: u4 = 0b0011, + decoded16: u3 = 0b011, + decoded19: u2 = 0b00, + decoded21: u1 = 0b0, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.56 CLREX + pub const Clrex = packed struct { + Rt: Register.Encoded = @enumFromInt(0b11111), + op2: u3 = 0b010, + CRm: u4, + decoded12: u4 = 0b0011, + decoded16: u3 = 0b011, + decoded19: u2 = 0b00, + decoded21: u1 = 0b0, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.116 DSB + pub const Dsb = packed struct { + Rt: Register.Encoded = @enumFromInt(0b11111), + opc: u2 = 0b00, + decoded7: u1 = 0b1, + CRm: Option, + decoded12: u4 = 0b0011, + decoded16: u3 = 0b011, + decoded19: u2 = 0b00, + decoded21: u1 = 0b0, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.114 DMB + pub const Dmb = packed struct { + Rt: Register.Encoded = @enumFromInt(0b11111), + opc: u2 = 0b01, + decoded7: u1 = 0b1, + CRm: Option, + decoded12: u4 = 0b0011, + decoded16: u3 = 0b011, + decoded19: u2 = 0b00, + decoded21: u1 = 0b0, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.131 ISB + pub const Isb = packed struct { + Rt: Register.Encoded = @enumFromInt(0b11111), + opc: u2 = 0b10, + decoded7: u1 = 0b1, + CRm: Option, + decoded12: u4 = 0b0011, + decoded16: u3 = 0b011, + decoded19: u2 = 0b00, + decoded21: u1 = 0b0, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.264 SB + pub const Sb = packed struct { + Rt: Register.Encoded = @enumFromInt(0b11111), + opc: u2 = 0b11, + decoded7: u1 = 0b1, + CRm: u4 = 0b0000, + decoded12: u4 = 0b0011, + decoded16: u3 = 0b011, + decoded19: u2 = 0b00, + decoded21: u1 = 0b0, + decoded22: u10 = 0b1101010100, + }; + + pub const Option = enum(u4) { + oshld = 0b0001, + oshst = 0b0010, + osh = 0b0011, + nshld = 0b0101, + nshst = 0b0110, + nsh = 0b0111, + ishld = 0b1001, + ishst = 0b1010, + ish = 0b1011, + ld = 0b1101, + st = 0b1110, + sy = 0b1111, + _, + }; + }; + + /// PSTATE + pub const Pstate = packed struct { + Rt: Register.Encoded, + op2: u3, + CRm: u4, + decoded12: u4 = 0b0100, + op1: u3, + decoded19: u13 = 0b1101010100000, + }; + + /// System with result + pub const SystemResult = packed struct { + Rt: Register.Encoded, + op2: u3, + CRm: u4, + CRn: u4, + op1: u3, + decoded19: u13 = 0b1101010100100, + }; + + /// System instructions + pub const System = packed union { + group: @This().Group, + sys: Sys, + sysl: Sysl, + + pub const Group = packed struct { + Rt: Register.Encoded, + op2: u3, + CRm: u4, + CRn: u4, + op1: u3, + decoded19: u2 = 0b01, + L: L, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.372 SYS + pub const Sys = packed struct { + Rt: Register.Encoded, + op2: u3, + CRm: u4, + CRn: u4, + op1: u3, + decoded19: u2 = 0b01, + L: L = .sys, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.373 SYSL + pub const Sysl = packed struct { + Rt: Register.Encoded, + op2: u3, + CRm: u4, + CRn: u4, + op1: u3, + decoded19: u2 = 0b01, + L: L = .sysl, + decoded22: u10 = 0b1101010100, + }; + + const L = enum(u1) { + sys = 0b0, + sysl = 0b1, + }; + + pub const Decoded = union(enum) { + sys: Sys, + sysl: Sysl, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.L) { + .sys => .{ .sys = inst.sys }, + .sysl => .{ .sysl = inst.sysl }, + }; + } + }; + + /// System register move + pub const SystemRegisterMove = packed union { + group: @This().Group, + msr: Msr, + mrs: Mrs, + + pub const Group = packed struct { + Rt: Register.Encoded, + op2: u3, + CRm: u4, + CRn: u4, + op1: u3, + o0: u1, + decoded20: u1 = 0b1, + L: L, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.230 MSR (register) + pub const Msr = packed struct { + Rt: Register.Encoded, + op2: u3, + CRm: u4, + CRn: u4, + op1: u3, + o0: u1, + decoded20: u1 = 0b1, + L: L = .msr, + decoded22: u10 = 0b1101010100, + }; + + /// C6.2.228 MRS + pub const Mrs = packed struct { + Rt: Register.Encoded, + op2: u3, + CRm: u4, + CRn: u4, + op1: u3, + o0: u1, + decoded20: u1 = 0b1, + L: L = .mrs, + decoded22: u10 = 0b1101010100, + }; + + pub const L = enum(u1) { + msr = 0b0, + mrs = 0b1, + }; + + pub const Decoded = union(enum) { + msr: Msr, + mrs: Mrs, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.L) { + .msr => .{ .msr = inst.msr }, + .mrs => .{ .mrs = inst.mrs }, + }; + } + }; + + /// Unconditional branch (register) + pub const UnconditionalBranchRegister = packed union { + group: @This().Group, + br: Br, + blr: Blr, + ret: Ret, + + pub const Group = packed struct { + op4: u5, + Rn: Register.Encoded, + op3: u6, + op2: u5, + opc: u4, + decoded25: u7 = 0b1101011, + }; + + /// C6.2.37 BR + pub const Br = packed struct { + Rm: Register.Encoded = @enumFromInt(0), + Rn: Register.Encoded, + M: bool = false, + A: bool = false, + decoded12: u4 = 0b0000, + decoded16: u5 = 0b11111, + op: u2 = 0b00, + decoded23: u1 = 0b0, + Z: bool = false, + decoded25: u7 = 0b1101011, + }; + + /// C6.2.35 BLR + pub const Blr = packed struct { + Rm: Register.Encoded = @enumFromInt(0), + Rn: Register.Encoded, + M: bool = false, + A: bool = false, + decoded12: u4 = 0b0000, + decoded16: u5 = 0b11111, + op: u2 = 0b01, + decoded23: u1 = 0b0, + Z: bool = false, + decoded25: u7 = 0b1101011, + }; + + /// C6.2.254 RET + pub const Ret = packed struct { + Rm: Register.Encoded = @enumFromInt(0), + Rn: Register.Encoded, + M: bool = false, + A: bool = false, + decoded12: u4 = 0b0000, + decoded16: u5 = 0b11111, + op: u2 = 0b10, + decoded23: u1 = 0b0, + Z: bool = false, + decoded25: u7 = 0b1101011, + }; + + pub const Decoded = union(enum) { + unallocated, + br: Br, + blr: Blr, + ret: Ret, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.op2) { + else => .unallocated, + 0b11111 => switch (inst.group.opc) { + 0b0000 => switch (inst.group.op4) { + else => .unallocated, + 0b00000 => .{ .br = inst.br }, + }, + 0b0001 => switch (inst.group.op4) { + else => .unallocated, + 0b00000 => .{ .blr = inst.blr }, + }, + 0b0010 => switch (inst.group.op4) { + else => .unallocated, + 0b00000 => .{ .ret = inst.ret }, + }, + else => .unallocated, + }, + }; + } + }; + + /// Unconditional branch (immediate) + pub const UnconditionalBranchImmediate = packed union { + group: @This().Group, + b: B, + bl: Bl, + + pub const Group = packed struct { + imm26: i26, + decoded26: u5 = 0b00101, + op: Op, + }; + + /// C6.2.25 B + pub const B = packed struct { + imm26: i26, + decoded26: u5 = 0b00101, + op: Op = .b, + }; + + /// C6.2.34 BL + pub const Bl = packed struct { + imm26: i26, + decoded26: u5 = 0b00101, + op: Op = .bl, + }; + + pub const Op = enum(u1) { + b = 0b0, + bl = 0b1, + }; + }; + + /// Compare and branch (immediate) + pub const CompareBranchImmediate = packed union { + group: @This().Group, + cbz: Cbz, + cbnz: Cbnz, + + pub const Group = packed struct { + Rt: Register.Encoded, + imm19: i19, + op: Op, + decoded25: u6 = 0b011010, + sf: Register.IntegerSize, + }; + + /// C6.2.47 CBZ + pub const Cbz = packed struct { + Rt: Register.Encoded, + imm19: i19, + op: Op = .cbz, + decoded25: u6 = 0b011010, + sf: Register.IntegerSize, + }; + + /// C6.2.46 CBNZ + pub const Cbnz = packed struct { + Rt: Register.Encoded, + imm19: i19, + op: Op = .cbnz, + decoded25: u6 = 0b011010, + sf: Register.IntegerSize, + }; + + pub const Op = enum(u1) { + cbz = 0b0, + cbnz = 0b1, + }; + }; + + /// Test and branch (immediate) + pub const TestBranchImmediate = packed union { + group: @This().Group, + tbz: Tbz, + tbnz: Tbnz, + + pub const Group = packed struct { + Rt: Register.Encoded, + imm14: i14, + b40: u5, + op: Op, + decoded25: u6 = 0b011011, + b5: u1, + }; + + /// C6.2.375 TBZ + pub const Tbz = packed struct { + Rt: Register.Encoded, + imm14: i14, + b40: u5, + op: Op = .tbz, + decoded25: u6 = 0b011011, + b5: u1, + }; + + /// C6.2.374 TBNZ + pub const Tbnz = packed struct { + Rt: Register.Encoded, + imm14: i14, + b40: u5, + op: Op = .tbnz, + decoded25: u6 = 0b011011, + b5: u1, + }; + + pub const Op = enum(u1) { + tbz = 0b0, + tbnz = 0b1, + }; + }; + + pub const Decoded = union(enum) { + unallocated, + conditional_branch_immediate: ConditionalBranchImmediate, + exception_generating: ExceptionGenerating, + system_register_argument: SystemRegisterArgument, + hints: Hints, + barriers: Barriers, + pstate: Pstate, + system_result: SystemResult, + system: System, + system_register_move: SystemRegisterMove, + unconditional_branch_register: UnconditionalBranchRegister, + unconditional_branch_immediate: UnconditionalBranchImmediate, + compare_branch_immediate: CompareBranchImmediate, + test_branch_immediate: TestBranchImmediate, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.op0) { + 0b010 => switch (inst.group.op1) { + 0b000000000000000...0b01111111111111 => .{ .conditional_branch_immediate = inst.conditional_branch_immediate }, + else => .unallocated, + }, + 0b110 => switch (inst.group.op1) { + 0b00000000000000...0b00111111111111 => .{ .exception_generating = inst.exception_generating }, + 0b01000000110001 => .{ .system_register_argument = inst.system_register_argument }, + 0b01000000110010 => switch (inst.group.op2) { + 0b11111 => .{ .hints = inst.hints }, + else => .unallocated, + }, + 0b01000000110011 => .{ .barriers = inst.barriers }, + 0b01000000000100, + 0b01000000010100, + 0b01000000100100, + 0b01000000110100, + 0b01000001000100, + 0b01000001010100, + 0b01000001100100, + 0b01000001110100, + => .{ .pstate = inst.pstate }, + 0b01001000000000...0b01001001111111 => .{ .system_result = inst.system_result }, + 0b01000010000000...0b01000011111111, 0b01001010000000...0b01001011111111 => .{ .system = inst.system }, + 0b01000100000000...0b01000111111111, 0b01001100000000...0b01001111111111 => .{ .system_register_move = inst.system_register_move }, + 0b10000000000000...0b11111111111111 => .{ .unconditional_branch_register = inst.unconditional_branch_register }, + else => .unallocated, + }, + 0b000, 0b100 => .{ .unconditional_branch_immediate = inst.unconditional_branch_immediate }, + 0b001, 0b101 => switch (inst.group.op1) { + 0b00000000000000...0b01111111111111 => .{ .compare_branch_immediate = inst.compare_branch_immediate }, + 0b10000000000000...0b11111111111111 => .{ .test_branch_immediate = inst.test_branch_immediate }, + }, + else => .unallocated, + }; + } + }; + + /// C4.1.88 Loads and Stores + pub const LoadStore = packed union { + group: @This().Group, + register_literal: RegisterLiteral, + memory: Memory, + no_allocate_pair_offset: NoAllocatePairOffset, + register_pair_post_indexed: RegisterPairPostIndexed, + register_pair_offset: RegisterPairOffset, + register_pair_pre_indexed: RegisterPairPreIndexed, + register_unscaled_immediate: RegisterUnscaledImmediate, + register_immediate_post_indexed: RegisterImmediatePostIndexed, + register_unprivileged: RegisterUnprivileged, + register_immediate_pre_indexed: RegisterImmediatePreIndexed, + register_register_offset: RegisterRegisterOffset, + register_unsigned_immediate: RegisterUnsignedImmediate, + + /// Table C4-89 Encoding table for the Loads and Stores group + pub const Group = packed struct { + encoded0: u10, + op4: u2, + encoded12: u4, + op3: u6, + encoded22: u1, + op2: u2, + decoded25: u1 = 0b0, + op1: bool, + decoded27: u1 = 0b1, + op0: u4, + }; + + /// Load register (literal) + pub const RegisterLiteral = packed union { + group: @This().Group, + integer: Integer, + vector: Vector, + + pub const Group = packed struct { + Rt: Register.Encoded, + imm19: i19, + decoded24: u2 = 0b00, + V: bool, + decoded27: u3 = 0b011, + opc: u2, + }; + + pub const Integer = packed union { + group: @This().Group, + ldr: Ldr, + ldrsw: Ldrsw, + prfm: Prfm, + + pub const Group = packed struct { + Rt: Register.Encoded, + imm19: i19, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b011, + opc: u2, + }; + + /// C6.2.167 LDR (literal) + pub const Ldr = packed struct { + Rt: Register.Encoded, + imm19: i19, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b011, + sf: Register.IntegerSize, + opc1: u1 = 0b0, + }; + + /// C6.2.179 LDRSW (literal) + pub const Ldrsw = packed struct { + Rt: Register.Encoded, + imm19: i19, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b011, + opc: u2 = 0b10, + }; + + /// C6.2.248 PRFM (literal) + pub const Prfm = packed struct { + prfop: PrfOp, + imm19: i19, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b011, + opc: u2 = 0b11, + }; + }; + + pub const Vector = packed union { + group: @This().Group, + ldr: Ldr, + + pub const Group = packed struct { + Rt: Register.Encoded, + imm19: i19, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b011, + opc: VectorSize, + }; + + /// C7.2.192 LDR (literal, SIMD&FP) + pub const Ldr = packed struct { + Rt: Register.Encoded, + imm19: i19, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b011, + opc: VectorSize, + }; + }; + + pub const Decoded = union(enum) { + integer: Integer, + vector: Vector, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.V) { + false => .{ .integer = inst.integer }, + true => .{ .vector = inst.vector }, + }; + } + }; + + /// Memory Copy and Memory Set + pub const Memory = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + op2: u4, + Rs: Register.Encoded, + decoded21: u1 = 0b0, + op1: u2, + decoded24: u2 = 0b01, + o0: u1, + decoded27: u3 = 0b011, + size: IntegerSize, + }; + + /// Load/store no-allocate pair (offset) + pub const NoAllocatePairOffset = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L, + decoded23: u3 = 0b000, + V: bool, + decoded27: u3 = 0b101, + opc: u2, + }; + + /// Load/store register pair (post-indexed) + pub const RegisterPairPostIndexed = packed union { + group: @This().Group, + integer: Integer, + vector: Vector, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L, + decoded23: u3 = 0b001, + V: bool, + decoded27: u3 = 0b101, + opc: u2, + }; + + pub const Integer = packed union { + group: @This().Group, + stp: Stp, + ldp: Ldp, + ldpsw: Ldpsw, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L, + decoded23: u3 = 0b001, + V: bool = false, + decoded27: u3 = 0b101, + opc: u2, + }; + + /// C6.2.321 STP + pub const Stp = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .store, + decoded23: u3 = 0b001, + V: bool = false, + decoded27: u3 = 0b101, + opc0: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.164 LDP + pub const Ldp = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .load, + decoded23: u3 = 0b001, + V: bool = false, + decoded27: u3 = 0b101, + opc0: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.165 LDPSW + pub const Ldpsw = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .load, + decoded23: u3 = 0b001, + V: bool = false, + decoded27: u3 = 0b101, + opc: u2 = 0b01, + }; + + pub const Decoded = union(enum) { + unallocated, + stp: Stp, + ldp: Ldp, + ldpsw: Ldpsw, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.opc) { + 0b00, 0b10 => switch (inst.group.L) { + .store => .{ .stp = inst.stp }, + .load => .{ .ldp = inst.ldp }, + }, + 0b01 => switch (inst.group.L) { + else => .unallocated, + .load => .{ .ldpsw = inst.ldpsw }, + }, + else => .unallocated, + }; + } + }; + + pub const Vector = packed union { + group: @This().Group, + stp: Stp, + ldp: Ldp, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L, + decoded23: u3 = 0b001, + V: bool = true, + decoded27: u3 = 0b101, + opc: VectorSize, + }; + + /// C7.2.330 STP (SIMD&FP) + pub const Stp = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .store, + decoded23: u3 = 0b001, + V: bool = true, + decoded27: u3 = 0b101, + opc: VectorSize, + }; + + /// C7.2.190 LDP (SIMD&FP) + pub const Ldp = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .load, + decoded23: u3 = 0b001, + V: bool = true, + decoded27: u3 = 0b101, + opc: VectorSize, + }; + + pub const Decoded = union(enum) { + unallocated, + stp: Stp, + ldp: Ldp, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.opc) { + .single, .double, .quad => switch (inst.group.L) { + .store => .{ .stp = inst.stp }, + .load => .{ .ldp = inst.ldp }, + }, + _ => .unallocated, + }; + } + }; + + pub const Decoded = union(enum) { + integer: Integer, + vector: Vector, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.V) { + false => .{ .integer = inst.integer }, + true => .{ .vector = inst.vector }, + }; + } + }; + + /// Load/store register pair (offset) + pub const RegisterPairOffset = packed union { + group: @This().Group, + integer: Integer, + vector: Vector, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L, + decoded23: u3 = 0b010, + V: bool, + decoded27: u3 = 0b101, + opc: u2, + }; + + pub const Integer = packed union { + group: @This().Group, + stp: Stp, + ldp: Ldp, + ldpsw: Ldpsw, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L, + decoded23: u3 = 0b010, + V: bool = false, + decoded27: u3 = 0b101, + opc: u2, + }; + + /// C6.2.321 STP + pub const Stp = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .store, + decoded23: u3 = 0b010, + V: bool = false, + decoded27: u3 = 0b101, + opc0: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.164 LDP + pub const Ldp = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .load, + decoded23: u3 = 0b010, + V: bool = false, + decoded27: u3 = 0b101, + opc0: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.165 LDPSW + pub const Ldpsw = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .load, + decoded23: u3 = 0b010, + V: bool = false, + decoded27: u3 = 0b101, + opc: u2 = 0b01, + }; + + pub const Decoded = union(enum) { + unallocated, + stp: Stp, + ldp: Ldp, + ldpsw: Ldpsw, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.opc) { + 0b00, 0b10 => switch (inst.group.L) { + .store => .{ .stp = inst.stp }, + .load => .{ .ldp = inst.ldp }, + }, + 0b01 => switch (inst.group.L) { + else => .unallocated, + .load => .{ .ldpsw = inst.ldpsw }, + }, + else => .unallocated, + }; + } + }; + + pub const Vector = packed union { + group: @This().Group, + stp: Stp, + ldp: Ldp, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L, + decoded23: u3 = 0b010, + V: bool = true, + decoded27: u3 = 0b101, + opc: VectorSize, + }; + + /// C7.2.330 STP (SIMD&FP) + pub const Stp = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .store, + decoded23: u3 = 0b010, + V: bool = true, + decoded27: u3 = 0b101, + opc: VectorSize, + }; + + /// C7.2.190 LDP (SIMD&FP) + pub const Ldp = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .load, + decoded23: u3 = 0b010, + V: bool = true, + decoded27: u3 = 0b101, + opc: VectorSize, + }; + + pub const Decoded = union(enum) { + unallocated, + stp: Stp, + ldp: Ldp, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.opc) { + .single, .double, .quad => switch (inst.group.L) { + .store => .{ .stp = inst.stp }, + .load => .{ .ldp = inst.ldp }, + }, + _ => .unallocated, + }; + } + }; + + pub const Decoded = union(enum) { + integer: Integer, + vector: Vector, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.V) { + false => .{ .integer = inst.integer }, + true => .{ .vector = inst.vector }, + }; + } + }; + + /// Load/store register pair (pre-indexed) + pub const RegisterPairPreIndexed = packed union { + group: @This().Group, + integer: Integer, + vector: Vector, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L, + decoded23: u3 = 0b011, + V: bool, + decoded27: u3 = 0b101, + opc: u2, + }; + + pub const Integer = packed union { + group: @This().Group, + stp: Stp, + ldp: Ldp, + ldpsw: Ldpsw, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L, + decoded23: u3 = 0b011, + V: bool = false, + decoded27: u3 = 0b101, + opc: u2, + }; + + /// C6.2.321 STP + pub const Stp = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .store, + decoded23: u3 = 0b011, + V: bool = false, + decoded27: u3 = 0b101, + opc0: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.164 LDP + pub const Ldp = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .load, + decoded23: u3 = 0b011, + V: bool = false, + decoded27: u3 = 0b101, + opc0: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.165 LDPSW + pub const Ldpsw = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .load, + decoded23: u3 = 0b011, + V: bool = false, + decoded27: u3 = 0b101, + opc0: u2 = 0b01, + }; + + pub const Decoded = union(enum) { + unallocated, + stp: Stp, + ldp: Ldp, + ldpsw: Ldpsw, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.opc) { + 0b00, 0b10 => switch (inst.group.L) { + .store => .{ .stp = inst.stp }, + .load => .{ .ldp = inst.ldp }, + }, + 0b01 => switch (inst.group.L) { + else => .unallocated, + .load => .{ .ldpsw = inst.ldpsw }, + }, + else => .unallocated, + }; + } + }; + + pub const Vector = packed union { + group: @This().Group, + stp: Stp, + ldp: Ldp, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L, + decoded23: u3 = 0b011, + V: bool = true, + decoded27: u3 = 0b101, + opc: VectorSize, + }; + + /// C7.2.330 STP (SIMD&FP) + pub const Stp = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .store, + decoded23: u3 = 0b011, + V: bool = true, + decoded27: u3 = 0b101, + opc: VectorSize, + }; + + /// C7.2.190 LDP (SIMD&FP) + pub const Ldp = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + Rt2: Register.Encoded, + imm7: i7, + L: L = .load, + decoded23: u3 = 0b011, + V: bool = true, + decoded27: u3 = 0b101, + opc: VectorSize, + }; + + pub const Decoded = union(enum) { + unallocated, + stp: Stp, + ldp: Ldp, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.opc) { + .single, .double, .quad => switch (inst.group.L) { + .store => .{ .stp = inst.stp }, + .load => .{ .ldp = inst.ldp }, + }, + _ => .unallocated, + }; + } + }; + + pub const Decoded = union(enum) { + integer: Integer, + vector: Vector, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.V) { + false => .{ .integer = inst.integer }, + true => .{ .vector = inst.vector }, + }; + } + }; + + /// Load/store register (unscaled immediate) + pub const RegisterUnscaledImmediate = packed union { + group: @This().Group, + integer: Integer, + vector: Vector, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2, + decoded24: u2 = 0b00, + V: bool, + decoded27: u3 = 0b111, + size: u2, + }; + + pub const Integer = packed union { + group: @This().Group, + sturb: Sturb, + ldurb: Ldurb, + ldursb: Ldursb, + sturh: Sturh, + ldurh: Ldurh, + ldursh: Ldursh, + stur: Stur, + ldur: Ldur, + ldursw: Ldursw, + prfum: Prfum, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize, + }; + + /// C6.2.347 STURB + pub const Sturb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b00, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.203 LDURB + pub const Ldurb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b01, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.205 LDURSB + pub const Ldursb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc0: u1, + opc1: u1 = 0b1, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.348 STURH + pub const Sturh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b00, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.204 LDURH + pub const Ldurh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b01, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.206 LDURSH + pub const Ldursh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc0: u1, + opc1: u1 = 0b1, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.346 STUR + pub const Stur = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b00, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + sf: Register.IntegerSize, + size1: u1 = 0b1, + }; + + /// C6.2.202 LDUR + pub const Ldur = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b01, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + sf: Register.IntegerSize, + size1: u1 = 0b1, + }; + + /// C6.2.207 LDURSW + pub const Ldursw = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b10, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .word, + }; + + /// C6.2.250 PRFUM + pub const Prfum = packed struct { + prfop: PrfOp, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b10, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .doubleword, + }; + + pub const Decoded = union(enum) { + unallocated, + sturb: Sturb, + ldurb: Ldurb, + ldursb: Ldursb, + sturh: Sturh, + ldurh: Ldurh, + ldursh: Ldursh, + stur: Stur, + ldur: Ldur, + ldursw: Ldursw, + prfum: Prfum, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.size) { + .byte => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .sturb = inst.sturb }, + 0b01 => .{ .ldurb = inst.ldurb }, + 0b10, 0b11 => .{ .ldursb = inst.ldursb }, + }, + true => .unallocated, + }, + .halfword => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .sturh = inst.sturh }, + 0b01 => .{ .ldurh = inst.ldurh }, + 0b10, 0b11 => .{ .ldursh = inst.ldursh }, + }, + true => .unallocated, + }, + .word => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .stur = inst.stur }, + 0b01 => .{ .ldur = inst.ldur }, + 0b10 => .{ .ldursw = inst.ldursw }, + 0b11 => .unallocated, + }, + true => .unallocated, + }, + .doubleword => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .stur = inst.stur }, + 0b01 => .{ .ldur = inst.ldur }, + 0b10 => .{ .prfum = inst.prfum }, + 0b11 => .unallocated, + }, + true => .unallocated, + }, + }; + } + }; + + pub const Vector = packed union { + group: @This().Group, + stur: Stur, + ldur: Ldur, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc0: L, + opc1: Opc1, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + /// C7.2.333 STUR (SIMD&FP) + pub const Stur = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc0: L = .store, + opc1: Opc1, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + /// C7.2.194 LDUR (SIMD&FP) + pub const Ldur = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + imm9: i9, + decoded21: u1 = 0b0, + opc0: L = .load, + opc1: Opc1, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + pub const Opc1 = packed struct { + encoded: u1, + + pub fn encode(vs: Register.VectorSize) Opc1 { + return .{ .encoded = switch (vs) { + .byte, .half, .single, .double => 0b0, + .quad => 0b1, + else => unreachable, + } }; + } + + pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize { + return switch (enc_size.encoded) { + 0b00 => switch (enc_opc1.encoded) { + 0b0 => .byte, + 0b1 => .quad, + }, + 0b01 => switch (enc_opc1.encoded) { + 0b0 => .half, + 0b1 => unreachable, + }, + 0b10 => switch (enc_opc1.encoded) { + 0b0 => .single, + 0b1 => unreachable, + }, + 0b11 => switch (enc_opc1.encoded) { + 0b0 => .double, + 0b1 => unreachable, + }, + }; + } + }; + + pub const Size = packed struct { + encoded: u2, + + pub fn encode(vs: Register.VectorSize) Size { + return .{ .encoded = switch (vs) { + .byte, .quad => 0b00, + .half => 0b01, + .single => 0b10, + .double => 0b11, + else => unreachable, + } }; + } + }; + + pub const Decoded = union(enum) { + unallocated, + stur: Stur, + ldur: Ldur, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.size.encoded) { + 0b00 => switch (inst.group.opc0) { + .store => .{ .stur = inst.stur }, + .load => .{ .ldur = inst.ldur }, + }, + 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) { + 0b0 => switch (inst.group.opc0) { + .store => .{ .stur = inst.stur }, + .load => .{ .ldur = inst.ldur }, + }, + 0b1 => .unallocated, + }, + }; + } + }; + + pub const Decoded = union(enum) { + integer: Integer, + vector: Vector, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.V) { + false => .{ .integer = inst.integer }, + true => .{ .vector = inst.vector }, + }; + } + }; + + /// Load/store register (immediate post-indexed) + pub const RegisterImmediatePostIndexed = packed union { + group: @This().Group, + integer: Integer, + vector: Vector, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2, + decoded24: u2 = 0b00, + V: bool, + decoded27: u3 = 0b111, + size: u2, + }; + + pub const Integer = packed union { + group: @This().Group, + strb: Strb, + ldrb: Ldrb, + ldrsb: Ldrsb, + strh: Strh, + ldrh: Ldrh, + ldrsh: Ldrsh, + str: Str, + ldr: Ldr, + ldrsw: Ldrsw, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize, + }; + + /// C6.2.324 STRB (immediate) + pub const Strb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b00, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.170 LDRB (immediate) + pub const Ldrb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b01, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.174 LDRSB (immediate) + pub const Ldrsb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc0: u1, + opc1: u1 = 0b1, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.326 STRH (immediate) + pub const Strh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b00, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.172 LDRH (immediate) + pub const Ldrh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b01, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.176 LDRSH (immediate) + pub const Ldrsh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc0: u1, + opc1: u1 = 0b1, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.322 STR (immediate) + pub const Str = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b00, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + sf: Register.IntegerSize, + size1: u1 = 0b1, + }; + + /// C6.2.166 LDR (immediate) + pub const Ldr = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b01, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + sf: Register.IntegerSize, + size1: u1 = 0b1, + }; + + /// C6.2.178 LDRSW (immediate) + pub const Ldrsw = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b10, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .word, + }; + + pub const Decoded = union(enum) { + unallocated, + strb: Strb, + ldrb: Ldrb, + ldrsb: Ldrsb, + strh: Strh, + ldrh: Ldrh, + ldrsh: Ldrsh, + str: Str, + ldr: Ldr, + ldrsw: Ldrsw, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.size) { + .byte => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .strb = inst.strb }, + 0b01 => .{ .ldrb = inst.ldrb }, + 0b10, 0b11 => .{ .ldrsb = inst.ldrsb }, + }, + true => .unallocated, + }, + .halfword => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .strh = inst.strh }, + 0b01 => .{ .ldrh = inst.ldrh }, + 0b10, 0b11 => .{ .ldrsh = inst.ldrsh }, + }, + true => .unallocated, + }, + .word => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .str = inst.str }, + 0b01 => .{ .ldr = inst.ldr }, + 0b10 => .{ .ldrsw = inst.ldrsw }, + 0b11 => .unallocated, + }, + true => .unallocated, + }, + .doubleword => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .str = inst.str }, + 0b01 => .{ .ldr = inst.ldr }, + 0b10, 0b11 => .unallocated, + }, + true => .unallocated, + }, + }; + } + }; + + pub const Vector = packed union { + group: @This().Group, + str: Str, + ldr: Ldr, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc0: L, + opc1: Opc1, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + /// C7.2.331 STR (immediate, SIMD&FP) + pub const Str = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc0: L = .store, + opc1: Opc1, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + /// C7.2.191 LDR (immediate, SIMD&FP) + pub const Ldr = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b01, + imm9: i9, + decoded21: u1 = 0b0, + opc0: L = .load, + opc1: Opc1, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + pub const Opc1 = packed struct { + encoded: u1, + + pub fn encode(vs: Register.VectorSize) Opc1 { + return .{ .encoded = switch (vs) { + .byte, .half, .single, .double => 0b0, + .quad => 0b1, + else => unreachable, + } }; + } + + pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize { + return switch (enc_size.encoded) { + 0b00 => switch (enc_opc1.encoded) { + 0b0 => .byte, + 0b1 => .quad, + }, + 0b01 => switch (enc_opc1.encoded) { + 0b0 => .half, + 0b1 => unreachable, + }, + 0b10 => switch (enc_opc1.encoded) { + 0b0 => .single, + 0b1 => unreachable, + }, + 0b11 => switch (enc_opc1.encoded) { + 0b0 => .double, + 0b1 => unreachable, + }, + }; + } + }; + + pub const Size = packed struct { + encoded: u2, + + pub fn encode(vs: Register.VectorSize) Size { + return .{ .encoded = switch (vs) { + .byte, .quad => 0b00, + .half => 0b01, + .single => 0b10, + .double => 0b11, + else => unreachable, + } }; + } + }; + + pub const Decoded = union(enum) { + unallocated, + str: Str, + ldr: Ldr, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.size.encoded) { + 0b00 => switch (inst.group.opc0) { + .store => .{ .str = inst.str }, + .load => .{ .ldr = inst.ldr }, + }, + 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) { + 0b0 => switch (inst.group.opc0) { + .store => .{ .str = inst.str }, + .load => .{ .ldr = inst.ldr }, + }, + 0b1 => .unallocated, + }, + }; + } + }; + + pub const Decoded = union(enum) { + integer: Integer, + vector: Vector, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.V) { + false => .{ .integer = inst.integer }, + true => .{ .vector = inst.vector }, + }; + } + }; + + /// Load/store register (unprivileged) + pub const RegisterUnprivileged = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2, + decoded24: u2 = 0b00, + V: bool, + decoded27: u3 = 0b111, + size: IntegerSize, + }; + + /// Load/store register (immediate pre-indexed) + pub const RegisterImmediatePreIndexed = packed union { + group: @This().Group, + integer: Integer, + vector: Vector, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2, + decoded24: u2 = 0b00, + V: bool, + decoded27: u3 = 0b111, + size: u2, + }; + + pub const Integer = packed union { + group: @This().Group, + strb: Strb, + ldrb: Ldrb, + ldrsb: Ldrsb, + strh: Strh, + ldrh: Ldrh, + ldrsh: Ldrsh, + str: Str, + ldr: Ldr, + ldrsw: Ldrsw, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize, + }; + + /// C6.2.324 STRB (immediate) + pub const Strb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b00, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.170 LDRB (immediate) + pub const Ldrb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b01, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.174 LDRSB (immediate) + pub const Ldrsb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc0: u1, + opc1: u1 = 0b1, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.326 STRH (immediate) + pub const Strh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b00, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.172 LDRH (immediate) + pub const Ldrh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b01, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.176 LDRSH (immediate) + pub const Ldrsh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc0: u1, + opc1: u1 = 0b1, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.322 STR (immediate) + pub const Str = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b00, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + sf: Register.IntegerSize, + size1: u1 = 0b1, + }; + + /// C6.2.166 LDR (immediate) + pub const Ldr = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b01, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + sf: Register.IntegerSize, + size1: u1 = 0b1, + }; + + /// C6.2.178 LDRSW (immediate) + pub const Ldrsw = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc: u2 = 0b10, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .word, + }; + + pub const Decoded = union(enum) { + unallocated, + strb: Strb, + ldrb: Ldrb, + ldrsb: Ldrsb, + strh: Strh, + ldrh: Ldrh, + ldrsh: Ldrsh, + str: Str, + ldr: Ldr, + ldrsw: Ldrsw, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.size) { + .byte => switch (inst.group.opc) { + 0b00 => .{ .strb = inst.strb }, + 0b01 => .{ .ldrb = inst.ldrb }, + 0b10, 0b11 => .{ .ldrsb = inst.ldrsb }, + }, + .halfword => switch (inst.group.opc) { + 0b00 => .{ .strh = inst.strh }, + 0b01 => .{ .ldrh = inst.ldrh }, + 0b10, 0b11 => .{ .ldrsh = inst.ldrsh }, + }, + .word => switch (inst.group.opc) { + 0b00 => .{ .str = inst.str }, + 0b01 => .{ .ldr = inst.ldr }, + 0b10 => .{ .ldrsw = inst.ldrsw }, + 0b11 => .unallocated, + }, + .doubleword => switch (inst.group.opc) { + 0b00 => .{ .str = inst.str }, + 0b01 => .{ .ldr = inst.ldr }, + 0b10, 0b11 => .unallocated, + }, + }; + } + }; + + pub const Vector = packed union { + group: @This().Group, + str: Str, + ldr: Ldr, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc0: L, + opc1: Opc1, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + /// C7.2.331 STR (immediate, SIMD&FP) + pub const Str = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc0: L = .store, + opc1: Opc1, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + /// C7.2.191 LDR (immediate, SIMD&FP) + pub const Ldr = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b11, + imm9: i9, + decoded21: u1 = 0b0, + opc0: L = .load, + opc1: Opc1, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + pub const Opc1 = packed struct { + encoded: u1, + + pub fn encode(vs: Register.VectorSize) Opc1 { + return .{ .encoded = switch (vs) { + .byte, .half, .single, .double => 0b0, + .quad => 0b1, + else => unreachable, + } }; + } + + pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize { + return switch (enc_size.encoded) { + 0b00 => switch (enc_opc1.encoded) { + 0b0 => .byte, + 0b1 => .quad, + }, + 0b01 => switch (enc_opc1.encoded) { + 0b0 => .half, + 0b1 => unreachable, + }, + 0b10 => switch (enc_opc1.encoded) { + 0b0 => .single, + 0b1 => unreachable, + }, + 0b11 => switch (enc_opc1.encoded) { + 0b0 => .double, + 0b1 => unreachable, + }, + }; + } + }; + + pub const Size = packed struct { + encoded: u2, + + pub fn encode(vs: Register.VectorSize) Size { + return .{ .encoded = switch (vs) { + .byte, .quad => 0b00, + .half => 0b01, + .single => 0b10, + .double => 0b11, + else => unreachable, + } }; + } + }; + + pub const Decoded = union(enum) { + unallocated, + str: Str, + ldr: Ldr, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.size.encoded) { + 0b00 => switch (inst.group.opc0) { + .store => .{ .str = inst.str }, + .load => .{ .ldr = inst.ldr }, + }, + 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) { + 0b0 => switch (inst.group.opc0) { + .store => .{ .str = inst.str }, + .load => .{ .ldr = inst.ldr }, + }, + 0b1 => .unallocated, + }, + }; + } + }; + + pub const Decoded = union(enum) { + integer: Integer, + vector: Vector, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.V) { + false => .{ .integer = inst.integer }, + true => .{ .vector = inst.vector }, + }; + } + }; + + /// Load/store register (register offset) + pub const RegisterRegisterOffset = packed union { + group: @This().Group, + integer: Integer, + vector: Vector, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc: u2, + decoded24: u2 = 0b00, + V: bool, + decoded27: u3 = 0b111, + size: u2, + }; + + pub const Integer = packed union { + group: @This().Group, + strb: Strb, + ldrb: Ldrb, + ldrsb: Ldrsb, + strh: Strh, + ldrh: Ldrh, + ldrsh: Ldrsh, + str: Str, + ldr: Ldr, + ldrsw: Ldrsw, + prfm: Prfm, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc: u2, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize, + }; + + /// C6.2.325 STRB (register) + pub const Strb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc: u2 = 0b00, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.171 LDRB (register) + pub const Ldrb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc: u2 = 0b01, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.175 LDRSB (register) + pub const Ldrsb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc0: u1, + opc1: u1 = 0b1, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.327 STRH (register) + pub const Strh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc: u2 = 0b00, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.173 LDRH (register) + pub const Ldrh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc: u2 = 0b01, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.177 LDRSH (register) + pub const Ldrsh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc0: u1, + opc1: u1 = 0b1, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.323 STR (register) + pub const Str = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc: u2 = 0b00, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + sf: Register.IntegerSize, + size1: u1 = 0b1, + }; + + /// C6.2.168 LDR (register) + pub const Ldr = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc: u2 = 0b01, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + sf: Register.IntegerSize, + size1: u1 = 0b1, + }; + + /// C6.2.180 LDRSW (register) + pub const Ldrsw = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc: u2 = 0b10, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .word, + }; + + /// C6.2.249 PRFM (register) + pub const Prfm = packed struct { + prfop: PrfOp, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc: u2 = 0b10, + decoded24: u2 = 0b00, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .doubleword, + }; + + pub const Decoded = union(enum) { + unallocated, + strb: Strb, + ldrb: Ldrb, + ldrsb: Ldrsb, + strh: Strh, + ldrh: Ldrh, + ldrsh: Ldrsh, + str: Str, + ldr: Ldr, + ldrsw: Ldrsw, + prfm: Prfm, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.size) { + .byte => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .strb = inst.strb }, + 0b01 => .{ .ldrb = inst.ldrb }, + 0b10, 0b11 => .{ .ldrsb = inst.ldrsb }, + }, + true => .unallocated, + }, + .halfword => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .strh = inst.strh }, + 0b01 => .{ .ldrh = inst.ldrh }, + 0b10, 0b11 => .{ .ldrsh = inst.ldrsh }, + }, + true => .unallocated, + }, + .word => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .str = inst.str }, + 0b01 => .{ .ldr = inst.ldr }, + 0b10 => .{ .ldrsw = inst.ldrsw }, + 0b11 => .unallocated, + }, + true => .unallocated, + }, + .doubleword => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .str = inst.str }, + 0b01 => .{ .ldr = inst.ldr }, + 0b10 => .{ .prfm = inst.prfm }, + 0b11 => .unallocated, + }, + true => .unallocated, + }, + }; + } + }; + + pub const Vector = packed union { + group: @This().Group, + str: Str, + ldr: Ldr, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc: u2, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + /// C7.2.332 STR (register, SIMD&FP) + pub const Str = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc0: L = .store, + opc1: Opc1, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + /// C7.2.193 LDR (register, SIMD&FP) + pub const Ldr = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + S: bool, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opc0: L = .load, + opc1: Opc1, + decoded24: u2 = 0b00, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + pub const Opc1 = packed struct { + encoded: u1, + + pub fn encode(vs: Register.VectorSize) Opc1 { + return .{ .encoded = switch (vs) { + .byte, .half, .single, .double => 0b0, + .quad => 0b1, + else => unreachable, + } }; + } + + pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize { + return switch (enc_size.encoded) { + 0b00 => switch (enc_opc1.encoded) { + 0b0 => .byte, + 0b1 => .quad, + }, + 0b01 => switch (enc_opc1.encoded) { + 0b0 => .half, + 0b1 => unreachable, + }, + 0b10 => switch (enc_opc1.encoded) { + 0b0 => .single, + 0b1 => unreachable, + }, + 0b11 => switch (enc_opc1.encoded) { + 0b0 => .double, + 0b1 => unreachable, + }, + }; + } + }; + + pub const Size = packed struct { + encoded: u2, + + pub fn encode(vs: Register.VectorSize) Size { + return .{ .encoded = switch (vs) { + .byte, .quad => 0b00, + .half => 0b01, + .single => 0b10, + .double => 0b11, + else => unreachable, + } }; + } + }; + }; + + pub const Option = enum(u3) { + uxtw = 0b010, + lsl = 0b011, + sxtw = 0b110, + sxtx = 0b111, + _, + + pub fn sf(option: Option) Register.IntegerSize { + return switch (option) { + .uxtw, .sxtw => .word, + .lsl, .sxtx => .doubleword, + _ => unreachable, + }; + } + }; + + pub const Extend = union(Option) { + uxtw: Amount, + lsl: Amount, + sxtw: Amount, + sxtx: Amount, + + pub const Amount = u3; + }; + + pub const Decoded = union(enum) { + integer: Integer, + vector: Vector, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.V) { + false => .{ .integer = inst.integer }, + true => .{ .vector = inst.vector }, + }; + } + }; + + /// Load/store register (unsigned immediate) + pub const RegisterUnsignedImmediate = packed union { + group: @This().Group, + integer: Integer, + vector: Vector, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc: u2, + decoded24: u2 = 0b01, + V: bool, + decoded27: u3 = 0b111, + size: u2, + }; + + pub const Integer = packed union { + group: @This().Group, + strb: Strb, + ldrb: Ldrb, + ldrsb: Ldrsb, + strh: Strh, + ldrh: Ldrh, + ldrsh: Ldrsh, + str: Str, + ldr: Ldr, + ldrsw: Ldrsw, + prfm: Prfm, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc: u2, + decoded24: u2 = 0b01, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize, + }; + + /// C6.2.324 STRB (immediate) + pub const Strb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc: u2 = 0b00, + decoded24: u2 = 0b01, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.170 LDRB (immediate) + pub const Ldrb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc: u2 = 0b01, + decoded24: u2 = 0b01, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.174 LDRSB (immediate) + pub const Ldrsb = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc0: u1, + opc1: u1 = 0b1, + decoded24: u2 = 0b01, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .byte, + }; + + /// C6.2.326 STRH (immediate) + pub const Strh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc: u2 = 0b00, + decoded24: u2 = 0b01, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.172 LDRH (immediate) + pub const Ldrh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc: u2 = 0b01, + decoded24: u2 = 0b01, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.176 LDRSH (immediate) + pub const Ldrsh = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc0: u1, + opc1: u1 = 0b1, + decoded24: u2 = 0b01, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .halfword, + }; + + /// C6.2.322 STR (immediate) + pub const Str = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc: u2 = 0b00, + decoded24: u2 = 0b01, + V: bool = false, + decoded27: u3 = 0b111, + sf: Register.IntegerSize, + size1: u1 = 0b1, + }; + + /// C6.2.166 LDR (immediate) + pub const Ldr = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc: u2 = 0b01, + decoded24: u2 = 0b01, + V: bool = false, + decoded27: u3 = 0b111, + sf: Register.IntegerSize, + size1: u1 = 0b1, + }; + + /// C6.2.178 LDRSW (immediate) + pub const Ldrsw = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc: u2 = 0b10, + decoded24: u2 = 0b01, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .word, + }; + + /// C6.2.247 PRFM (immediate) + pub const Prfm = packed struct { + prfop: PrfOp, + Rn: Register.Encoded, + imm12: u12, + opc: u2 = 0b10, + decoded24: u2 = 0b01, + V: bool = false, + decoded27: u3 = 0b111, + size: IntegerSize = .doubleword, + }; + + pub const Decoded = union(enum) { + unallocated, + strb: Strb, + ldrb: Ldrb, + ldrsb: Ldrsb, + strh: Strh, + ldrh: Ldrh, + ldrsh: Ldrsh, + str: Str, + ldr: Ldr, + ldrsw: Ldrsw, + prfm: Prfm, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.size) { + .byte => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .strb = inst.strb }, + 0b01 => .{ .ldrb = inst.ldrb }, + 0b10, 0b11 => .{ .ldrsb = inst.ldrsb }, + }, + true => .unallocated, + }, + .halfword => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .strh = inst.strh }, + 0b01 => .{ .ldrh = inst.ldrh }, + 0b10, 0b11 => .{ .ldrsh = inst.ldrsh }, + }, + true => .unallocated, + }, + .word => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .str = inst.str }, + 0b01 => .{ .ldr = inst.ldr }, + 0b10 => .{ .ldrsw = inst.ldrsw }, + 0b11 => .unallocated, + }, + true => .unallocated, + }, + .doubleword => switch (inst.group.V) { + false => switch (inst.group.opc) { + 0b00 => .{ .str = inst.str }, + 0b01 => .{ .ldr = inst.ldr }, + 0b10 => .{ .prfm = inst.prfm }, + 0b11 => .unallocated, + }, + true => .unallocated, + }, + }; + } + }; + + pub const Vector = packed union { + group: @This().Group, + str: Str, + ldr: Ldr, + + pub const Group = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc0: L, + opc1: Opc1, + decoded24: u2 = 0b01, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + /// C7.2.331 STR (immediate, SIMD&FP) + pub const Str = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc0: L = .store, + opc1: Opc1, + decoded24: u2 = 0b01, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + /// C7.2.191 LDR (immediate, SIMD&FP) + pub const Ldr = packed struct { + Rt: Register.Encoded, + Rn: Register.Encoded, + imm12: u12, + opc0: L = .load, + opc1: Opc1, + decoded24: u2 = 0b01, + V: bool = true, + decoded27: u3 = 0b111, + size: Size, + }; + + pub const Opc1 = packed struct { + encoded: u1, + + pub fn encode(vs: Register.VectorSize) Opc1 { + return .{ .encoded = switch (vs) { + .byte, .half, .single, .double => 0b0, + .quad => 0b1, + else => unreachable, + } }; + } + + pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize { + return switch (enc_size.encoded) { + 0b00 => switch (enc_opc1.encoded) { + 0b0 => .byte, + 0b1 => .quad, + }, + 0b01 => switch (enc_opc1.encoded) { + 0b0 => .half, + 0b1 => unreachable, + }, + 0b10 => switch (enc_opc1.encoded) { + 0b0 => .single, + 0b1 => unreachable, + }, + 0b11 => switch (enc_opc1.encoded) { + 0b0 => .double, + 0b1 => unreachable, + }, + }; + } + }; + + pub const Size = packed struct { + encoded: u2, + + pub fn encode(vs: Register.VectorSize) Size { + return .{ .encoded = switch (vs) { + .byte, .quad => 0b00, + .half => 0b01, + .single => 0b10, + .double => 0b11, + else => unreachable, + } }; + } + }; + + pub const Decoded = union(enum) { + unallocated, + str: Str, + ldr: Ldr, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.size.encoded) { + 0b00 => switch (inst.group.opc0) { + .store => .{ .str = inst.str }, + .load => .{ .ldr = inst.ldr }, + }, + 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) { + 0b0 => switch (inst.group.opc0) { + .store => .{ .str = inst.str }, + .load => .{ .ldr = inst.ldr }, + }, + 0b1 => .unallocated, + }, + }; + } + }; + + pub const Decoded = union(enum) { + integer: Integer, + vector: Vector, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.V) { + false => .{ .integer = inst.integer }, + true => .{ .vector = inst.vector }, + }; + } + }; + + pub const L = enum(u1) { + store = 0b0, + load = 0b1, + }; + + pub const IntegerSize = enum(u2) { + byte = 0b00, + halfword = 0b01, + word = 0b10, + doubleword = 0b11, + }; + + pub const VectorSize = enum(u2) { + single = 0b00, + double = 0b01, + quad = 0b10, + _, + + pub fn decode(vs: VectorSize) Register.VectorSize { + return switch (vs) { + .single => .single, + .double => .double, + .quad => .quad, + _ => unreachable, + }; + } + + pub fn encode(vs: Register.VectorSize) VectorSize { + return switch (vs) { + else => unreachable, + .single => .single, + .double => .double, + .quad => .quad, + }; + } + }; + + pub const PrfOp = packed struct { + policy: Policy, + target: Target, + type: Type, + + pub const Policy = enum(u1) { + keep = 0b0, + strm = 0b1, + }; + + pub const Target = enum(u2) { + l1 = 0b00, + l2 = 0b01, + l3 = 0b10, + _, + }; + + pub const Type = enum(u2) { + pld = 0b00, + pli = 0b01, + pst = 0b10, + _, + }; + + pub const pldl1keep: PrfOp = .{ .type = .pld, .target = .l1, .policy = .keep }; + pub const pldl1strm: PrfOp = .{ .type = .pld, .target = .l1, .policy = .strm }; + pub const pldl2keep: PrfOp = .{ .type = .pld, .target = .l2, .policy = .keep }; + pub const pldl2strm: PrfOp = .{ .type = .pld, .target = .l2, .policy = .strm }; + pub const pldl3keep: PrfOp = .{ .type = .pld, .target = .l3, .policy = .keep }; + pub const pldl3strm: PrfOp = .{ .type = .pld, .target = .l3, .policy = .strm }; + pub const plil1keep: PrfOp = .{ .type = .pli, .target = .l1, .policy = .keep }; + pub const plil1strm: PrfOp = .{ .type = .pli, .target = .l1, .policy = .strm }; + pub const plil2keep: PrfOp = .{ .type = .pli, .target = .l2, .policy = .keep }; + pub const plil2strm: PrfOp = .{ .type = .pli, .target = .l2, .policy = .strm }; + pub const plil3keep: PrfOp = .{ .type = .pli, .target = .l3, .policy = .keep }; + pub const plil3strm: PrfOp = .{ .type = .pli, .target = .l3, .policy = .strm }; + pub const pstl1keep: PrfOp = .{ .type = .pst, .target = .l1, .policy = .keep }; + pub const pstl1strm: PrfOp = .{ .type = .pst, .target = .l1, .policy = .strm }; + pub const pstl2keep: PrfOp = .{ .type = .pst, .target = .l2, .policy = .keep }; + pub const pstl2strm: PrfOp = .{ .type = .pst, .target = .l2, .policy = .strm }; + pub const pstl3keep: PrfOp = .{ .type = .pst, .target = .l3, .policy = .keep }; + pub const pstl3strm: PrfOp = .{ .type = .pst, .target = .l3, .policy = .strm_ }; + }; + + pub const Decoded = union(enum) { + unallocated, + register_literal: RegisterLiteral, + memory: Memory, + no_allocate_pair_offset: NoAllocatePairOffset, + register_pair_post_indexed: RegisterPairPostIndexed, + register_pair_offset: RegisterPairOffset, + register_pair_pre_indexed: RegisterPairPreIndexed, + register_unscaled_immediate: RegisterUnscaledImmediate, + register_immediate_post_indexed: RegisterImmediatePostIndexed, + register_unprivileged: RegisterUnprivileged, + register_immediate_pre_indexed: RegisterImmediatePreIndexed, + register_register_offset: RegisterRegisterOffset, + register_unsigned_immediate: RegisterUnsignedImmediate, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.op0) { + else => .unallocated, + 0b0010, 0b0110, 0b1010, 0b1110 => switch (inst.group.op2) { + 0b00 => .{ .no_allocate_pair_offset = inst.no_allocate_pair_offset }, + 0b01 => .{ .register_pair_post_indexed = inst.register_pair_post_indexed }, + 0b10 => .{ .register_pair_offset = inst.register_pair_offset }, + 0b11 => .{ .register_pair_pre_indexed = inst.register_pair_pre_indexed }, + }, + 0b0011, 0b0111, 0b1011, 0b1111 => switch (inst.group.op2) { + 0b00...0b01 => switch (inst.group.op3) { + 0b000000...0b011111 => switch (inst.group.op4) { + 0b00 => .{ .register_unscaled_immediate = inst.register_unscaled_immediate }, + 0b01 => .{ .register_immediate_post_indexed = inst.register_immediate_post_indexed }, + 0b10 => .{ .register_unprivileged = inst.register_unprivileged }, + 0b11 => .{ .register_immediate_pre_indexed = inst.register_immediate_pre_indexed }, + }, + 0b100000...0b111111 => switch (inst.group.op4) { + 0b00 => .unallocated, + 0b10 => .{ .register_register_offset = inst.register_register_offset }, + 0b01, 0b11 => .unallocated, + }, + }, + 0b10...0b11 => .{ .register_unsigned_immediate = inst.register_unsigned_immediate }, + }, + }; + } + }; + + /// C4.1.89 Data Processing -- Register + pub const DataProcessingRegister = packed union { + group: @This().Group, + data_processing_two_source: DataProcessingTwoSource, + data_processing_one_source: DataProcessingOneSource, + logical_shifted_register: LogicalShiftedRegister, + add_subtract_shifted_register: AddSubtractShiftedRegister, + add_subtract_extended_register: AddSubtractExtendedRegister, + add_subtract_with_carry: AddSubtractWithCarry, + rotate_right_into_flags: RotateRightIntoFlags, + evaluate_into_flags: EvaluateIntoFlags, + conditional_compare_register: ConditionalCompareRegister, + conditional_compare_immediate: ConditionalCompareImmediate, + conditional_select: ConditionalSelect, + data_processing_three_source: DataProcessingThreeSource, + + /// Table C4-90 Encoding table for the Data Processing -- Register group + pub const Group = packed struct { + encoded0: u10, + op3: u6, + encoded16: u5, + op2: u4, + decoded25: u3 = 0b101, + op1: u1, + encoded29: u1, + op0: u1, + encoded31: u1, + }; + + /// Data-processing (2 source) + pub const DataProcessingTwoSource = packed union { + group: @This().Group, + udiv: Udiv, + sdiv: Sdiv, + lslv: Lslv, + lsrv: Lsrv, + asrv: Asrv, + rorv: Rorv, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + opcode: u6, + Rm: Register.Encoded, + decoded21: u8 = 0b11010110, + S: bool, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.388 UDIV + pub const Udiv = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + o1: DivOp = .udiv, + decoded11: u5 = 0b00001, + Rm: Register.Encoded, + decoded21: u8 = 0b11010110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.270 SDIV + pub const Sdiv = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + o1: DivOp = .sdiv, + decoded11: u5 = 0b00001, + Rm: Register.Encoded, + decoded21: u8 = 0b11010110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.214 LSLV + pub const Lslv = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + op2: ShiftOp = .lslv, + decoded12: u4 = 0b0010, + Rm: Register.Encoded, + decoded21: u8 = 0b11010110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.217 LSRV + pub const Lsrv = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + op2: ShiftOp = .lsrv, + decoded12: u4 = 0b0010, + Rm: Register.Encoded, + decoded21: u8 = 0b11010110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.18 ASRV + pub const Asrv = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + op2: ShiftOp = .asrv, + decoded12: u4 = 0b0010, + Rm: Register.Encoded, + decoded21: u8 = 0b11010110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.263 RORV + pub const Rorv = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + op2: ShiftOp = .rorv, + decoded12: u4 = 0b0010, + Rm: Register.Encoded, + decoded21: u8 = 0b11010110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + pub const DivOp = enum(u1) { + udiv = 0b0, + sdiv = 0b1, + }; + + pub const ShiftOp = enum(u2) { + lslv = 0b00, + lsrv = 0b01, + asrv = 0b10, + rorv = 0b11, + }; + + pub const Decoded = union(enum) { + unallocated, + udiv: Udiv, + sdiv: Sdiv, + lslv: Lslv, + lsrv: Lsrv, + asrv: Asrv, + rorv: Rorv, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.S) { + false => switch (inst.group.opcode) { + else => .unallocated, + 0b000010 => .{ .udiv = inst.udiv }, + 0b000011 => .{ .sdiv = inst.sdiv }, + 0b001000 => .{ .lslv = inst.lslv }, + 0b001001 => .{ .lsrv = inst.lsrv }, + 0b001010 => .{ .asrv = inst.asrv }, + 0b001011 => .{ .rorv = inst.rorv }, + }, + true => .unallocated, + }; + } + }; + + /// Data-processing (1 source) + pub const DataProcessingOneSource = packed union { + group: @This().Group, + rbit: Rbit, + rev16: Rev16, + rev32: Rev32, + rev: Rev, + clz: Clz, + cls: Cls, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + opcode: u6, + opcode2: u5, + decoded21: u8 = 0b11010110, + S: bool, + decoded30: u1 = 0b1, + sf: Register.IntegerSize, + }; + + /// C6.2.253 RBIT + pub const Rbit = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b00, + decoded12: u4 = 0b0000, + decoded16: u5 = 0b00000, + decoded21: u8 = 0b11010110, + S: bool = false, + decoded30: u1 = 0b1, + sf: Register.IntegerSize, + }; + + /// C6.2.257 REV16 + pub const Rev16 = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + opc: u2 = 0b01, + decoded12: u4 = 0b0000, + decoded16: u5 = 0b00000, + decoded21: u8 = 0b11010110, + S: bool = false, + decoded30: u1 = 0b1, + sf: Register.IntegerSize, + }; + + /// C6.2.258 REV32 + pub const Rev32 = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + opc: u2 = 0b10, + decoded12: u4 = 0b0000, + decoded16: u5 = 0b00000, + decoded21: u8 = 0b11010110, + S: bool = false, + decoded30: u1 = 0b1, + sf: Register.IntegerSize = .doubleword, + }; + + /// C6.2.256 REV + pub const Rev = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + opc0: Register.IntegerSize, + opc1: u1 = 0b1, + decoded12: u4 = 0b0000, + decoded16: u5 = 0b00000, + decoded21: u8 = 0b11010110, + S: bool = false, + decoded30: u1 = 0b1, + sf: Register.IntegerSize, + }; + + /// C6.2.58 CLZ + pub const Clz = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + op: u1 = 0b0, + decoded11: u5 = 0b00010, + decoded16: u5 = 0b00000, + decoded21: u8 = 0b11010110, + S: bool = false, + decoded30: u1 = 0b1, + sf: Register.IntegerSize, + }; + + /// C6.2.57 CLS + pub const Cls = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + op: u1 = 0b1, + decoded11: u5 = 0b00010, + decoded16: u5 = 0b00000, + decoded21: u8 = 0b11010110, + S: bool = false, + decoded30: u1 = 0b1, + sf: Register.IntegerSize, + }; + + pub const Decoded = union(enum) { + unallocated, + rbit: Rbit, + rev16: Rev16, + rev32: Rev32, + rev: Rev, + clz: Clz, + cls: Cls, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.S) { + true => .unallocated, + false => switch (inst.group.opcode2) { + else => .unallocated, + 0b00000 => switch (inst.group.opcode) { + else => .unallocated, + 0b000000 => .{ .rbit = inst.rbit }, + 0b000001 => .{ .rev16 = inst.rev16 }, + 0b000010 => switch (inst.group.sf) { + .word => .{ .rev = inst.rev }, + .doubleword => .{ .rev32 = inst.rev32 }, + }, + 0b000011 => switch (inst.group.sf) { + .word => .unallocated, + .doubleword => .{ .rev = inst.rev }, + }, + 0b000100 => .{ .clz = inst.clz }, + 0b000101 => .{ .cls = inst.cls }, + }, + }, + }; + } + }; + + /// Logical (shifted register) + pub const LogicalShiftedRegister = packed union { + group: @This().Group, + @"and": And, + bic: Bic, + orr: Orr, + orn: Orn, + eor: Eor, + eon: Eon, + ands: Ands, + bics: Bics, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + N: bool, + shift: Shift.Op, + decoded24: u5 = 0b01010, + opc: LogicalOpc, + sf: Register.IntegerSize, + }; + + /// C6.2.13 AND (shifted register) + pub const And = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + N: bool = false, + shift: Shift.Op, + decoded24: u5 = 0b01010, + opc: LogicalOpc = .@"and", + sf: Register.IntegerSize, + }; + + /// C6.2.32 BIC (shifted register) + pub const Bic = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + N: bool = true, + shift: Shift.Op, + decoded24: u5 = 0b01010, + opc: LogicalOpc = .@"and", + sf: Register.IntegerSize, + }; + + /// C6.2.241 ORR (shifted register) + pub const Orr = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + N: bool = false, + shift: Shift.Op, + decoded24: u5 = 0b01010, + opc: LogicalOpc = .orr, + sf: Register.IntegerSize, + }; + + /// C6.2.239 ORN (shifted register) + pub const Orn = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + N: bool = true, + shift: Shift.Op, + decoded24: u5 = 0b01010, + opc: LogicalOpc = .orr, + sf: Register.IntegerSize, + }; + + /// C6.2.120 EOR (shifted register) + pub const Eor = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + N: bool = false, + shift: Shift.Op, + decoded24: u5 = 0b01010, + opc: LogicalOpc = .eor, + sf: Register.IntegerSize, + }; + + /// C6.2.118 EON (shifted register) + pub const Eon = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + N: bool = true, + shift: Shift.Op, + decoded24: u5 = 0b01010, + opc: LogicalOpc = .eor, + sf: Register.IntegerSize, + }; + + /// C6.2.15 ANDS (shifted register) + pub const Ands = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + N: bool = false, + shift: Shift.Op, + decoded24: u5 = 0b01010, + opc: LogicalOpc = .ands, + sf: Register.IntegerSize, + }; + + /// C6.2.33 BICS (shifted register) + pub const Bics = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + N: bool = true, + shift: Shift.Op, + decoded24: u5 = 0b01010, + opc: LogicalOpc = .ands, + sf: Register.IntegerSize, + }; + + pub const Decoded = union(enum) { + unallocated, + @"and": And, + bic: Bic, + orr: Orr, + orn: Orn, + eor: Eor, + eon: Eon, + ands: Ands, + bics: Bics, + }; + pub fn decode(inst: @This()) @This().Decoded { + return if (inst.group.sf == .word and @as(u1, @truncate(inst.group.imm6 >> 5)) == 0b1) + .unallocated + else switch (inst.group.opc) { + .@"and" => switch (inst.group.N) { + false => .{ .@"and" = inst.@"and" }, + true => .{ .bic = inst.bic }, + }, + .orr => switch (inst.group.N) { + false => .{ .orr = inst.orr }, + true => .{ .orn = inst.orn }, + }, + .eor => switch (inst.group.N) { + false => .{ .eor = inst.eor }, + true => .{ .eon = inst.eon }, + }, + .ands => switch (inst.group.N) { + false => .{ .ands = inst.ands }, + true => .{ .bics = inst.bics }, + }, + }; + } + }; + + /// Add/subtract (shifted register) + pub const AddSubtractShiftedRegister = packed union { + group: @This().Group, + add: Add, + adds: Adds, + sub: Sub, + subs: Subs, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + decoded21: u1 = 0b0, + shift: Shift.Op, + decoded24: u5 = 0b01011, + S: bool, + op: AddSubtractOp, + sf: Register.IntegerSize, + }; + + /// C6.2.5 ADD (shifted register) + pub const Add = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + decoded21: u1 = 0b0, + shift: Shift.Op, + decoded24: u5 = 0b01011, + S: bool = false, + op: AddSubtractOp = .add, + sf: Register.IntegerSize, + }; + + /// C6.2.9 ADDS (shifted register) + pub const Adds = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + decoded21: u1 = 0b0, + shift: Shift.Op, + decoded24: u5 = 0b01011, + S: bool = true, + op: AddSubtractOp = .add, + sf: Register.IntegerSize, + }; + + /// C6.2.5 SUB (shifted register) + pub const Sub = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + decoded21: u1 = 0b0, + shift: Shift.Op, + decoded24: u5 = 0b01011, + S: bool = false, + op: AddSubtractOp = .sub, + sf: Register.IntegerSize, + }; + + /// C6.2.9 SUBS (shifted register) + pub const Subs = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm6: Shift.Amount, + Rm: Register.Encoded, + decoded21: u1 = 0b0, + shift: Shift.Op, + decoded24: u5 = 0b01011, + S: bool = true, + op: AddSubtractOp = .sub, + sf: Register.IntegerSize, + }; + + pub const Decoded = union(enum) { + unallocated, + add: Add, + adds: Adds, + sub: Sub, + subs: Subs, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.shift) { + .ror => .unallocated, + .lsl, .lsr, .asr => if (inst.group.sf == .word and @as(u1, @truncate(inst.group.imm6 >> 5)) == 0b1) + .unallocated + else switch (inst.group.op) { + .add => switch (inst.group.S) { + false => .{ .add = inst.add }, + true => .{ .adds = inst.adds }, + }, + .sub => switch (inst.group.S) { + false => .{ .sub = inst.sub }, + true => .{ .subs = inst.subs }, + }, + }, + }; + } + }; + + /// Add/subtract (extended register) + pub const AddSubtractExtendedRegister = packed union { + group: @This().Group, + add: Add, + adds: Adds, + sub: Sub, + subs: Subs, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm3: Extend.Amount, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opt: u2, + decoded24: u5 = 0b01011, + S: bool, + op: AddSubtractOp, + sf: Register.IntegerSize, + }; + + /// C6.2.3 ADD (extended register) + pub const Add = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm3: Extend.Amount, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opt: u2 = 0b00, + decoded24: u5 = 0b01011, + S: bool = false, + op: AddSubtractOp = .add, + sf: Register.IntegerSize, + }; + + /// C6.2.7 ADDS (extended register) + pub const Adds = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm3: Extend.Amount, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opt: u2 = 0b00, + decoded24: u5 = 0b01011, + S: bool = true, + op: AddSubtractOp = .add, + sf: Register.IntegerSize, + }; + + /// C6.2.356 SUB (extended register) + pub const Sub = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm3: Extend.Amount, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opt: u2 = 0b00, + decoded24: u5 = 0b01011, + S: bool = false, + op: AddSubtractOp = .sub, + sf: Register.IntegerSize, + }; + + /// C6.2.362 SUBS (extended register) + pub const Subs = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + imm3: Extend.Amount, + option: Option, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + opt: u2 = 0b00, + decoded24: u5 = 0b01011, + S: bool = true, + op: AddSubtractOp = .sub, + sf: Register.IntegerSize, + }; + + pub const Option = enum(u3) { + uxtb = 0b000, + uxth = 0b001, + uxtw = 0b010, + uxtx = 0b011, + sxtb = 0b100, + sxth = 0b101, + sxtw = 0b110, + sxtx = 0b111, + + pub fn sf(option: Option) Register.IntegerSize { + return switch (option) { + .uxtb, .uxth, .uxtw, .sxtb, .sxth, .sxtw => .word, + .uxtx, .sxtx => .doubleword, + }; + } + }; + + pub const Extend = union(Option) { + uxtb: Amount, + uxth: Amount, + uxtw: Amount, + uxtx: Amount, + sxtb: Amount, + sxth: Amount, + sxtw: Amount, + sxtx: Amount, + + pub const Amount = u3; + }; + + pub const Decoded = union(enum) { + unallocated, + add: Add, + adds: Adds, + sub: Sub, + subs: Subs, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.imm3) { + 0b101 => .unallocated, + 0b110...0b111 => .unallocated, + 0b000...0b100 => switch (inst.group.opt) { + 0b01 => .unallocated, + 0b10...0b11 => .unallocated, + 0b00 => switch (inst.group.op) { + .add => switch (inst.group.S) { + false => .{ .add = inst.add }, + true => .{ .adds = inst.adds }, + }, + .sub => switch (inst.group.S) { + false => .{ .sub = inst.sub }, + true => .{ .subs = inst.subs }, + }, + }, + }, + }; + } + }; + + /// Add/subtract (with carry) + pub const AddSubtractWithCarry = packed union { + group: @This().Group, + adc: Adc, + adcs: Adcs, + sbc: Sbc, + sbcs: Sbcs, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + Rm: Register.Encoded, + decoded21: u8 = 0b11010000, + S: bool, + op: Op, + sf: Register.IntegerSize, + }; + + /// C6.2.1 ADC + pub const Adc = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + Rm: Register.Encoded, + decoded21: u8 = 0b11010000, + S: bool = false, + op: Op = .adc, + sf: Register.IntegerSize, + }; + + /// C6.2.2 ADCS + pub const Adcs = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + Rm: Register.Encoded, + decoded21: u8 = 0b11010000, + S: bool = true, + op: Op = .adc, + sf: Register.IntegerSize, + }; + + /// C6.2.265 SBC + pub const Sbc = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + Rm: Register.Encoded, + decoded21: u8 = 0b11010000, + S: bool = false, + op: Op = .sbc, + sf: Register.IntegerSize, + }; + + /// C6.2.266 SBCS + pub const Sbcs = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + Rm: Register.Encoded, + decoded21: u8 = 0b11010000, + S: bool = true, + op: Op = .sbc, + sf: Register.IntegerSize, + }; + + pub const Op = enum(u1) { + adc = 0b0, + sbc = 0b1, + }; + + pub const Decoded = union(enum) { + adc: Adc, + adcs: Adcs, + sbc: Sbc, + sbcs: Sbcs, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.op) { + .adc => switch (inst.group.S) { + false => .{ .adc = inst.adc }, + true => .{ .adcs = inst.adcs }, + }, + .sbc => switch (inst.group.S) { + false => .{ .sbc = inst.sbc }, + true => .{ .sbcs = inst.sbcs }, + }, + }; + } + }; + + /// Rotate right into flags + pub const RotateRightIntoFlags = packed union { + group: @This().Group, + + pub const Group = packed struct { + mask: Nzcv, + o2: u1, + Rn: Register.Encoded, + decoded10: u5 = 0b0001, + imm6: u6, + decoded21: u8 = 0b11010000, + S: bool, + op: u1, + sf: Register.IntegerSize, + }; + }; + + /// Evaluate into flags + pub const EvaluateIntoFlags = packed union { + group: @This().Group, + + pub const Group = packed struct { + mask: Nzcv, + o3: u1, + Rn: Register.Encoded, + decoded10: u4 = 0b0010, + sz: enum(u1) { + byte = 0b0, + word = 0b1, + }, + opcode2: u6, + decoded21: u8 = 0b11010000, + S: bool, + op: u1, + sf: Register.IntegerSize, + }; + }; + + /// Conditional compare (register) + pub const ConditionalCompareRegister = packed union { + group: @This().Group, + ccmn: Ccmn, + ccmp: Ccmp, + + pub const Group = packed struct { + nzcv: Nzcv, + o3: u1, + Rn: Register.Encoded, + o2: u1, + decoded11: u1 = 0b0, + cond: ConditionCode, + Rm: Register.Encoded, + decoded21: u8 = 0b11010010, + S: bool, + op: Op, + sf: Register.IntegerSize, + }; + + /// C6.2.49 CCMN (register) + pub const Ccmn = packed struct { + nzcv: Nzcv, + o3: u1 = 0b0, + Rn: Register.Encoded, + o2: u1 = 0b0, + decoded11: u1 = 0b0, + cond: ConditionCode, + Rm: Register.Encoded, + decoded21: u8 = 0b11010010, + S: bool = true, + op: Op = .ccmn, + sf: Register.IntegerSize, + }; + + /// C6.2.51 CCMP (register) + pub const Ccmp = packed struct { + nzcv: Nzcv, + o3: u1 = 0b0, + Rn: Register.Encoded, + o2: u1 = 0b0, + decoded11: u1 = 0b0, + cond: ConditionCode, + Rm: Register.Encoded, + decoded21: u8 = 0b11010010, + S: bool = true, + op: Op = .ccmp, + sf: Register.IntegerSize, + }; + + pub const Op = enum(u1) { + ccmn = 0b0, + ccmp = 0b1, + }; + }; + + /// Conditional compare (immediate) + pub const ConditionalCompareImmediate = packed union { + group: @This().Group, + ccmn: Ccmn, + ccmp: Ccmp, + + pub const Group = packed struct { + nzcv: Nzcv, + o3: u1, + Rn: Register.Encoded, + o2: u1, + decoded11: u1 = 0b1, + cond: ConditionCode, + imm5: u5, + decoded21: u8 = 0b11010010, + S: bool, + op: Op, + sf: Register.IntegerSize, + }; + + /// C6.2.48 CCMN (immediate) + pub const Ccmn = packed struct { + nzcv: Nzcv, + o3: u1 = 0b0, + Rn: Register.Encoded, + o2: u1 = 0b0, + decoded11: u1 = 0b1, + cond: ConditionCode, + imm5: u5, + decoded21: u8 = 0b11010010, + S: bool = true, + op: Op = .ccmn, + sf: Register.IntegerSize, + }; + + /// C6.2.50 CCMP (immediate) + pub const Ccmp = packed struct { + nzcv: Nzcv, + o3: u1 = 0b0, + Rn: Register.Encoded, + o2: u1 = 0b0, + decoded11: u1 = 0b1, + cond: ConditionCode, + imm5: u5, + decoded21: u8 = 0b11010010, + S: bool = true, + op: Op = .ccmp, + sf: Register.IntegerSize, + }; + + pub const Op = enum(u1) { + ccmn = 0b0, + ccmp = 0b1, + }; + }; + + /// Conditional select + pub const ConditionalSelect = packed union { + group: @This().Group, + csel: Csel, + csinc: Csinc, + csinv: Csinv, + csneg: Csneg, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + op2: u2, + cond: ConditionCode, + Rm: Register.Encoded, + decoded21: u8 = 0b11010100, + S: bool, + op: u1, + sf: Register.IntegerSize, + }; + + /// C6.2.103 CSEL + pub const Csel = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + op2: u2 = 0b00, + cond: ConditionCode, + Rm: Register.Encoded, + decoded21: u8 = 0b11010100, + S: bool = false, + op: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.106 CSINC + pub const Csinc = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + op2: u2 = 0b01, + cond: ConditionCode, + Rm: Register.Encoded, + decoded21: u8 = 0b11010100, + S: bool = false, + op: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C6.2.107 CSINV + pub const Csinv = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + op2: u2 = 0b00, + cond: ConditionCode, + Rm: Register.Encoded, + decoded21: u8 = 0b11010100, + S: bool = false, + op: u1 = 0b1, + sf: Register.IntegerSize, + }; + + /// C6.2.108 CSNEG + pub const Csneg = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + op2: u2 = 0b01, + cond: ConditionCode, + Rm: Register.Encoded, + decoded21: u8 = 0b11010100, + S: bool = false, + op: u1 = 0b1, + sf: Register.IntegerSize, + }; + + pub const Decoded = union(enum) { + unallocated, + csel: Csel, + csinc: Csinc, + csinv: Csinv, + csneg: Csneg, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.S) { + true => .unallocated, + false => switch (inst.group.op) { + 0b0 => switch (inst.group.op2) { + 0b10...0b11 => .unallocated, + 0b00 => .{ .csel = inst.csel }, + 0b01 => .{ .csinc = inst.csinc }, + }, + 0b1 => switch (inst.group.op2) { + 0b10...0b11 => .unallocated, + 0b00 => .{ .csinv = inst.csinv }, + 0b01 => .{ .csneg = inst.csneg }, + }, + }, + }; + } + }; + + /// Data-processing (3 source) + pub const DataProcessingThreeSource = packed union { + group: @This().Group, + madd: Madd, + msub: Msub, + smaddl: Smaddl, + smsubl: Smsubl, + smulh: Smulh, + umaddl: Umaddl, + umsubl: Umsubl, + umulh: Umulh, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded, + o0: AddSubtractOp, + Rm: Register.Encoded, + op31: u3, + decoded24: u5 = 0b11011, + op54: u2, + sf: Register.IntegerSize, + }; + + /// C6.2.218 MADD + pub const Madd = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded, + o0: AddSubtractOp = .add, + Rm: Register.Encoded, + op31: u3 = 0b000, + decoded24: u5 = 0b11011, + op54: u2 = 0b00, + sf: Register.IntegerSize, + }; + + /// C6.2.231 MSUB + pub const Msub = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded, + o0: AddSubtractOp = .sub, + Rm: Register.Encoded, + op31: u3 = 0b000, + decoded24: u5 = 0b11011, + op54: u2 = 0b00, + sf: Register.IntegerSize, + }; + + /// C6.2.282 SMADDL + pub const Smaddl = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded, + o0: AddSubtractOp = .add, + Rm: Register.Encoded, + op21: u2 = 0b01, + U: bool = false, + decoded24: u5 = 0b11011, + op54: u2 = 0b00, + sf: Register.IntegerSize = .doubleword, + }; + + /// C6.2.287 SMSUBL + pub const Smsubl = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded, + o0: AddSubtractOp = .sub, + Rm: Register.Encoded, + op21: u2 = 0b01, + U: bool = false, + decoded24: u5 = 0b11011, + op54: u2 = 0b00, + sf: Register.IntegerSize = .doubleword, + }; + + /// C6.2.288 SMULH + pub const Smulh = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded = @enumFromInt(0b11111), + o0: AddSubtractOp = .add, + Rm: Register.Encoded, + op21: u2 = 0b10, + U: bool = false, + decoded24: u5 = 0b11011, + op54: u2 = 0b00, + sf: Register.IntegerSize = .doubleword, + }; + + /// C6.2.389 UMADDL + pub const Umaddl = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded, + o0: AddSubtractOp = .add, + Rm: Register.Encoded, + op21: u2 = 0b01, + U: bool = true, + decoded24: u5 = 0b11011, + op54: u2 = 0b00, + sf: Register.IntegerSize = .doubleword, + }; + + /// C6.2.391 UMSUBL + pub const Umsubl = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded, + o0: AddSubtractOp = .sub, + Rm: Register.Encoded, + op21: u2 = 0b01, + U: bool = true, + decoded24: u5 = 0b11011, + op54: u2 = 0b00, + sf: Register.IntegerSize = .doubleword, + }; + + /// C6.2.392 UMULH + pub const Umulh = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded = @enumFromInt(0b11111), + o0: AddSubtractOp = .add, + Rm: Register.Encoded, + op21: u2 = 0b10, + U: bool = true, + decoded24: u5 = 0b11011, + op54: u2 = 0b00, + sf: Register.IntegerSize = .doubleword, + }; + + pub const Decoded = union(enum) { + unallocated, + madd: Madd, + msub: Msub, + smaddl: Smaddl, + smsubl: Smsubl, + smulh: Smulh, + umaddl: Umaddl, + umsubl: Umsubl, + umulh: Umulh, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.op54) { + 0b01, 0b10...0b11 => .unallocated, + 0b00 => switch (inst.group.op31) { + 0b011, 0b100, 0b111 => .unallocated, + 0b000 => switch (inst.group.o0) { + .add => .{ .madd = inst.madd }, + .sub => .{ .msub = inst.msub }, + }, + 0b001 => switch (inst.group.sf) { + .word => .unallocated, + .doubleword => switch (inst.group.o0) { + .add => .{ .smaddl = inst.smaddl }, + .sub => .{ .smsubl = inst.smsubl }, + }, + }, + 0b010 => switch (inst.group.sf) { + .word => .unallocated, + .doubleword => switch (inst.group.o0) { + .add => .{ .smulh = inst.smulh }, + .sub => .unallocated, + }, + }, + 0b101 => switch (inst.group.sf) { + .word => .unallocated, + .doubleword => switch (inst.group.o0) { + .add => .{ .umaddl = inst.umaddl }, + .sub => .{ .umsubl = inst.umsubl }, + }, + }, + 0b110 => switch (inst.group.sf) { + .word => .unallocated, + .doubleword => switch (inst.group.o0) { + .add => .{ .umulh = inst.umulh }, + .sub => .unallocated, + }, + }, + }, + }; + } + }; + + pub const Shift = union(enum(u2)) { + lsl: Amount = 0b00, + lsr: Amount = 0b01, + asr: Amount = 0b10, + ror: Amount = 0b11, + + pub const Op = @typeInfo(Shift).@"union".tag_type.?; + pub const Amount = u6; + pub const none: Shift = .{ .lsl = 0 }; + }; + + pub const Nzcv = packed struct { v: bool, c: bool, z: bool, n: bool }; + + pub const Decoded = union(enum) { + unallocated, + data_processing_two_source: DataProcessingTwoSource, + data_processing_one_source: DataProcessingOneSource, + logical_shifted_register: LogicalShiftedRegister, + add_subtract_shifted_register: AddSubtractShiftedRegister, + add_subtract_extended_register: AddSubtractExtendedRegister, + add_subtract_with_carry: AddSubtractWithCarry, + rotate_right_into_flags: RotateRightIntoFlags, + evaluate_into_flags: EvaluateIntoFlags, + conditional_compare_register: ConditionalCompareRegister, + conditional_compare_immediate: ConditionalCompareImmediate, + conditional_select: ConditionalSelect, + data_processing_three_source: DataProcessingThreeSource, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.op1) { + 0b0 => switch (@as(u1, @truncate(inst.group.op2 >> 3))) { + 0b0 => .{ .logical_shifted_register = inst.logical_shifted_register }, + 0b1 => switch (@as(u1, @truncate(inst.group.op2 >> 0))) { + 0b0 => .{ .add_subtract_shifted_register = inst.add_subtract_shifted_register }, + 0b1 => .{ .add_subtract_extended_register = inst.add_subtract_extended_register }, + }, + }, + 0b1 => switch (inst.group.op2) { + 0b0000 => switch (inst.group.op3) { + 0b000000 => .{ .add_subtract_with_carry = inst.add_subtract_with_carry }, + 0b000001, 0b100001 => .{ .rotate_right_into_flags = inst.rotate_right_into_flags }, + 0b000010, 0b010010, 0b100010, 0b110010 => .{ .evaluate_into_flags = inst.evaluate_into_flags }, + else => .unallocated, + }, + 0b0010 => switch (@as(u1, @truncate(inst.group.op3 >> 1))) { + 0b0 => .{ .conditional_compare_register = inst.conditional_compare_register }, + 0b1 => .{ .conditional_compare_immediate = inst.conditional_compare_immediate }, + }, + 0b0100 => .{ .conditional_select = inst.conditional_select }, + 0b0110 => switch (inst.group.op0) { + 0b0 => .{ .data_processing_two_source = inst.data_processing_two_source }, + 0b1 => .{ .data_processing_one_source = inst.data_processing_one_source }, + }, + 0b1000...0b1111 => .{ .data_processing_three_source = inst.data_processing_three_source }, + else => .unallocated, + }, + }; + } + }; + + /// C4.1.90 Data Processing -- Scalar Floating-Point and Advanced SIMD + pub const DataProcessingVector = packed union { + group: @This().Group, + simd_scalar_pairwise: SimdScalarPairwise, + simd_copy: SimdCopy, + simd_two_register_miscellaneous: SimdTwoRegisterMiscellaneous, + simd_across_lanes: SimdAcrossLanes, + simd_three_same: SimdThreeSame, + simd_modified_immediate: SimdModifiedImmediate, + convert_float_integer: ConvertFloatInteger, + float_data_processing_one_source: FloatDataProcessingOneSource, + float_compare: FloatCompare, + float_immediate: FloatImmediate, + float_data_processing_two_source: FloatDataProcessingTwoSource, + float_data_processing_three_source: FloatDataProcessingThreeSource, + + /// Table C4-91 Encoding table for the Data Processing -- Scalar Floating-Point and Advanced SIMD group + pub const Group = packed struct { + encoded0: u10, + op3: u9, + op2: u4, + op1: u2, + decoded25: u3 = 0b111, + op0: u4, + }; + + /// Advanced SIMD scalar pairwise + pub const SimdScalarPairwise = packed union { + group: @This().Group, + addp: Addp, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: u5, + decoded17: u5 = 0b11000, + size: Size, + decoded24: u5 = 0b11110, + U: u1, + decoded30: u2 = 0b01, + }; + + /// C7.2.4 ADDP (scalar) + pub const Addp = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: u5 = 0b11011, + decoded17: u5 = 0b11000, + size: Size, + decoded24: u5 = 0b11110, + U: u1 = 0b0, + decoded30: u2 = 0b01, + }; + }; + + /// Advanced SIMD copy + pub const SimdCopy = packed union { + group: @This().Group, + smov: Smov, + umov: Umov, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u1 = 0b1, + imm4: u4, + decoded15: u1 = 0b0, + imm5: u5, + decoded21: u8 = 0b01110000, + op: u1, + Q: Register.IntegerSize, + decoded31: u1 = 0b0, + }; + + /// C7.2.279 SMOV + pub const Smov = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u1 = 0b1, + decoded11: u1 = 0b1, + decoded12: u1 = 0b0, + decoded13: u2 = 0b01, + decoded15: u1 = 0b0, + imm5: u5, + decoded21: u8 = 0b01110000, + decoded29: u1 = 0b0, + Q: Register.IntegerSize, + decoded31: u1 = 0b0, + }; + + /// C7.2.371 UMOV + pub const Umov = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u1 = 0b1, + decoded11: u1 = 0b1, + decoded12: u1 = 0b1, + decoded13: u2 = 0b01, + decoded15: u1 = 0b0, + imm5: u5, + decoded21: u8 = 0b01110000, + decoded29: u1 = 0b0, + Q: Register.IntegerSize, + decoded31: u1 = 0b0, + }; + }; + + /// Advanced SIMD two-register miscellaneous + pub const SimdTwoRegisterMiscellaneous = packed union { + group: @This().Group, + cnt: Cnt, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: u5, + decoded17: u5 = 0b10000, + size: Size, + decoded24: u5 = 0b01110, + U: u1, + Q: Q, + decoded31: u1 = 0b0, + }; + + /// C7.2.38 CNT + pub const Cnt = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: u5 = 0b00101, + decoded17: u5 = 0b10000, + size: Size, + decoded24: u5 = 0b01110, + U: u1 = 0b0, + Q: Q, + decoded31: u1 = 0b0, + }; + }; + + /// Advanced SIMD across lanes + pub const SimdAcrossLanes = packed union { + group: @This().Group, + addv: Addv, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: u5, + decoded17: u5 = 0b11000, + size: Size, + decoded24: u5 = 0b01110, + U: u1, + Q: Q, + decoded31: u1 = 0b0, + }; + + /// C7.2.6 ADDV + pub const Addv = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: u5 = 0b11011, + decoded17: u5 = 0b11000, + size: Size, + decoded24: u5 = 0b01110, + U: u1 = 0b0, + Q: Q, + decoded31: u1 = 0b0, + }; + }; + + /// Advanced SIMD three same + pub const SimdThreeSame = packed union { + group: @This().Group, + addp: Addp, + @"and": And, + bic: Bic, + orr: Orr, + orn: Orn, + eor: Eor, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u1 = 0b1, + opcode: u5, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + size: Size, + decoded24: u5 = 0b01110, + U: u1, + Q: Q, + decoded31: u1 = 0b0, + }; + + /// C7.2.5 ADDP (vector) + pub const Addp = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u1 = 0b1, + opcode: u5 = 0b10111, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + size: Size, + decoded24: u5 = 0b01110, + U: u1 = 0b0, + Q: Q, + decoded31: u1 = 0b0, + }; + + /// C7.2.11 AND (vector) + pub const And = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u1 = 0b1, + opcode: u5 = 0b00011, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + size: Size = .byte, + decoded24: u5 = 0b01110, + U: u1 = 0b0, + Q: Q, + decoded31: u1 = 0b0, + }; + + /// C7.2.21 BIC (vector, register) + pub const Bic = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u1 = 0b1, + opcode: u5 = 0b00011, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + size: Size = .half, + decoded24: u5 = 0b01110, + U: u1 = 0b0, + Q: Q, + decoded31: u1 = 0b0, + }; + + /// C7.2.213 ORR (vector, register) + pub const Orr = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u1 = 0b1, + opcode: u5 = 0b00011, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + size: Size = .single, + decoded24: u5 = 0b01110, + U: u1 = 0b0, + Q: Q, + decoded31: u1 = 0b0, + }; + + /// C7.2.211 ORN (vector) + pub const Orn = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u1 = 0b1, + opcode: u5 = 0b00011, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + size: Size = .double, + decoded24: u5 = 0b01110, + U: u1 = 0b0, + Q: Q, + decoded31: u1 = 0b0, + }; + + /// C7.2.41 EOR (vector) + pub const Eor = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u1 = 0b1, + opcode: u5 = 0b00011, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + size: Size = .byte, + decoded24: u5 = 0b01110, + U: u1 = 0b1, + Q: Q, + decoded31: u1 = 0b0, + }; + }; + + /// Advanced SIMD modified immediate + pub const SimdModifiedImmediate = packed union { + group: @This().Group, + movi: Movi, + orr: Orr, + fmov: Fmov, + mvni: Mvni, + bic: Bic, + + pub const Group = packed struct { + Rd: Register.Encoded, + imm5: u5, + decoded10: u1 = 0b1, + o2: u1, + cmode: u4, + imm3: u3, + decoded19: u10 = 0b0111100000, + op: u1, + Q: Q, + decoded31: u1 = 0b0, + }; + + /// C7.2.204 MOVI + pub const Movi = packed struct { + Rd: Register.Encoded, + imm5: u5, + decoded10: u1 = 0b1, + o2: u1 = 0b0, + cmode: u4, + imm3: u3, + decoded19: u10 = 0b0111100000, + op: u1, + Q: Q, + decoded31: u1 = 0b0, + }; + + /// C7.2.212 ORR (vector, immediate) + pub const Orr = packed struct { + Rd: Register.Encoded, + imm5: u5, + decoded10: u1 = 0b1, + o2: u1 = 0b0, + cmode0: u1 = 0b1, + cmode: u3, + imm3: u3, + decoded19: u10 = 0b0111100000, + op: u1 = 0b0, + Q: Q, + decoded31: u1 = 0b0, + }; + + /// C7.2.129 FMOV (vector, immediate) + pub const Fmov = packed struct { + Rd: Register.Encoded, + imm5: u5, + decoded10: u1 = 0b1, + o2: u1 = 0b1, + cmode: u4 = 0b1111, + imm3: u3, + decoded19: u10 = 0b0111100000, + op: u1 = 0b0, + Q: Q, + decoded31: u1 = 0b0, + }; + + /// C7.2.208 MVNI + pub const Mvni = packed struct { + Rd: Register.Encoded, + imm5: u5, + decoded10: u1 = 0b1, + o2: u1 = 0b0, + cmode: u4, + imm3: u3, + decoded19: u10 = 0b0111100000, + op: u1 = 0b1, + Q: Q, + decoded31: u1 = 0b0, + }; + + /// C7.2.20 BIC (vector, immediate) + pub const Bic = packed struct { + Rd: Register.Encoded, + imm5: u5, + decoded10: u1 = 0b1, + o2: u1 = 0b0, + cmode0: u1 = 0b1, + cmode: u3, + imm3: u3, + decoded19: u10 = 0b0111100000, + op: u1 = 0b1, + Q: Q, + decoded31: u1 = 0b0, + }; + }; + + /// Conversion between floating-point and integer + pub const ConvertFloatInteger = packed union { + group: @This().Group, + fcvtns: Fcvtns, + fcvtnu: Fcvtnu, + scvtf: Scvtf, + ucvtf: Ucvtf, + fcvtas: Fcvtas, + fcvtau: Fcvtau, + fmov: Fmov, + fcvtps: Fcvtps, + fcvtpu: Fcvtpu, + fcvtms: Fcvtms, + fcvtmu: Fcvtmu, + fcvtzs: Fcvtzs, + fcvtzu: Fcvtzu, + fjcvtzs: Fjcvtzs, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3, + rmode: u2, + decoded21: u1 = 0b1, + ptype: Ftype, + decoded24: u5 = 0b11110, + S: bool, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C7.2.81 FCVTNS (scalar) + pub const Fcvtns = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3 = 0b000, + rmode: Rmode = .n, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C7.2.83 FCVTNU (scalar) + pub const Fcvtnu = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3 = 0b001, + rmode: Rmode = .n, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C7.2.236 SCVTF (scalar, integer) + pub const Scvtf = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3 = 0b010, + rmode: Rmode = .n, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C7.2.355 UCVTF (scalar, integer) + pub const Ucvtf = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3 = 0b011, + rmode: Rmode = .n, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C7.2.71 FCVTAS (scalar) + pub const Fcvtas = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3 = 0b100, + rmode: Rmode = .n, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C7.2.73 FCVTAU (scalar) + pub const Fcvtau = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3 = 0b101, + rmode: Rmode = .n, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C7.2.131 FMOV (general) + pub const Fmov = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: Opcode, + rmode: Fmov.Rmode, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + + pub const Opcode = enum(u3) { + float_to_integer = 0b110, + integer_to_float = 0b111, + _, + }; + + pub const Rmode = enum(u2) { + @"0" = 0b00, + @"1" = 0b01, + _, + }; + }; + + /// C7.2.85 FCVTPS (scalar) + pub const Fcvtps = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3 = 0b000, + rmode: Rmode = .p, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C7.2.87 FCVTPU (scalar) + pub const Fcvtpu = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3 = 0b001, + rmode: Rmode = .p, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C7.2.76 FCVTMS (scalar) + pub const Fcvtms = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3 = 0b000, + rmode: Rmode = .m, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C7.2.78 FCVTMU (scalar) + pub const Fcvtmu = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3 = 0b001, + rmode: Rmode = .m, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C7.2.92 FCVTZS (scalar, integer) + pub const Fcvtzs = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3 = 0b000, + rmode: Rmode = .z, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C7.2.96 FCVTZU (scalar, integer) + pub const Fcvtzu = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3 = 0b001, + rmode: Rmode = .z, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize, + }; + + /// C7.2.99 FJCVTZS + pub const Fjcvtzs = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u6 = 0b000000, + opcode: u3 = 0b110, + rmode: Rmode = .z, + decoded21: u1 = 0b1, + ftype: Ftype = .double, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + sf: Register.IntegerSize = .word, + }; + + pub const Rmode = enum(u2) { + /// to nearest + n = 0b00, + /// toward plus infinity + p = 0b01, + /// toward minus infinity + m = 0b10, + /// toward zero + z = 0b11, + }; + }; + + /// Floating-point data-processing (1 source) + pub const FloatDataProcessingOneSource = packed union { + group: @This().Group, + fmov: Fmov, + fabs: Fabs, + fneg: Fneg, + fsqrt: Fsqrt, + fcvt: Fcvt, + frintn: Frintn, + frintp: Frintp, + frintm: Frintm, + frintz: Frintz, + frinta: Frinta, + frintx: Frintx, + frinti: Frinti, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u5 = 0b10000, + opcode: u6, + decoded21: u1 = 0b1, + ptype: Ftype, + decoded24: u5 = 0b11110, + S: bool, + decoded30: u1 = 0b0, + M: u1, + }; + + /// C7.2.130 FMOV (register) + pub const Fmov = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u5 = 0b10000, + opc: u2 = 0b00, + decoded17: u4 = 0b0000, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.46 FABS (scalar) + pub const Fabs = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u5 = 0b10000, + opc: u2 = 0b01, + decoded17: u4 = 0b0000, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.140 FNEG (scalar) + pub const Fneg = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u5 = 0b10000, + opc: u2 = 0b10, + decoded17: u4 = 0b0000, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.172 FSQRT (scalar) + pub const Fsqrt = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u5 = 0b10000, + opc: u2 = 0b11, + decoded17: u4 = 0b0000, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.69 FCVT + pub const Fcvt = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u5 = 0b10000, + opc: Ftype, + decoded17: u4 = 0b0001, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.162 FRINTN (scalar) + pub const Frintn = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u5 = 0b10000, + rmode: Rmode = .n, + decoded18: u3 = 0b001, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.164 FRINTP (scalar) + pub const Frintp = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u5 = 0b10000, + rmode: Rmode = .p, + decoded18: u3 = 0b001, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.160 FRINTM (scalar) + pub const Frintm = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u5 = 0b10000, + rmode: Rmode = .m, + decoded18: u3 = 0b001, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.168 FRINTZ (scalar) + pub const Frintz = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u5 = 0b10000, + rmode: Rmode = .z, + decoded18: u3 = 0b001, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.156 FRINTA (scalar) + pub const Frinta = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u5 = 0b10000, + rmode: Rmode = .a, + decoded18: u3 = 0b001, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.166 FRINTX (scalar) + pub const Frintx = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u5 = 0b10000, + rmode: Rmode = .x, + decoded18: u3 = 0b001, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.158 FRINTI (scalar) + pub const Frinti = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u5 = 0b10000, + rmode: Rmode = .i, + decoded18: u3 = 0b001, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + pub const Rmode = enum(u3) { + /// to nearest with ties to even + n = 0b000, + /// toward plus infinity + p = 0b001, + /// toward minus infinity + m = 0b010, + /// toward zero + z = 0b011, + /// to nearest with ties to away + a = 0b100, + /// exact, using current rounding mode + x = 0b110, + /// using current rounding mode + i = 0b111, + _, + }; + }; + + /// Floating-point compare + pub const FloatCompare = packed union { + group: @This().Group, + fcmp: Fcmp, + fcmpe: Fcmpe, + + pub const Group = packed struct { + opcode2: u5, + Rn: Register.Encoded, + decoded10: u4 = 0b1000, + op: u2, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + ptype: Ftype, + decoded24: u5 = 0b11110, + S: bool, + decoded30: u1 = 0b0, + M: u1, + }; + + /// C7.2.66 FCMP + pub const Fcmp = packed struct { + decoded0: u3 = 0b000, + opc0: Opc0, + opc1: u1 = 0b0, + Rn: Register.Encoded, + decoded10: u4 = 0b1000, + op: u2 = 0b00, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.67 FCMPE + pub const Fcmpe = packed struct { + decoded0: u3 = 0b000, + opc0: Opc0, + opc1: u1 = 0b1, + Rn: Register.Encoded, + decoded10: u4 = 0b1000, + op: u2 = 0b00, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + pub const Opc0 = enum(u1) { + register = 0b00, + zero = 0b01, + }; + }; + + /// Floating-point immediate + pub const FloatImmediate = packed union { + group: @This().Group, + fmov: Fmov, + + pub const Group = packed struct { + Rd: Register.Encoded, + imm5: u5, + decoded10: u3 = 0b100, + imm8: u8, + decoded21: u1 = 0b1, + ptype: Ftype, + decoded24: u5 = 0b11110, + S: bool, + decoded30: u1 = 0b0, + M: u1, + }; + + /// C7.2.132 FMOV (scalar, immediate) + pub const Fmov = packed struct { + Rd: Register.Encoded, + imm5: u5 = 0b00000, + decoded10: u3 = 0b100, + imm8: u8, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + }; + + /// Floating-point data-processing (2 source) + pub const FloatDataProcessingTwoSource = packed union { + group: @This().Group, + fmul: Fmul, + fdiv: Fdiv, + fadd: Fadd, + fsub: Fsub, + fmax: Fmax, + fmin: Fmin, + fmaxnm: Fmaxnm, + fminnm: Fminnm, + fnmul: Fnmul, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: Opcode, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + ptype: Ftype, + decoded24: u5 = 0b11110, + S: bool, + decoded30: u1 = 0b0, + M: u1, + }; + + /// C7.2.136 FMUL (scalar) + pub const Fmul = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: Opcode = .fmul, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.98 FDIV (scalar) + pub const Fdiv = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: Opcode = .fdiv, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.50 FADD (scalar) + pub const Fadd = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: Opcode = .fadd, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.174 FSUB (scalar) + pub const Fsub = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: Opcode = .fsub, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.102 FMAX (scalar) + pub const Fmax = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: Opcode = .fmax, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.112 FMIN (scalar) + pub const Fmin = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: Opcode = .fmin, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.104 FMAXNM (scalar) + pub const Fmaxnm = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: Opcode = .fmaxnm, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.114 FMINNM (scalar) + pub const Fminnm = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: Opcode = .fminnm, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.143 FNMUL (scalar) + pub const Fnmul = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + decoded10: u2 = 0b10, + opcode: Opcode = .fnmul, + Rm: Register.Encoded, + decoded21: u1 = 0b1, + ftype: Ftype, + decoded24: u5 = 0b11110, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + pub const Opcode = enum(u4) { + fmul = 0b0000, + fdiv = 0b0001, + fadd = 0b0010, + fsub = 0b0011, + fmax = 0b0100, + fmin = 0b0101, + fmaxnm = 0b0110, + fminnm = 0b0111, + fnmul = 0b1000, + _, + }; + }; + + /// Floating-point data-processing (3 source) + pub const FloatDataProcessingThreeSource = packed union { + group: @This().Group, + fmadd: Fmadd, + fmsub: Fmsub, + fnmadd: Fnmadd, + fnmsub: Fnmsub, + + pub const Group = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded, + o0: AddSubtractOp, + Rm: Register.Encoded, + o1: u1, + ptype: Ftype, + decoded24: u5 = 0b11111, + S: bool, + decoded30: u1 = 0b0, + M: u1, + }; + + /// C7.2.100 FMADD + pub const Fmadd = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded, + o0: AddSubtractOp = .add, + Rm: Register.Encoded, + o1: O1 = .fm, + ftype: Ftype, + decoded24: u5 = 0b11111, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.133 FMSUB + pub const Fmsub = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded, + o0: AddSubtractOp = .sub, + Rm: Register.Encoded, + o1: O1 = .fm, + ftype: Ftype, + decoded24: u5 = 0b11111, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.141 FNMADD + pub const Fnmadd = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded, + o0: AddSubtractOp = .add, + Rm: Register.Encoded, + o1: O1 = .fnm, + ftype: Ftype, + decoded24: u5 = 0b11111, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + /// C7.2.142 FNMSUB + pub const Fnmsub = packed struct { + Rd: Register.Encoded, + Rn: Register.Encoded, + Ra: Register.Encoded, + o0: AddSubtractOp = .sub, + Rm: Register.Encoded, + o1: O1 = .fnm, + ftype: Ftype, + decoded24: u5 = 0b11111, + S: bool = false, + decoded30: u1 = 0b0, + M: u1 = 0b0, + }; + + pub const O1 = enum(u1) { + fm = 0b0, + fnm = 0b1, + }; + }; + + pub const Q = enum(u1) { + double = 0b0, + quad = 0b1, + }; + + pub const Size = enum(u2) { + byte = 0b00, + half = 0b01, + single = 0b10, + double = 0b11, + + pub fn toVectorSize(s: Size) Register.VectorSize { + return switch (s) { + .byte => .byte, + .half => .half, + .single => .single, + .double => .double, + }; + } + + pub fn fromVectorSize(vs: Register.VectorSize) Size { + return switch (vs) { + .byte => .byte, + .half => .half, + .single => .single, + .double => .double, + }; + } + }; + + pub const Ftype = enum(u2) { + single = 0b00, + double = 0b01, + quad = 0b10, + half = 0b11, + }; + }; + + pub const AddSubtractOp = enum(u1) { + add = 0b0, + sub = 0b1, + }; + + pub const LogicalOpc = enum(u2) { + @"and" = 0b00, + orr = 0b01, + eor = 0b10, + ands = 0b11, + }; + + pub const Decoded = union(enum) { + unallocated, + reserved: Reserved, + sme: Sme, + sve: Sve, + data_processing_immediate: DataProcessingImmediate, + branch_exception_generating_system: BranchExceptionGeneratingSystem, + load_store: LoadStore, + data_processing_register: DataProcessingRegister, + data_processing_vector: DataProcessingVector, + }; + pub fn decode(inst: @This()) @This().Decoded { + return switch (inst.group.op1) { + 0b0000 => switch (inst.group.op0) { + 0b0 => .{ .reserved = inst.reserved }, + 0b1 => .{ .sme = inst.sme }, + }, + 0b0001 => .unallocated, + 0b0010 => .{ .sve = inst.sve }, + 0b0011 => .unallocated, + 0b1000, 0b1001 => .{ .data_processing_immediate = inst.data_processing_immediate }, + 0b1010, 0b1011 => .{ .branch_exception_generating_system = inst.branch_exception_generating_system }, + 0b0100, 0b0110, 0b1100, 0b1110 => .{ .load_store = inst.load_store }, + 0b0101, 0b1101 => .{ .data_processing_register = inst.data_processing_register }, + 0b0111, 0b1111 => .{ .data_processing_vector = inst.data_processing_vector }, + }; + } + + /// C6.2.1 ADC + pub fn adc(d: Register, n: Register, m: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .add_subtract_with_carry = .{ + .adc = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.2 ADCS + pub fn adcs(d: Register, n: Register, m: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .add_subtract_with_carry = .{ + .adcs = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.3 ADD (extended register) + /// C6.2.4 ADD (immediate) + /// C6.2.5 ADD (shifted register) + pub fn add(d: Register, n: Register, form: union(enum) { + extended_register_explicit: struct { + register: Register, + option: DataProcessingRegister.AddSubtractExtendedRegister.Option, + amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount, + }, + extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend }, + immediate: u12, + shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" }, + register: Register, + shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, + shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, + }) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf); + form: switch (form) { + .extended_register_explicit => |extended_register_explicit| { + assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf()); + return .{ .data_processing_register = .{ .add_subtract_extended_register = .{ + .add = .{ + .Rd = d.alias.encode(.{ .sp = true }), + .Rn = n.alias.encode(.{ .sp = true }), + .imm3 = switch (extended_register_explicit.amount) { + 0...4 => |amount| amount, + else => unreachable, + }, + .option = extended_register_explicit.option, + .Rm = extended_register_explicit.register.alias.encode(.{}), + .sf = sf, + }, + } } }; + }, + .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ + .register = extended_register.register, + .option = extended_register.extend, + .amount = switch (extended_register.extend) { + .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount, + }, + } }, + .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } }, + .shifted_immediate => |shifted_immediate| { + return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{ + .add = .{ + .Rd = d.alias.encode(.{ .sp = true }), + .Rn = n.alias.encode(.{ .sp = true }), + .imm12 = shifted_immediate.immediate, + .sh = shifted_immediate.lsl, + .sf = sf, + }, + } } }; + }, + .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp) + .{ .extended_register = .{ .register = register, .extend = switch (sf) { + .word => .{ .uxtw = 0 }, + .doubleword => .{ .uxtx = 0 }, + } } } + else + .{ .shifted_register = .{ .register = register } }, + .shifted_register_explicit => |shifted_register_explicit| { + assert(shifted_register_explicit.register.format.integer == sf); + return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{ + .add = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm6 = switch (sf) { + .word => @as(u5, @intCast(shifted_register_explicit.amount)), + .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), + }, + .Rm = shifted_register_explicit.register.alias.encode(.{}), + .shift = switch (shifted_register_explicit.shift) { + .lsl, .lsr, .asr => |shift| shift, + .ror => unreachable, + }, + .sf = sf, + }, + } } }; + }, + .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ + .register = shifted_register.register, + .shift = shifted_register.shift, + .amount = switch (shifted_register.shift) { + .lsl, .lsr, .asr => |amount| amount, + .ror => unreachable, + }, + } }, + } + } + /// C7.2.4 ADDP (scalar) + /// C7.2.5 ADDP (vector) + pub fn addp(d: Register, n: Register, form: union(enum) { + scalar, + vector: Register, + }) Instruction { + switch (form) { + .scalar => { + assert(d.format.scalar == .double and n.format.vector == .@"2d"); + return .{ .data_processing_vector = .{ .simd_scalar_pairwise = .{ + .addp = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .size = .double, + }, + } } }; + }, + .vector => |m| { + const arrangement = d.format.vector; + assert(arrangement != .@"1d" and n.format.vector == arrangement and m.format.vector == arrangement); + return .{ .data_processing_vector = .{ .simd_three_same = .{ + .addp = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .size = arrangement.elemSize(), + .Q = arrangement.size(), + }, + } } }; + }, + } + } + /// C6.2.7 ADDS (extended register) + /// C6.2.8 ADDS (immediate) + /// C6.2.9 ADDS (shifted register) + pub fn adds(d: Register, n: Register, form: union(enum) { + extended_register_explicit: struct { + register: Register, + option: DataProcessingRegister.AddSubtractExtendedRegister.Option, + amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount, + }, + extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend }, + immediate: u12, + shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" }, + register: Register, + shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, + shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, + }) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf); + form: switch (form) { + .extended_register_explicit => |extended_register_explicit| { + assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf()); + return .{ .data_processing_register = .{ .add_subtract_extended_register = .{ + .adds = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .sp = true }), + .imm3 = switch (extended_register_explicit.amount) { + 0...4 => |amount| amount, + else => unreachable, + }, + .option = extended_register_explicit.option, + .Rm = extended_register_explicit.register.alias.encode(.{}), + .sf = sf, + }, + } } }; + }, + .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ + .register = extended_register.register, + .option = extended_register.extend, + .amount = switch (extended_register.extend) { + .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount, + }, + } }, + .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } }, + .shifted_immediate => |shifted_immediate| { + return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{ + .adds = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .sp = true }), + .imm12 = shifted_immediate.immediate, + .sh = shifted_immediate.lsl, + .sf = sf, + }, + } } }; + }, + .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp) + .{ .extended_register = .{ .register = register, .extend = switch (sf) { + .word => .{ .uxtw = 0 }, + .doubleword => .{ .uxtx = 0 }, + } } } + else + .{ .shifted_register = .{ .register = register } }, + .shifted_register_explicit => |shifted_register_explicit| { + assert(shifted_register_explicit.register.format.integer == sf); + return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{ + .adds = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm6 = switch (sf) { + .word => @as(u5, @intCast(shifted_register_explicit.amount)), + .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), + }, + .Rm = shifted_register_explicit.register.alias.encode(.{}), + .shift = switch (shifted_register_explicit.shift) { + .lsl, .lsr, .asr => |shift| shift, + .ror => unreachable, + }, + .sf = sf, + }, + } } }; + }, + .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ + .register = shifted_register.register, + .shift = shifted_register.shift, + .amount = switch (shifted_register.shift) { + .lsl, .lsr, .asr => |amount| amount, + .ror => unreachable, + }, + } }, + } + } + /// C7.2.6 ADDV + pub fn addv(d: Register, n: Register) Instruction { + const arrangement = n.format.vector; + assert(arrangement.len() > 2 and d.format.scalar == arrangement.elemSize().toVectorSize()); + return .{ .data_processing_vector = .{ .simd_across_lanes = .{ + .addv = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .size = arrangement.elemSize(), + .Q = arrangement.size(), + }, + } } }; + } + /// C6.2.10 ADR + pub fn adr(d: Register, label: i21) Instruction { + assert(d.format.integer == .doubleword); + return .{ .data_processing_immediate = .{ .pc_relative_addressing = .{ + .adr = .{ + .Rd = d.alias.encode(.{}), + .immhi = @intCast(label >> 2), + .immlo = @truncate(@as(u21, @bitCast(label))), + }, + } } }; + } + /// C6.2.11 ADRP + pub fn adrp(d: Register, label: i33) Instruction { + assert(d.format.integer == .doubleword); + const imm: i21 = @intCast(@shrExact(label, 12)); + return .{ .data_processing_immediate = .{ .pc_relative_addressing = .{ + .adrp = .{ + .Rd = d.alias.encode(.{}), + .immhi = @intCast(imm >> 2), + .immlo = @truncate(@as(u21, @bitCast(imm))), + }, + } } }; + } + /// C6.2.12 AND (immediate) + /// C6.2.13 AND (shifted register) + /// C7.2.11 AND (vector) + pub fn @"and"(d: Register, n: Register, form: union(enum) { + immediate: DataProcessingImmediate.Bitmask, + register: Register, + shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, + shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, + }) Instruction { + switch (d.format) { + else => unreachable, + .integer => |sf| { + assert(n.format.integer == sf); + form: switch (form) { + .immediate => |bitmask| { + assert(bitmask.validImmediate(sf)); + return .{ .data_processing_immediate = .{ .logical_immediate = .{ + .@"and" = .{ + .Rd = d.alias.encode(.{ .sp = true }), + .Rn = n.alias.encode(.{}), + .imm = bitmask, + .sf = sf, + }, + } } }; + }, + .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, + .shifted_register_explicit => |shifted_register_explicit| { + assert(shifted_register_explicit.register.format.integer == sf); + return .{ .data_processing_register = .{ .logical_shifted_register = .{ + .@"and" = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm6 = switch (sf) { + .word => @as(u5, @intCast(shifted_register_explicit.amount)), + .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), + }, + .Rm = shifted_register_explicit.register.alias.encode(.{}), + .shift = shifted_register_explicit.shift, + .sf = sf, + }, + } } }; + }, + .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ + .register = shifted_register.register, + .shift = shifted_register.shift, + .amount = switch (shifted_register.shift) { + .lsl, .lsr, .asr, .ror => |amount| amount, + }, + } }, + } + }, + .vector => |arrangement| { + const m = form.register; + assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement); + return .{ .data_processing_vector = .{ .simd_three_same = .{ + .@"and" = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .Q = arrangement.size(), + }, + } } }; + }, + } + } + /// C6.2.14 ANDS (immediate) + /// C6.2.15 ANDS (shifted register) + pub fn ands(d: Register, n: Register, form: union(enum) { + immediate: DataProcessingImmediate.Bitmask, + register: Register, + shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, + shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, + }) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf); + form: switch (form) { + .immediate => |bitmask| { + assert(bitmask.validImmediate(sf)); + return .{ .data_processing_immediate = .{ .logical_immediate = .{ + .ands = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm = bitmask, + .sf = sf, + }, + } } }; + }, + .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, + .shifted_register_explicit => |shifted_register_explicit| { + assert(shifted_register_explicit.register.format.integer == sf); + return .{ .data_processing_register = .{ .logical_shifted_register = .{ + .ands = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm6 = switch (sf) { + .word => @as(u5, @intCast(shifted_register_explicit.amount)), + .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), + }, + .Rm = shifted_register_explicit.register.alias.encode(.{}), + .shift = shifted_register_explicit.shift, + .sf = sf, + }, + } } }; + }, + .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ + .register = shifted_register.register, + .shift = shifted_register.shift, + .amount = switch (shifted_register.shift) { + .lsl, .lsr, .asr, .ror => |amount| amount, + }, + } }, + } + } + /// C6.2.18 ASRV + pub fn asrv(d: Register, n: Register, m: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .data_processing_two_source = .{ + .asrv = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.25 B + pub fn b(label: i28) Instruction { + return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{ + .b = .{ .imm26 = @intCast(@shrExact(label, 2)) }, + } } }; + } + /// C6.2.26 B.cond + pub fn @"b."(cond: ConditionCode, label: i21) Instruction { + return .{ .branch_exception_generating_system = .{ .conditional_branch_immediate = .{ + .b = .{ + .cond = cond, + .imm19 = @intCast(@shrExact(label, 2)), + }, + } } }; + } + /// C6.2.27 BC.cond + pub fn @"bc."(cond: ConditionCode, label: i21) Instruction { + return .{ .branch_exception_generating_system = .{ .conditional_branch_immediate = .{ + .bc = .{ + .cond = cond, + .imm19 = @intCast(@shrExact(label, 2)), + }, + } } }; + } + /// C6.2.30 BFM + pub fn bfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and bitmask.validBitfield(sf)); + return .{ .data_processing_immediate = .{ .bitfield = .{ + .bfm = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm = bitmask, + .sf = sf, + }, + } } }; + } + /// C6.2.32 BIC (shifted register) + /// C7.2.20 BIC (vector, immediate) + /// C7.2.21 BIC (vector, register) + pub fn bic(d: Register, n: Register, form: union(enum) { + shifted_immediate: struct { immediate: u8, lsl: u5 = 0 }, + register: Register, + shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, + shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, + }) Instruction { + switch (d.format) { + else => unreachable, + .integer => |sf| { + assert(n.format.integer == sf); + form: switch (form) { + else => unreachable, + .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, + .shifted_register_explicit => |shifted_register_explicit| { + assert(shifted_register_explicit.register.format.integer == sf); + return .{ .data_processing_register = .{ .logical_shifted_register = .{ + .bic = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm6 = switch (sf) { + .word => @as(u5, @intCast(shifted_register_explicit.amount)), + .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), + }, + .Rm = shifted_register_explicit.register.alias.encode(.{}), + .shift = shifted_register_explicit.shift, + .sf = sf, + }, + } } }; + }, + .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ + .register = shifted_register.register, + .shift = shifted_register.shift, + .amount = switch (shifted_register.shift) { + .lsl, .lsr, .asr, .ror => |amount| amount, + }, + } }, + } + }, + .vector => |arrangement| switch (form) { + else => unreachable, + .shifted_immediate => |shifted_immediate| { + assert(n.alias == d.alias and n.format.vector == arrangement); + return .{ .data_processing_vector = .{ .simd_modified_immediate = .{ + .bic = .{ + .Rd = d.alias.encode(.{ .V = true }), + .imm5 = @truncate(shifted_immediate.immediate >> 0), + .cmode = switch (arrangement) { + else => unreachable, + .@"4h", .@"8h" => @as(u3, 0b100) | + @as(u3, @as(u1, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0, + .@"2s", .@"4s" => @as(u3, 0b000) | + @as(u3, @as(u2, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0, + }, + .imm3 = @intCast(shifted_immediate.immediate >> 5), + .Q = arrangement.size(), + }, + } } }; + }, + .register => |m| { + assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement); + return .{ .data_processing_vector = .{ .simd_three_same = .{ + .bic = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .Q = arrangement.size(), + }, + } } }; + }, + }, + } + } + /// C6.2.33 BICS (shifted register) + pub fn bics(d: Register, n: Register, form: union(enum) { + register: Register, + shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, + shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, + }) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf); + form: switch (form) { + .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, + .shifted_register_explicit => |shifted_register_explicit| { + assert(shifted_register_explicit.register.format.integer == sf); + return .{ .data_processing_register = .{ .logical_shifted_register = .{ + .bics = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm6 = switch (sf) { + .word => @as(u5, @intCast(shifted_register_explicit.amount)), + .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), + }, + .Rm = shifted_register_explicit.register.alias.encode(.{}), + .shift = shifted_register_explicit.shift, + .sf = sf, + }, + } } }; + }, + .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ + .register = shifted_register.register, + .shift = shifted_register.shift, + .amount = switch (shifted_register.shift) { + .lsl, .lsr, .asr, .ror => |amount| amount, + }, + } }, + } + } + /// C6.2.34 BL + pub fn bl(label: i28) Instruction { + return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{ + .bl = .{ .imm26 = @intCast(@shrExact(label, 2)) }, + } } }; + } + /// C6.2.35 BLR + pub fn blr(n: Register) Instruction { + assert(n.format.integer == .doubleword); + return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{ + .blr = .{ .Rn = n.alias.encode(.{}) }, + } } }; + } + /// C6.2.37 BR + pub fn br(n: Register) Instruction { + assert(n.format.integer == .doubleword); + return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{ + .br = .{ .Rn = n.alias.encode(.{}) }, + } } }; + } + /// C6.2.40 BRK + pub fn brk(imm: u16) Instruction { + return .{ .branch_exception_generating_system = .{ .exception_generating = .{ + .brk = .{ .imm16 = imm }, + } } }; + } + /// C6.2.46 CBNZ + pub fn cbnz(t: Register, label: i21) Instruction { + return .{ .branch_exception_generating_system = .{ .compare_branch_immediate = .{ + .cbnz = .{ + .Rt = t.alias.encode(.{}), + .imm19 = @intCast(@shrExact(label, 2)), + .sf = t.format.integer, + }, + } } }; + } + /// C6.2.47 CBZ + pub fn cbz(t: Register, label: i21) Instruction { + return .{ .branch_exception_generating_system = .{ .compare_branch_immediate = .{ + .cbz = .{ + .Rt = t.alias.encode(.{}), + .imm19 = @intCast(@shrExact(label, 2)), + .sf = t.format.integer, + }, + } } }; + } + /// C6.2.48 CCMN (immediate) + /// C6.2.49 CCMN (register) + pub fn ccmn( + n: Register, + form: union(enum) { register: Register, immediate: u5 }, + nzcv: DataProcessingRegister.Nzcv, + cond: ConditionCode, + ) Instruction { + const sf = n.format.integer; + switch (form) { + .register => |m| { + assert(m.format.integer == sf); + return .{ .data_processing_register = .{ .conditional_compare_register = .{ + .ccmn = .{ + .nzcv = nzcv, + .Rn = n.alias.encode(.{}), + .cond = cond, + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + }, + .immediate => |imm| return .{ .data_processing_register = .{ .conditional_compare_immediate = .{ + .ccmn = .{ + .nzcv = nzcv, + .Rn = n.alias.encode(.{}), + .cond = cond, + .imm5 = imm, + .sf = sf, + }, + } } }, + } + } + /// C6.2.50 CCMP (immediate) + /// C6.2.51 CCMP (register) + pub fn ccmp( + n: Register, + form: union(enum) { register: Register, immediate: u5 }, + nzcv: DataProcessingRegister.Nzcv, + cond: ConditionCode, + ) Instruction { + const sf = n.format.integer; + switch (form) { + .register => |m| { + assert(m.format.integer == sf); + return .{ .data_processing_register = .{ .conditional_compare_register = .{ + .ccmp = .{ + .nzcv = nzcv, + .Rn = n.alias.encode(.{}), + .cond = cond, + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + }, + .immediate => |imm| return .{ .data_processing_register = .{ .conditional_compare_immediate = .{ + .ccmp = .{ + .nzcv = nzcv, + .Rn = n.alias.encode(.{}), + .cond = cond, + .imm5 = imm, + .sf = sf, + }, + } } }, + } + } + /// C6.2.56 CLREX + pub fn clrex(imm: u4) Instruction { + return .{ .branch_exception_generating_system = .{ .barriers = .{ + .clrex = .{ + .CRm = imm, + }, + } } }; + } + /// C6.2.58 CLZ + pub fn clz(d: Register, n: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf); + return .{ .data_processing_register = .{ .data_processing_one_source = .{ + .clz = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C7.2.38 CNT + pub fn cnt(d: Register, n: Register) Instruction { + const arrangement = d.format.vector; + assert(arrangement.elemSize() == .byte and n.format.vector == arrangement); + return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ + .cnt = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .size = arrangement.elemSize(), + .Q = arrangement.size(), + }, + } } }; + } + /// C6.2.103 CSEL + pub fn csel(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .conditional_select = .{ + .csel = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .cond = cond, + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.106 CSINC + pub fn csinc(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .conditional_select = .{ + .csinc = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .cond = cond, + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.107 CSINV + pub fn csinv(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .conditional_select = .{ + .csinv = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .cond = cond, + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.108 CSNEG + pub fn csneg(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .conditional_select = .{ + .csneg = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .cond = cond, + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.110 DCPS1 + pub fn dcps1(imm: u16) Instruction { + return .{ .branch_exception_generating_system = .{ .exception_generating = .{ + .dcps1 = .{ .imm16 = imm }, + } } }; + } + /// C6.2.111 DCPS2 + pub fn dcps2(imm: u16) Instruction { + return .{ .branch_exception_generating_system = .{ .exception_generating = .{ + .dcps2 = .{ .imm16 = imm }, + } } }; + } + /// C6.2.112 DCPS3 + pub fn dcps3(imm: u16) Instruction { + return .{ .branch_exception_generating_system = .{ .exception_generating = .{ + .dcps3 = .{ .imm16 = imm }, + } } }; + } + /// C6.2.116 DSB + pub fn dsb(option: BranchExceptionGeneratingSystem.Barriers.Option) Instruction { + return .{ .branch_exception_generating_system = .{ .barriers = .{ + .dsb = .{ + .CRm = option, + }, + } } }; + } + /// C6.2.118 EON (shifted register) + pub fn eon(d: Register, n: Register, form: union(enum) { + register: Register, + shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, + shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, + }) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf); + form: switch (form) { + .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, + .shifted_register_explicit => |shifted_register_explicit| { + assert(shifted_register_explicit.register.format.integer == sf); + return .{ .data_processing_register = .{ .logical_shifted_register = .{ + .eon = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm6 = switch (sf) { + .word => @as(u5, @intCast(shifted_register_explicit.amount)), + .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), + }, + .Rm = shifted_register_explicit.register.alias.encode(.{}), + .shift = shifted_register_explicit.shift, + .sf = sf, + }, + } } }; + }, + .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ + .register = shifted_register.register, + .shift = shifted_register.shift, + .amount = switch (shifted_register.shift) { + .lsl, .lsr, .asr, .ror => |amount| amount, + }, + } }, + } + } + /// C6.2.119 EOR (immediate) + /// C6.2.120 EOR (shifted register) + /// C7.2.41 EOR (vector) + pub fn eor(d: Register, n: Register, form: union(enum) { + immediate: DataProcessingImmediate.Bitmask, + register: Register, + shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, + shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, + }) Instruction { + switch (d.format) { + else => unreachable, + .integer => |sf| { + assert(n.format.integer == sf); + form: switch (form) { + .immediate => |bitmask| { + assert(bitmask.validImmediate(sf)); + return .{ .data_processing_immediate = .{ .logical_immediate = .{ + .eor = .{ + .Rd = d.alias.encode(.{ .sp = true }), + .Rn = n.alias.encode(.{}), + .imm = bitmask, + .sf = sf, + }, + } } }; + }, + .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, + .shifted_register_explicit => |shifted_register_explicit| { + assert(shifted_register_explicit.register.format.integer == sf); + return .{ .data_processing_register = .{ .logical_shifted_register = .{ + .eor = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm6 = switch (sf) { + .word => @as(u5, @intCast(shifted_register_explicit.amount)), + .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), + }, + .Rm = shifted_register_explicit.register.alias.encode(.{}), + .shift = shifted_register_explicit.shift, + .sf = sf, + }, + } } }; + }, + .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ + .register = shifted_register.register, + .shift = shifted_register.shift, + .amount = switch (shifted_register.shift) { + .lsl, .lsr, .asr, .ror => |amount| amount, + }, + } }, + } + }, + .vector => |arrangement| { + const m = form.register; + assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement); + return .{ .data_processing_vector = .{ .simd_three_same = .{ + .eor = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .Q = arrangement.size(), + }, + } } }; + }, + } + } + /// C6.2.124 EXTR + pub fn extr(d: Register, n: Register, m: Register, lsb: u6) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_immediate = .{ .extract = .{ + .extr = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imms = switch (sf) { + .word => @as(u5, @intCast(lsb)), + .doubleword => @as(u6, @intCast(lsb)), + }, + .Rm = m.alias.encode(.{}), + .N = sf, + .sf = sf, + }, + } } }; + } + /// C7.2.46 FABS (scalar) + pub fn fabs(d: Register, n: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ + .fabs = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.50 FADD (scalar) + pub fn fadd(d: Register, n: Register, m: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype and m.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ + .fadd = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.66 FCMP + pub fn fcmp(n: Register, form: union(enum) { register: Register, zero }) Instruction { + const ftype = n.format.scalar; + switch (form) { + .register => |m| { + assert(m.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_compare = .{ + .fcmp = .{ + .opc0 = .register, + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + }, + .zero => return .{ .data_processing_vector = .{ .float_compare = .{ + .fcmp = .{ + .opc0 = .register, + .Rn = n.alias.encode(.{ .V = true }), + .Rm = @enumFromInt(0b00000), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }, + } + } + /// C7.2.67 FCMPE + pub fn fcmpe(n: Register, form: union(enum) { register: Register, zero }) Instruction { + const ftype = n.format.scalar; + switch (form) { + .register => |m| { + assert(m.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_compare = .{ + .fcmpe = .{ + .opc0 = .zero, + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + }, + .zero => return .{ .data_processing_vector = .{ .float_compare = .{ + .fcmpe = .{ + .opc0 = .zero, + .Rn = n.alias.encode(.{ .V = true }), + .Rm = @enumFromInt(0b00000), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }, + } + } + /// C7.2.69 FCVT + pub fn fcvt(d: Register, n: Register) Instruction { + assert(d.format.scalar != n.format.scalar); + return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ + .fcvt = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .opc = switch (d.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .ftype = switch (n.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.71 FCVTAS (scalar) + pub fn fcvtas(d: Register, n: Register) Instruction { + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fcvtas = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (n.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = d.format.integer, + }, + } } }; + } + /// C7.2.73 FCVTAU (scalar) + pub fn fcvtau(d: Register, n: Register) Instruction { + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fcvtau = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (n.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = d.format.integer, + }, + } } }; + } + /// C7.2.76 FCVTMS (scalar) + pub fn fcvtms(d: Register, n: Register) Instruction { + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fcvtms = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (n.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = d.format.integer, + }, + } } }; + } + /// C7.2.78 FCVTMU (scalar) + pub fn fcvtmu(d: Register, n: Register) Instruction { + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fcvtmu = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (n.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = d.format.integer, + }, + } } }; + } + /// C7.2.81 FCVTNS (scalar) + pub fn fcvtns(d: Register, n: Register) Instruction { + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fcvtns = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (n.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = d.format.integer, + }, + } } }; + } + /// C7.2.83 FCVTNU (scalar) + pub fn fcvtnu(d: Register, n: Register) Instruction { + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fcvtnu = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (n.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = d.format.integer, + }, + } } }; + } + /// C7.2.85 FCVTPS (scalar) + pub fn fcvtps(d: Register, n: Register) Instruction { + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fcvtps = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (n.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = d.format.integer, + }, + } } }; + } + /// C7.2.87 FCVTPU (scalar) + pub fn fcvtpu(d: Register, n: Register) Instruction { + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fcvtpu = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (n.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = d.format.integer, + }, + } } }; + } + /// C7.2.92 FCVTZS (scalar, integer) + pub fn fcvtzs(d: Register, n: Register) Instruction { + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fcvtzs = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (n.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = d.format.integer, + }, + } } }; + } + /// C7.2.96 FCVTZU (scalar, integer) + pub fn fcvtzu(d: Register, n: Register) Instruction { + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fcvtzu = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (n.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = d.format.integer, + }, + } } }; + } + /// C7.2.98 FDIV (scalar) + pub fn fdiv(d: Register, n: Register, m: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype and m.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ + .fdiv = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.99 FJCVTZS + pub fn fjcvtzs(d: Register, n: Register) Instruction { + assert(d.format.integer == .word); + assert(n.format.scalar == .double); + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fjcvtzs = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + }, + } } }; + } + /// C7.2.100 FMADD + pub fn fmadd(d: Register, n: Register, m: Register, a: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{ + .fmadd = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .Ra = a.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.102 FMAX (scalar) + pub fn fmax(d: Register, n: Register, m: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype and m.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ + .fmax = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.104 FMAXNM (scalar) + pub fn fmaxnm(d: Register, n: Register, m: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype and m.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ + .fmaxnm = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.112 FMIN (scalar) + pub fn fmin(d: Register, n: Register, m: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype and m.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ + .fmin = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.114 FMINNM (scalar) + pub fn fminnm(d: Register, n: Register, m: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype and m.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ + .fminnm = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.129 FMOV (vector, immediate) + /// C7.2.130 FMOV (register) + /// C7.2.131 FMOV (general) + /// C7.2.132 FMOV (scalar, immediate) + pub fn fmov(d: Register, form: union(enum) { immediate: f16, register: Register }) Instruction { + switch (form) { + .immediate => |immediate| { + const repr: std.math.FloatRepr(f16) = @bitCast(immediate); + const imm: u8 = @bitCast(@as(packed struct(u8) { + mantissa: u4, + exponent: i3, + sign: std.math.Sign, + }, .{ + .mantissa = @intCast(@shrExact(repr.mantissa, 6)), + .exponent = @intCast(repr.exponent.unbias() - 1), + .sign = repr.sign, + })); + switch (d.format) { + else => unreachable, + .scalar => |ftype| return .{ .data_processing_vector = .{ .float_immediate = .{ + .fmov = .{ + .Rd = d.alias.encode(.{ .V = true }), + .imm8 = imm, + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }, + .vector => |arrangement| { + assert(arrangement.len() > 1 and arrangement.elemSize() != .byte); + return .{ .data_processing_vector = .{ .simd_modified_immediate = .{ + .fmov = .{ + .Rd = d.alias.encode(.{ .V = true }), + .imm5 = @truncate(imm >> 0), + .imm3 = @intCast(imm >> 5), + .Q = arrangement.size(), + }, + } } }; + }, + } + }, + .register => |n| switch (d.format) { + else => unreachable, + .integer => |sf| switch (n.format) { + else => unreachable, + .scalar => |ftype| { + switch (ftype) { + else => unreachable, + .half => {}, + .single => assert(sf == .word), + .double => assert(sf == .doubleword), + } + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fmov = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .opcode = .float_to_integer, + .rmode = .@"0", + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = sf, + }, + } } }; + }, + .element => |element| return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fmov = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .opcode = .float_to_integer, + .rmode = switch (element.index) { + else => unreachable, + 1 => .@"1", + }, + .ftype = switch (element.size) { + else => unreachable, + .double => .quad, + }, + .sf = sf, + }, + } } }, + }, + .scalar => |ftype| switch (n.format) { + else => unreachable, + .integer => { + const sf = n.format.integer; + switch (ftype) { + else => unreachable, + .half => {}, + .single => assert(sf == .word), + .double => assert(sf == .doubleword), + } + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fmov = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{}), + .opcode = .integer_to_float, + .rmode = .@"0", + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = sf, + }, + } } }; + }, + .scalar => { + assert(n.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ + .fmov = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + }, + }, + .element => |element| switch (n.format) { + else => unreachable, + .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .fmov = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{}), + .opcode = .integer_to_float, + .rmode = switch (element.index) { + else => unreachable, + 1 => .@"1", + }, + .ftype = switch (element.size) { + else => unreachable, + .double => .quad, + }, + .sf = sf, + }, + } } }, + }, + }, + } + } + /// C7.2.133 FMSUB + pub fn fmsub(d: Register, n: Register, m: Register, a: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{ + .fmsub = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .Ra = a.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.136 FMUL (scalar) + pub fn fmul(d: Register, n: Register, m: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype and m.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ + .fmul = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.140 FNEG (scalar) + pub fn fneg(d: Register, n: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ + .fneg = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.141 FNMADD + pub fn fnmadd(d: Register, n: Register, m: Register, a: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{ + .fnmadd = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .Ra = a.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.142 FNMSUB + pub fn fnmsub(d: Register, n: Register, m: Register, a: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{ + .fnmsub = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .Ra = a.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.143 FNMUL (scalar) + pub fn fnmul(d: Register, n: Register, m: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype and m.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ + .fnmul = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.156 FRINTA (scalar) + pub fn frinta(d: Register, n: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ + .frinta = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.158 FRINTI (scalar) + pub fn frinti(d: Register, n: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ + .frinti = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.160 FRINTM (scalar) + pub fn frintm(d: Register, n: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ + .frintm = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.162 FRINTN (scalar) + pub fn frintn(d: Register, n: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ + .frintn = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.164 FRINTP (scalar) + pub fn frintp(d: Register, n: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ + .frintp = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.166 FRINTX (scalar) + pub fn frintx(d: Register, n: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ + .frintx = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.168 FRINTZ (scalar) + pub fn frintz(d: Register, n: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ + .frintz = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.172 FSQRT (scalar) + pub fn fsqrt(d: Register, n: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ + .fsqrt = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C7.2.174 FSUB (scalar) + pub fn fsub(d: Register, n: Register, m: Register) Instruction { + const ftype = d.format.scalar; + assert(n.format.scalar == ftype and m.format.scalar == ftype); + return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ + .fsub = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .ftype = switch (ftype) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + }, + } } }; + } + /// C6.2.126 HINT + pub fn hint(imm: u7) Instruction { + return .{ .branch_exception_generating_system = .{ .hints = .{ + .group = .{ + .op2 = @truncate(imm >> 0), + .CRm = @intCast(imm >> 3), + }, + } } }; + } + /// C6.2.127 HLT + pub fn hlt(imm: u16) Instruction { + return .{ .branch_exception_generating_system = .{ .exception_generating = .{ + .hlt = .{ .imm16 = imm }, + } } }; + } + /// C6.2.128 HVC + pub fn hvc(imm: u16) Instruction { + return .{ .branch_exception_generating_system = .{ .exception_generating = .{ + .hvc = .{ .imm16 = imm }, + } } }; + } + /// C6.2.131 ISB + pub fn isb(option: BranchExceptionGeneratingSystem.Barriers.Option) Instruction { + return .{ .branch_exception_generating_system = .{ .barriers = .{ + .isb = .{ + .CRm = option, + }, + } } }; + } + /// C6.2.164 LDP + /// C7.2.190 LDP (SIMD&FP) + pub fn ldp(t1: Register, t2: Register, form: union(enum) { + post_index: struct { base: Register, index: i10 }, + pre_index: struct { base: Register, index: i10 }, + signed_offset: struct { base: Register, offset: i10 = 0 }, + base: Register, + }) Instruction { + switch (t1.format) { + else => unreachable, + .integer => |sf| { + assert(t2.format.integer == sf); + form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_post_indexed = .{ .integer = .{ + .ldp = .{ + .Rt = t1.alias.encode(.{}), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .Rt2 = t2.alias.encode(.{}), + .imm7 = @intCast(@shrExact(post_index.index, @as(u2, 2) + @intFromEnum(sf))), + .sf = sf, + }, + } } } }; + }, + .signed_offset => |signed_offset| { + assert(signed_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{ + .ldp = .{ + .Rt = t1.alias.encode(.{}), + .Rn = signed_offset.base.alias.encode(.{ .sp = true }), + .Rt2 = t2.alias.encode(.{}), + .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))), + .sf = sf, + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{ + .ldp = .{ + .Rt = t1.alias.encode(.{}), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .Rt2 = t2.alias.encode(.{}), + .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))), + .sf = sf, + }, + } } } }; + }, + .base => |base| continue :form .{ .signed_offset = .{ .base = base } }, + } + }, + .scalar => |vs| { + assert(t2.format.scalar == vs); + form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_post_indexed = .{ .vector = .{ + .ldp = .{ + .Rt = t1.alias.encode(.{ .V = true }), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .Rt2 = t2.alias.encode(.{ .V = true }), + .imm7 = @intCast(@shrExact(post_index.index, @intFromEnum(vs))), + .opc = .encode(vs), + }, + } } } }; + }, + .signed_offset => |signed_offset| { + assert(signed_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_offset = .{ .vector = .{ + .ldp = .{ + .Rt = t1.alias.encode(.{ .V = true }), + .Rn = signed_offset.base.alias.encode(.{ .sp = true }), + .Rt2 = t2.alias.encode(.{ .V = true }), + .imm7 = @intCast(@shrExact(signed_offset.offset, @intFromEnum(vs))), + .opc = .encode(vs), + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_pre_indexed = .{ .vector = .{ + .ldp = .{ + .Rt = t1.alias.encode(.{ .V = true }), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .Rt2 = t2.alias.encode(.{ .V = true }), + .imm7 = @intCast(@shrExact(pre_index.index, @intFromEnum(vs))), + .opc = .encode(vs), + }, + } } } }; + }, + .base => |base| continue :form .{ .signed_offset = .{ .base = base } }, + } + }, + } + } + /// C6.2.166 LDR (immediate) + /// C6.2.167 LDR (literal) + /// C6.2.168 LDR (register) + /// C7.2.191 LDR (immediate, SIMD&FP) + /// C7.2.192 LDR (literal, SIMD&FP) + /// C7.2.193 LDR (register, SIMD&FP) + pub fn ldr(t: Register, form: union(enum) { + post_index: struct { base: Register, index: i9 }, + pre_index: struct { base: Register, index: i9 }, + unsigned_offset: struct { base: Register, offset: u16 = 0 }, + base: Register, + literal: i21, + extended_register_explicit: struct { + base: Register, + index: Register, + option: LoadStore.RegisterRegisterOffset.Option, + amount: LoadStore.RegisterRegisterOffset.Extend.Amount, + }, + extended_register: struct { + base: Register, + index: Register, + extend: LoadStore.RegisterRegisterOffset.Extend, + }, + }) Instruction { + switch (t.format) { + else => unreachable, + .integer => |sf| form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ + .ldr = .{ + .Rt = t.alias.encode(.{}), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .imm9 = post_index.index, + .sf = sf, + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ + .ldr = .{ + .Rt = t.alias.encode(.{}), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .imm9 = pre_index.index, + .sf = sf, + }, + } } } }; + }, + .unsigned_offset => |unsigned_offset| { + assert(unsigned_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ + .ldr = .{ + .Rt = t.alias.encode(.{}), + .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), + .imm12 = @intCast(@shrExact(unsigned_offset.offset, @as(u2, 2) + @intFromEnum(sf))), + .sf = sf, + }, + } } } }; + }, + .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, + .literal => |offset| return .{ .load_store = .{ .register_literal = .{ .integer = .{ + .ldr = .{ + .Rt = t.alias.encode(.{}), + .imm19 = @intCast(@shrExact(offset, 2)), + .sf = sf, + }, + } } } }, + .extended_register_explicit => |extended_register_explicit| { + assert(extended_register_explicit.base.format.integer == .doubleword and + extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); + return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ + .ldr = .{ + .Rt = t.alias.encode(.{}), + .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), + .S = switch (sf) { + .word => switch (extended_register_explicit.amount) { + 0 => false, + 2 => true, + else => unreachable, + }, + .doubleword => switch (extended_register_explicit.amount) { + 0 => false, + 3 => true, + else => unreachable, + }, + }, + .option = extended_register_explicit.option, + .Rm = extended_register_explicit.index.alias.encode(.{}), + .sf = sf, + }, + } } } }; + }, + .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ + .base = extended_register.base, + .index = extended_register.index, + .option = extended_register.extend, + .amount = switch (extended_register.extend) { + .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, + }, + } }, + }, + .scalar => |vs| form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_post_indexed = .{ .vector = .{ + .ldr = .{ + .Rt = t.alias.encode(.{ .V = true }), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .imm9 = post_index.index, + .opc1 = .encode(vs), + .size = .encode(vs), + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .vector = .{ + .ldr = .{ + .Rt = t.alias.encode(.{ .V = true }), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .imm9 = pre_index.index, + .opc1 = .encode(vs), + .size = .encode(vs), + }, + } } } }; + }, + .unsigned_offset => |unsigned_offset| { + assert(unsigned_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_unsigned_immediate = .{ .vector = .{ + .ldr = .{ + .Rt = t.alias.encode(.{ .V = true }), + .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), + .imm12 = @intCast(@shrExact(unsigned_offset.offset, @intFromEnum(vs))), + .opc1 = .encode(vs), + .size = .encode(vs), + }, + } } } }; + }, + .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, + .literal => |offset| return .{ .load_store = .{ .register_literal = .{ .vector = .{ + .ldr = .{ + .Rt = t.alias.encode(.{ .V = true }), + .imm19 = @intCast(@shrExact(offset, 2)), + .opc = .encode(vs), + }, + } } } }, + .extended_register_explicit => |extended_register_explicit| { + assert(extended_register_explicit.base.format.integer == .doubleword and + extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); + return .{ .load_store = .{ .register_register_offset = .{ .vector = .{ + .ldr = .{ + .Rt = t.alias.encode(.{ .V = true }), + .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), + .S = switch (vs) { + else => unreachable, + .byte => switch (extended_register_explicit.amount) { + 0 => false, + else => unreachable, + }, + .half => switch (extended_register_explicit.amount) { + 0 => false, + 1 => true, + else => unreachable, + }, + .single => switch (extended_register_explicit.amount) { + 0 => false, + 2 => true, + else => unreachable, + }, + .double => switch (extended_register_explicit.amount) { + 0 => false, + 3 => true, + else => unreachable, + }, + .quad => switch (extended_register_explicit.amount) { + 0 => false, + 4 => true, + else => unreachable, + }, + }, + .option = extended_register_explicit.option, + .Rm = extended_register_explicit.index.alias.encode(.{}), + .opc1 = .encode(vs), + .size = .encode(vs), + }, + } } } }; + }, + .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ + .base = extended_register.base, + .index = extended_register.index, + .option = extended_register.extend, + .amount = switch (extended_register.extend) { + .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, + }, + } }, + }, + } + } + /// C6.2.170 LDRB (immediate) + /// C6.2.171 LDRB (register) + pub fn ldrb(t: Register, form: union(enum) { + post_index: struct { base: Register, index: i9 }, + pre_index: struct { base: Register, index: i9 }, + unsigned_offset: struct { base: Register, offset: u12 = 0 }, + base: Register, + extended_register_explicit: struct { + base: Register, + index: Register, + option: LoadStore.RegisterRegisterOffset.Option, + amount: LoadStore.RegisterRegisterOffset.Extend.Amount, + }, + extended_register: struct { + base: Register, + index: Register, + extend: LoadStore.RegisterRegisterOffset.Extend, + }, + }) Instruction { + assert(t.format.integer == .word); + form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ + .ldrb = .{ + .Rt = t.alias.encode(.{}), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .imm9 = post_index.index, + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ + .ldrb = .{ + .Rt = t.alias.encode(.{}), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .imm9 = pre_index.index, + }, + } } } }; + }, + .unsigned_offset => |unsigned_offset| { + assert(unsigned_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ + .ldrb = .{ + .Rt = t.alias.encode(.{}), + .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), + .imm12 = unsigned_offset.offset, + }, + } } } }; + }, + .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, + .extended_register_explicit => |extended_register_explicit| { + assert(extended_register_explicit.base.format.integer == .doubleword and + extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); + return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ + .ldrb = .{ + .Rt = t.alias.encode(.{}), + .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), + .S = switch (extended_register_explicit.amount) { + 0 => false, + else => unreachable, + }, + .option = extended_register_explicit.option, + .Rm = extended_register_explicit.index.alias.encode(.{}), + }, + } } } }; + }, + .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ + .base = extended_register.base, + .index = extended_register.index, + .option = extended_register.extend, + .amount = switch (extended_register.extend) { + .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, + }, + } }, + } + } + /// C6.2.172 LDRH (immediate) + /// C6.2.173 LDRH (register) + pub fn ldrh(t: Register, form: union(enum) { + post_index: struct { base: Register, index: i9 }, + pre_index: struct { base: Register, index: i9 }, + unsigned_offset: struct { base: Register, offset: u13 = 0 }, + base: Register, + extended_register_explicit: struct { + base: Register, + index: Register, + option: LoadStore.RegisterRegisterOffset.Option, + amount: LoadStore.RegisterRegisterOffset.Extend.Amount, + }, + extended_register: struct { + base: Register, + index: Register, + extend: LoadStore.RegisterRegisterOffset.Extend, + }, + }) Instruction { + assert(t.format.integer == .word); + form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ + .ldrh = .{ + .Rt = t.alias.encode(.{}), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .imm9 = post_index.index, + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ + .ldrh = .{ + .Rt = t.alias.encode(.{}), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .imm9 = pre_index.index, + }, + } } } }; + }, + .unsigned_offset => |unsigned_offset| { + assert(unsigned_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ + .ldrh = .{ + .Rt = t.alias.encode(.{}), + .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), + .imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)), + }, + } } } }; + }, + .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, + .extended_register_explicit => |extended_register_explicit| { + assert(extended_register_explicit.base.format.integer == .doubleword and + extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); + return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ + .ldrh = .{ + .Rt = t.alias.encode(.{}), + .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), + .S = switch (extended_register_explicit.amount) { + 0 => false, + 1 => true, + else => unreachable, + }, + .option = extended_register_explicit.option, + .Rm = extended_register_explicit.index.alias.encode(.{}), + }, + } } } }; + }, + .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ + .base = extended_register.base, + .index = extended_register.index, + .option = extended_register.extend, + .amount = switch (extended_register.extend) { + .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, + }, + } }, + } + } + /// C6.2.174 LDRSB (immediate) + /// C6.2.175 LDRSB (register) + pub fn ldrsb(t: Register, form: union(enum) { + post_index: struct { base: Register, index: i9 }, + pre_index: struct { base: Register, index: i9 }, + unsigned_offset: struct { base: Register, offset: u12 = 0 }, + base: Register, + extended_register_explicit: struct { + base: Register, + index: Register, + option: LoadStore.RegisterRegisterOffset.Option, + amount: LoadStore.RegisterRegisterOffset.Extend.Amount, + }, + extended_register: struct { + base: Register, + index: Register, + extend: LoadStore.RegisterRegisterOffset.Extend, + }, + }) Instruction { + const sf = t.format.integer; + form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ + .ldrsb = .{ + .Rt = t.alias.encode(.{}), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .imm9 = post_index.index, + .opc0 = ~@intFromEnum(sf), + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ + .ldrsb = .{ + .Rt = t.alias.encode(.{}), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .imm9 = pre_index.index, + .opc0 = ~@intFromEnum(sf), + }, + } } } }; + }, + .unsigned_offset => |unsigned_offset| { + assert(unsigned_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ + .ldrsb = .{ + .Rt = t.alias.encode(.{}), + .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), + .imm12 = unsigned_offset.offset, + .opc0 = ~@intFromEnum(sf), + }, + } } } }; + }, + .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, + .extended_register_explicit => |extended_register_explicit| { + assert(extended_register_explicit.base.format.integer == .doubleword and + extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); + return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ + .ldrsb = .{ + .Rt = t.alias.encode(.{}), + .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), + .S = switch (extended_register_explicit.amount) { + 0 => false, + else => unreachable, + }, + .option = extended_register_explicit.option, + .Rm = extended_register_explicit.index.alias.encode(.{}), + .opc0 = ~@intFromEnum(sf), + }, + } } } }; + }, + .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ + .base = extended_register.base, + .index = extended_register.index, + .option = extended_register.extend, + .amount = switch (extended_register.extend) { + .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, + }, + } }, + } + } + /// C6.2.176 LDRSH (immediate) + /// C6.2.177 LDRSH (register) + pub fn ldrsh(t: Register, form: union(enum) { + post_index: struct { base: Register, index: i9 }, + pre_index: struct { base: Register, index: i9 }, + unsigned_offset: struct { base: Register, offset: u13 = 0 }, + base: Register, + extended_register_explicit: struct { + base: Register, + index: Register, + option: LoadStore.RegisterRegisterOffset.Option, + amount: LoadStore.RegisterRegisterOffset.Extend.Amount, + }, + extended_register: struct { + base: Register, + index: Register, + extend: LoadStore.RegisterRegisterOffset.Extend, + }, + }) Instruction { + const sf = t.format.integer; + form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ + .ldrsh = .{ + .Rt = t.alias.encode(.{}), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .imm9 = post_index.index, + .opc0 = ~@intFromEnum(sf), + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ + .ldrsh = .{ + .Rt = t.alias.encode(.{}), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .imm9 = pre_index.index, + .opc0 = ~@intFromEnum(sf), + }, + } } } }; + }, + .unsigned_offset => |unsigned_offset| { + assert(unsigned_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ + .ldrsh = .{ + .Rt = t.alias.encode(.{}), + .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), + .imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)), + .opc0 = ~@intFromEnum(sf), + }, + } } } }; + }, + .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, + .extended_register_explicit => |extended_register_explicit| { + assert(extended_register_explicit.base.format.integer == .doubleword and + extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); + return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ + .ldrsh = .{ + .Rt = t.alias.encode(.{}), + .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), + .S = switch (extended_register_explicit.amount) { + 0 => false, + 1 => true, + else => unreachable, + }, + .option = extended_register_explicit.option, + .Rm = extended_register_explicit.index.alias.encode(.{}), + .opc0 = ~@intFromEnum(sf), + }, + } } } }; + }, + .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ + .base = extended_register.base, + .index = extended_register.index, + .option = extended_register.extend, + .amount = switch (extended_register.extend) { + .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, + }, + } }, + } + } + /// C6.2.178 LDRSW (immediate) + /// C6.2.179 LDRSW (literal) + /// C6.2.180 LDRSW (register) + pub fn ldrsw(t: Register, form: union(enum) { + post_index: struct { base: Register, index: i9 }, + pre_index: struct { base: Register, index: i9 }, + unsigned_offset: struct { base: Register, offset: u14 = 0 }, + base: Register, + literal: i21, + extended_register_explicit: struct { + base: Register, + index: Register, + option: LoadStore.RegisterRegisterOffset.Integer.Option, + amount: LoadStore.RegisterRegisterOffset.Integer.Extend.Amount, + }, + extended_register: struct { + base: Register, + index: Register, + extend: LoadStore.RegisterRegisterOffset.Integer.Extend, + }, + }) Instruction { + assert(t.format.integer == .doubleword); + form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_post_indexed = .{ + .ldrsw = .{ + .Rt = t.alias.encode(.{}), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .imm9 = post_index.index, + }, + } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ + .ldrsw = .{ + .Rt = t.alias.encode(.{}), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .imm9 = pre_index.index, + }, + } } } }; + }, + .unsigned_offset => |unsigned_offset| { + assert(unsigned_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_unsigned_immediate = .{ + .ldrsw = .{ + .Rt = t.alias.encode(.{}), + .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), + .imm12 = @intCast(@shrExact(unsigned_offset.offset, 2)), + }, + } } }; + }, + .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, + .literal => |offset| return .{ .load_store = .{ .register_literal = .{ + .ldrsw = .{ + .Rt = t.alias.encode(.{}), + .imm19 = @intCast(@shrExact(offset, 2)), + }, + } } }, + .extended_register_explicit => |extended_register_explicit| { + assert(extended_register_explicit.base.format.integer == .doubleword and + extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); + return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ + .ldrsw = .{ + .Rt = t.alias.encode(.{}), + .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), + .S = switch (extended_register_explicit.amount) { + 0 => 0b0, + 2 => 0b1, + else => unreachable, + }, + .option = extended_register_explicit.option, + .Rm = extended_register_explicit.index.alias.encode(.{}), + }, + } } } }; + }, + .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ + .base = extended_register.base, + .index = extended_register.index, + .option = extended_register.extend, + .amount = switch (extended_register.extend) { + .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, + }, + } }, + } + } + /// C6.2.202 LDUR + /// C7.2.194 LDUR (SIMD&FP) + pub fn ldur(t: Register, n: Register, simm: i9) Instruction { + assert(n.format.integer == .doubleword); + switch (t.format) { + else => unreachable, + .integer => |sf| return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ + .ldur = .{ + .Rt = t.alias.encode(.{}), + .Rn = n.alias.encode(.{ .sp = true }), + .imm9 = simm, + .sf = sf, + }, + } } } }, + .scalar => |vs| return .{ .load_store = .{ .register_unscaled_immediate = .{ .vector = .{ + .ldur = .{ + .Rt = t.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .sp = true }), + .imm9 = simm, + .opc1 = .encode(vs), + .size = .encode(vs), + }, + } } } }, + } + } + /// C6.2.203 LDURB + pub fn ldurb(t: Register, n: Register, simm: i9) Instruction { + assert(t.format.integer == .word and n.format.integer == .doubleword); + return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ + .ldurb = .{ + .Rt = t.alias.encode(.{}), + .Rn = n.alias.encode(.{ .sp = true }), + .imm9 = simm, + }, + } } } }; + } + /// C6.2.204 LDURH + pub fn ldurh(t: Register, n: Register, simm: i9) Instruction { + assert(t.format.integer == .word and n.format.integer == .doubleword); + return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ + .ldurh = .{ + .Rt = t.alias.encode(.{}), + .Rn = n.alias.encode(.{ .sp = true }), + .imm9 = simm, + }, + } } } }; + } + /// C6.2.205 LDURSB + pub fn ldursb(t: Register, n: Register, simm: i9) Instruction { + assert(n.format.integer == .doubleword); + return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ + .ldursb = .{ + .Rt = t.alias.encode(.{}), + .Rn = n.alias.encode(.{ .sp = true }), + .imm9 = simm, + .opc0 = ~@intFromEnum(t.format.integer), + }, + } } } }; + } + /// C6.2.206 LDURSH + pub fn ldursh(t: Register, n: Register, simm: i9) Instruction { + assert(n.format.integer == .doubleword); + return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ + .ldursh = .{ + .Rt = t.alias.encode(.{}), + .Rn = n.alias.encode(.{ .sp = true }), + .imm9 = simm, + .opc0 = ~@intFromEnum(t.format.integer), + }, + } } } }; + } + /// C6.2.207 LDURSW + pub fn ldursw(t: Register, n: Register, simm: i9) Instruction { + assert(t.format.integer == .doubleword and n.format.integer == .doubleword); + return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ + .ldursw = .{ + .Rt = t.alias.encode(.{}), + .Rn = n.alias.encode(.{ .sp = true }), + .imm9 = simm, + }, + } } } }; + } + /// C6.2.214 LSLV + pub fn lslv(d: Register, n: Register, m: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .data_processing_two_source = .{ + .lslv = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.217 LSRV + pub fn lsrv(d: Register, n: Register, m: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .data_processing_two_source = .{ + .lsrv = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.218 MADD + pub fn madd(d: Register, n: Register, m: Register, a: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf and a.format.integer == sf); + return .{ .data_processing_register = .{ .data_processing_three_source = .{ + .madd = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Ra = a.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C7.2.204 MOVI + pub fn movi(d: Register, imm8: u8, shift: union(enum) { lsl: u5, msl: u5, replicate }) Instruction { + const arrangement = switch (d.format) { + else => unreachable, + .scalar => |vs| switch (vs) { + else => unreachable, + .double => .@"1d", + }, + .vector => |arrangement| switch (arrangement) { + .@"1d" => unreachable, + else => arrangement, + }, + }; + return .{ .data_processing_vector = .{ .simd_modified_immediate = .{ + .movi = .{ + .Rd = d.alias.encode(.{ .V = true }), + .imm5 = @truncate(imm8 >> 0), + .cmode = switch (shift) { + .lsl => |amount| switch (arrangement) { + else => unreachable, + .@"8b", .@"16b" => @as(u4, 0b1110) | + @as(u4, @as(u0, @intCast(@shrExact(amount, 3)))) << 1, + .@"4h", .@"8h" => @as(u4, 0b1000) | + @as(u4, @as(u1, @intCast(@shrExact(amount, 3)))) << 1, + .@"2s", .@"4s" => @as(u4, 0b0000) | + @as(u4, @as(u2, @intCast(@shrExact(amount, 3)))) << 1, + }, + .msl => |amount| switch (arrangement) { + else => unreachable, + .@"2s", .@"4s" => @as(u4, 0b1100) | + @as(u4, @as(u1, @intCast(@shrExact(amount, 3) - 1))) << 0, + }, + .replicate => switch (arrangement) { + else => unreachable, + .@"1d", .@"2d" => 0b1110, + }, + }, + .imm3 = @intCast(imm8 >> 5), + .op = switch (shift) { + .lsl, .msl => 0b0, + .replicate => 0b1, + }, + .Q = arrangement.size(), + }, + } } }; + } + /// C6.2.225 MOVK + pub fn movk( + d: Register, + imm: u16, + shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" }, + ) Instruction { + const sf = d.format.integer; + assert(sf == .doubleword or shift.lsl.sf() == .word); + return .{ .data_processing_immediate = .{ .move_wide_immediate = .{ + .movk = .{ + .Rd = d.alias.encode(.{}), + .imm16 = imm, + .hw = shift.lsl, + .sf = sf, + }, + } } }; + } + /// C6.2.226 MOVN + pub fn movn( + d: Register, + imm: u16, + shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" }, + ) Instruction { + const sf = d.format.integer; + assert(sf == .doubleword or shift.lsl.sf() == .word); + return .{ .data_processing_immediate = .{ .move_wide_immediate = .{ + .movn = .{ + .Rd = d.alias.encode(.{}), + .imm16 = imm, + .hw = shift.lsl, + .sf = sf, + }, + } } }; + } + /// C6.2.227 MOVZ + pub fn movz( + d: Register, + imm: u16, + shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" }, + ) Instruction { + const sf = d.format.integer; + assert(sf == .doubleword or shift.lsl.sf() == .word); + return .{ .data_processing_immediate = .{ .move_wide_immediate = .{ + .movz = .{ + .Rd = d.alias.encode(.{}), + .imm16 = imm, + .hw = shift.lsl, + .sf = sf, + }, + } } }; + } + /// C6.2.228 MRS + pub fn mrs(t: Register, op0: u2, op1: u3, n: u4, m: u4, op2: u3) Instruction { + assert(t.format.integer == .doubleword); + return .{ .branch_exception_generating_system = .{ .system_register_move = .{ + .mrs = .{ + .Rt = t.alias.encode(.{}), + .op2 = op2, + .CRm = m, + .CRn = n, + .op1 = op1, + .o0 = @intCast(op0 - 0b10), + }, + } } }; + } + /// C6.2.230 MSR (register) + pub fn msr(op0: u2, op1: u3, n: u4, m: u4, op2: u3, t: Register) Instruction { + assert(t.format.integer == .doubleword); + return .{ .branch_exception_generating_system = .{ .system_register_move = .{ + .msr = .{ + .Rt = t.alias.encode(.{}), + .op2 = op2, + .CRm = m, + .CRn = n, + .op1 = op1, + .o0 = @intCast(op0 - 0b10), + }, + } } }; + } + /// C6.2.231 MSUB + pub fn msub(d: Register, n: Register, m: Register, a: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf and a.format.integer == sf); + return .{ .data_processing_register = .{ .data_processing_three_source = .{ + .msub = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Ra = a.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.238 NOP + pub fn nop() Instruction { + return .{ .branch_exception_generating_system = .{ .hints = .{ + .nop = .{}, + } } }; + } + /// C6.2.239 ORN (shifted register) + /// C7.2.211 ORN (vector) + pub fn orn(d: Register, n: Register, form: union(enum) { + register: Register, + shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, + shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, + }) Instruction { + switch (d.format) { + else => unreachable, + .integer => |sf| { + assert(n.format.integer == sf); + form: switch (form) { + .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, + .shifted_register_explicit => |shifted_register_explicit| { + assert(shifted_register_explicit.register.format.integer == sf); + return .{ .data_processing_register = .{ .logical_shifted_register = .{ + .orn = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm6 = switch (sf) { + .word => @as(u5, @intCast(shifted_register_explicit.amount)), + .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), + }, + .Rm = shifted_register_explicit.register.alias.encode(.{}), + .shift = shifted_register_explicit.shift, + .sf = sf, + }, + } } }; + }, + .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ + .register = shifted_register.register, + .shift = shifted_register.shift, + .amount = switch (shifted_register.shift) { + .lsl, .lsr, .asr, .ror => |amount| amount, + }, + } }, + } + }, + .vector => |arrangement| { + const m = form.register; + assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement); + return .{ .data_processing_vector = .{ .simd_three_same = .{ + .orn = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .Q = arrangement.size(), + }, + } } }; + }, + } + } + /// C6.2.240 ORR (immediate) + /// C6.2.241 ORR (shifted register) + /// C7.2.212 ORR (vector, immediate) + /// C7.2.213 ORR (vector, register) + pub fn orr(d: Register, n: Register, form: union(enum) { + immediate: DataProcessingImmediate.Bitmask, + shifted_immediate: struct { immediate: u8, lsl: u5 = 0 }, + register: Register, + shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, + shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, + }) Instruction { + switch (d.format) { + else => unreachable, + .integer => |sf| { + assert(n.format.integer == sf); + form: switch (form) { + .immediate => |bitmask| { + assert(bitmask.validImmediate(sf)); + return .{ .data_processing_immediate = .{ .logical_immediate = .{ + .orr = .{ + .Rd = d.alias.encode(.{ .sp = true }), + .Rn = n.alias.encode(.{}), + .imm = bitmask, + .sf = sf, + }, + } } }; + }, + .shifted_immediate => unreachable, + .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, + .shifted_register_explicit => |shifted_register_explicit| { + assert(shifted_register_explicit.register.format.integer == sf); + return .{ .data_processing_register = .{ .logical_shifted_register = .{ + .orr = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm6 = switch (sf) { + .word => @as(u5, @intCast(shifted_register_explicit.amount)), + .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), + }, + .Rm = shifted_register_explicit.register.alias.encode(.{}), + .shift = shifted_register_explicit.shift, + .sf = sf, + }, + } } }; + }, + .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ + .register = shifted_register.register, + .shift = shifted_register.shift, + .amount = switch (shifted_register.shift) { + .lsl, .lsr, .asr, .ror => |amount| amount, + }, + } }, + } + }, + .vector => |arrangement| switch (form) { + else => unreachable, + .shifted_immediate => |shifted_immediate| { + assert(n.alias == d.alias and n.format.vector == arrangement); + return .{ .data_processing_vector = .{ .simd_modified_immediate = .{ + .orr = .{ + .Rd = d.alias.encode(.{ .V = true }), + .imm5 = @truncate(shifted_immediate.immediate >> 0), + .cmode = switch (arrangement) { + else => unreachable, + .@"4h", .@"8h" => @as(u3, 0b100) | + @as(u3, @as(u1, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0, + .@"2s", .@"4s" => @as(u3, 0b000) | + @as(u3, @as(u2, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0, + }, + .imm3 = @intCast(shifted_immediate.immediate >> 5), + .Q = arrangement.size(), + }, + } } }; + }, + .register => |m| { + assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement); + return .{ .data_processing_vector = .{ .simd_three_same = .{ + .orr = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .V = true }), + .Rm = m.alias.encode(.{ .V = true }), + .Q = arrangement.size(), + }, + } } }; + }, + }, + } + } + /// C6.2.247 PRFM (immediate) + /// C6.2.248 PRFM (literal) + /// C6.2.249 PRFM (register) + pub fn prfm(prfop: LoadStore.PrfOp, form: union(enum) { + unsigned_offset: struct { base: Register, offset: u15 = 0 }, + base: Register, + literal: i21, + extended_register_explicit: struct { + base: Register, + index: Register, + option: LoadStore.RegisterRegisterOffset.Option, + amount: LoadStore.RegisterRegisterOffset.Extend.Amount, + }, + extended_register: struct { + base: Register, + index: Register, + extend: LoadStore.RegisterRegisterOffset.Extend, + }, + }) Instruction { + form: switch (form) { + .unsigned_offset => |unsigned_offset| { + assert(unsigned_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ + .prfm = .{ + .prfop = prfop, + .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), + .imm12 = @intCast(@shrExact(unsigned_offset.offset, 3)), + }, + } } } }; + }, + .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, + .literal => |offset| return .{ .load_store = .{ .register_literal = .{ .integer = .{ + .prfm = .{ + .prfop = prfop, + .imm19 = @intCast(@shrExact(offset, 2)), + }, + } } } }, + .extended_register_explicit => |extended_register_explicit| { + assert(extended_register_explicit.base.format.integer == .doubleword and + extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); + return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ + .prfm = .{ + .prfop = prfop, + .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), + .S = switch (extended_register_explicit.amount) { + 0 => false, + 3 => true, + else => unreachable, + }, + .option = extended_register_explicit.option, + .Rm = extended_register_explicit.index.alias.encode(.{}), + }, + } } } }; + }, + .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ + .base = extended_register.base, + .index = extended_register.index, + .option = extended_register.extend, + .amount = switch (extended_register.extend) { + .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, + }, + } }, + } + } + /// C6.2.253 RBIT + pub fn rbit(d: Register, n: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf); + return .{ .data_processing_register = .{ .data_processing_one_source = .{ + .rbit = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.254 RET + pub fn ret(n: Register) Instruction { + assert(n.format.integer == .doubleword); + return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{ + .ret = .{ .Rn = n.alias.encode(.{}) }, + } } }; + } + /// C6.2.256 REV + pub fn rev(d: Register, n: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf); + return .{ .data_processing_register = .{ .data_processing_one_source = .{ + .rev = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .opc0 = sf, + .sf = sf, + }, + } } }; + } + /// C6.2.257 REV16 + pub fn rev16(d: Register, n: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf); + return .{ .data_processing_register = .{ .data_processing_one_source = .{ + .rev16 = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.258 REV32 + pub fn rev32(d: Register, n: Register) Instruction { + assert(d.format.integer == .doubleword and n.format.integer == .doubleword); + return .{ .data_processing_register = .{ .data_processing_one_source = .{ + .rev32 = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + }, + } } }; + } + /// C6.2.263 RORV + pub fn rorv(d: Register, n: Register, m: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .data_processing_two_source = .{ + .rorv = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.264 SB + pub fn sb() Instruction { + return .{ .branch_exception_generating_system = .{ .barriers = .{ + .sb = .{}, + } } }; + } + /// C6.2.265 SBC + pub fn sbc(d: Register, n: Register, m: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .add_subtract_with_carry = .{ + .sbc = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.266 SBCS + pub fn sbcs(d: Register, n: Register, m: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .add_subtract_with_carry = .{ + .sbcs = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.268 SBFM + pub fn sbfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and bitmask.validBitfield(sf)); + return .{ .data_processing_immediate = .{ .bitfield = .{ + .sbfm = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm = bitmask, + .sf = sf, + }, + } } }; + } + /// C7.2.236 SCVTF (scalar, integer) + pub fn scvtf(d: Register, n: Register) Instruction { + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .scvtf = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{}), + .ftype = switch (d.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = n.format.integer, + }, + } } }; + } + /// C6.2.270 SDIV + pub fn sdiv(d: Register, n: Register, m: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .data_processing_two_source = .{ + .sdiv = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.280 SEV + pub fn sev() Instruction { + return .{ .branch_exception_generating_system = .{ .hints = .{ + .sev = .{}, + } } }; + } + /// C6.2.281 SEVL + pub fn sevl() Instruction { + return .{ .branch_exception_generating_system = .{ .hints = .{ + .sevl = .{}, + } } }; + } + /// C6.2.282 SMADDL + pub fn smaddl(d: Register, n: Register, m: Register, a: Register) Instruction { + assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword); + return .{ .data_processing_register = .{ .data_processing_three_source = .{ + .smaddl = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Ra = a.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + }, + } } }; + } + /// C6.2.283 SMC + pub fn smc(imm: u16) Instruction { + return .{ .branch_exception_generating_system = .{ .exception_generating = .{ + .smc = .{ .imm16 = imm }, + } } }; + } + /// C7.2.279 SMOV + pub fn smov(d: Register, n: Register) Instruction { + const sf = d.format.integer; + const vs = n.format.element.size; + switch (vs) { + else => unreachable, + .byte, .half => {}, + .single => assert(sf == .doubleword), + } + return .{ .data_processing_vector = .{ .simd_copy = .{ + .smov = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .imm5 = switch (vs) { + else => unreachable, + .byte => @as(u5, @as(u4, @intCast(n.format.element.index))) << 1 | @as(u5, 0b1) << 0, + .half => @as(u5, @as(u3, @intCast(n.format.element.index))) << 2 | @as(u5, 0b10) << 0, + .single => @as(u5, @as(u2, @intCast(n.format.element.index))) << 3 | @as(u5, 0b100) << 0, + }, + .Q = sf, + }, + } } }; + } + /// C6.2.287 SMSUBL + pub fn smsubl(d: Register, n: Register, m: Register, a: Register) Instruction { + assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword); + return .{ .data_processing_register = .{ .data_processing_three_source = .{ + .smsubl = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Ra = a.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + }, + } } }; + } + /// C6.2.288 SMULH + pub fn smulh(d: Register, n: Register, m: Register) Instruction { + assert(d.format.integer == .doubleword and n.format.integer == .doubleword and m.format.integer == .doubleword); + return .{ .data_processing_register = .{ .data_processing_three_source = .{ + .smulh = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + }, + } } }; + } + /// C6.2.321 STP + /// C7.2.330 STP (SIMD&FP) + pub fn stp(t1: Register, t2: Register, form: union(enum) { + post_index: struct { base: Register, index: i10 }, + pre_index: struct { base: Register, index: i10 }, + signed_offset: struct { base: Register, offset: i10 = 0 }, + base: Register, + }) Instruction { + switch (t1.format) { + else => unreachable, + .integer => |sf| { + assert(t2.format.integer == sf); + form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_post_indexed = .{ .integer = .{ + .stp = .{ + .Rt = t1.alias.encode(.{}), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .Rt2 = t2.alias.encode(.{}), + .imm7 = @intCast(@shrExact(post_index.index, @as(u2, 2) + @intFromEnum(sf))), + .sf = sf, + }, + } } } }; + }, + .signed_offset => |signed_offset| { + assert(signed_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{ + .stp = .{ + .Rt = t1.alias.encode(.{}), + .Rn = signed_offset.base.alias.encode(.{ .sp = true }), + .Rt2 = t2.alias.encode(.{}), + .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))), + .sf = sf, + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{ + .stp = .{ + .Rt = t1.alias.encode(.{}), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .Rt2 = t2.alias.encode(.{}), + .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))), + .sf = sf, + }, + } } } }; + }, + .base => |base| continue :form .{ .signed_offset = .{ .base = base } }, + } + }, + .scalar => |vs| { + assert(t2.format.scalar == vs); + form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_post_indexed = .{ .vector = .{ + .stp = .{ + .Rt = t1.alias.encode(.{ .V = true }), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .Rt2 = t2.alias.encode(.{ .V = true }), + .imm7 = @intCast(@shrExact(post_index.index, @intFromEnum(vs))), + .opc = .encode(vs), + }, + } } } }; + }, + .signed_offset => |signed_offset| { + assert(signed_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_offset = .{ .vector = .{ + .stp = .{ + .Rt = t1.alias.encode(.{ .V = true }), + .Rn = signed_offset.base.alias.encode(.{ .sp = true }), + .Rt2 = t2.alias.encode(.{ .V = true }), + .imm7 = @intCast(@shrExact(signed_offset.offset, @intFromEnum(vs))), + .opc = .encode(vs), + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_pre_indexed = .{ .vector = .{ + .stp = .{ + .Rt = t1.alias.encode(.{ .V = true }), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .Rt2 = t2.alias.encode(.{ .V = true }), + .imm7 = @intCast(@shrExact(pre_index.index, @intFromEnum(vs))), + .opc = .encode(vs), + }, + } } } }; + }, + .base => |base| continue :form .{ .signed_offset = .{ .base = base } }, + } + }, + } + } + /// C6.2.322 STR (immediate) + /// C7.2.331 STR (immediate, SIMD&FP) + pub fn str(t: Register, form: union(enum) { + post_index: struct { base: Register, index: i9 }, + pre_index: struct { base: Register, index: i9 }, + unsigned_offset: struct { base: Register, offset: u16 = 0 }, + base: Register, + }) Instruction { + switch (t.format) { + else => unreachable, + .integer => |sf| form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ + .str = .{ + .Rt = t.alias.encode(.{}), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .imm9 = post_index.index, + .sf = sf, + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ + .str = .{ + .Rt = t.alias.encode(.{}), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .imm9 = pre_index.index, + .sf = sf, + }, + } } } }; + }, + .unsigned_offset => |unsigned_offset| { + assert(unsigned_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ + .str = .{ + .Rt = t.alias.encode(.{}), + .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), + .imm12 = @intCast(@shrExact(unsigned_offset.offset, @as(u2, 2) + @intFromEnum(sf))), + .sf = sf, + }, + } } } }; + }, + .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, + }, + .scalar => |vs| form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_post_indexed = .{ .vector = .{ + .str = .{ + .Rt = t.alias.encode(.{ .V = true }), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .imm9 = post_index.index, + .opc1 = .encode(vs), + .size = .encode(vs), + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .vector = .{ + .str = .{ + .Rt = t.alias.encode(.{ .V = true }), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .imm9 = pre_index.index, + .opc1 = .encode(vs), + .size = .encode(vs), + }, + } } } }; + }, + .unsigned_offset => |unsigned_offset| { + assert(unsigned_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_unsigned_immediate = .{ .vector = .{ + .str = .{ + .Rt = t.alias.encode(.{ .V = true }), + .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), + .imm12 = @intCast(@shrExact(unsigned_offset.offset, @intFromEnum(vs))), + .opc1 = .encode(vs), + .size = .encode(vs), + }, + } } } }; + }, + .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, + }, + } + } + /// C6.2.324 STRB (immediate) + pub fn strb(t: Register, form: union(enum) { + post_index: struct { base: Register, index: i9 }, + pre_index: struct { base: Register, index: i9 }, + unsigned_offset: struct { base: Register, offset: u12 = 0 }, + base: Register, + }) Instruction { + assert(t.format.integer == .word); + form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ + .strb = .{ + .Rt = t.alias.encode(.{}), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .imm9 = post_index.index, + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ + .strb = .{ + .Rt = t.alias.encode(.{}), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .imm9 = pre_index.index, + }, + } } } }; + }, + .unsigned_offset => |unsigned_offset| { + assert(unsigned_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ + .strb = .{ + .Rt = t.alias.encode(.{}), + .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), + .imm12 = unsigned_offset.offset, + }, + } } } }; + }, + .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, + } + } + /// C6.2.326 STRH (immediate) + pub fn strh(t: Register, form: union(enum) { + post_index: struct { base: Register, index: i9 }, + pre_index: struct { base: Register, index: i9 }, + unsigned_offset: struct { base: Register, offset: u13 = 0 }, + base: Register, + }) Instruction { + assert(t.format.integer == .word); + form: switch (form) { + .post_index => |post_index| { + assert(post_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ + .strh = .{ + .Rt = t.alias.encode(.{}), + .Rn = post_index.base.alias.encode(.{ .sp = true }), + .imm9 = post_index.index, + }, + } } } }; + }, + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ + .strh = .{ + .Rt = t.alias.encode(.{}), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .imm9 = pre_index.index, + }, + } } } }; + }, + .unsigned_offset => |unsigned_offset| { + assert(unsigned_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ + .strh = .{ + .Rt = t.alias.encode(.{}), + .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), + .imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)), + }, + } } } }; + }, + .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, + } + } + /// C6.2.346 STUR + /// C7.2.333 STUR (SIMD&FP) + pub fn stur(t: Register, n: Register, simm: i9) Instruction { + assert(n.format.integer == .doubleword); + switch (t.format) { + else => unreachable, + .integer => |sf| return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ + .stur = .{ + .Rt = t.alias.encode(.{}), + .Rn = n.alias.encode(.{ .sp = true }), + .imm9 = simm, + .sf = sf, + }, + } } } }, + .scalar => |vs| return .{ .load_store = .{ .register_unscaled_immediate = .{ .vector = .{ + .stur = .{ + .Rt = t.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{ .sp = true }), + .imm9 = simm, + .opc1 = .encode(vs), + .size = .encode(vs), + }, + } } } }, + } + } + /// C6.2.347 STURB + pub fn sturb(t: Register, n: Register, simm: i9) Instruction { + assert(t.format.integer == .word and n.format.integer == .doubleword); + return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ + .sturb = .{ + .Rt = t.alias.encode(.{}), + .Rn = n.alias.encode(.{ .sp = true }), + .imm9 = simm, + }, + } } } }; + } + /// C6.2.348 STURH + pub fn sturh(t: Register, n: Register, simm: i9) Instruction { + assert(t.format.integer == .word and n.format.integer == .doubleword); + return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ + .sturh = .{ + .Rt = t.alias.encode(.{}), + .Rn = n.alias.encode(.{ .sp = true }), + .imm9 = simm, + }, + } } } }; + } + /// C6.2.356 SUB (extended register) + /// C6.2.357 SUB (immediate) + /// C6.2.358 SUB (shifted register) + pub fn sub(d: Register, n: Register, form: union(enum) { + extended_register_explicit: struct { + register: Register, + option: DataProcessingRegister.AddSubtractExtendedRegister.Option, + amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount, + }, + extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend }, + immediate: u12, + shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" }, + register: Register, + shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, + shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, + }) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf); + form: switch (form) { + .extended_register_explicit => |extended_register_explicit| { + assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf()); + return .{ .data_processing_register = .{ .add_subtract_extended_register = .{ + .sub = .{ + .Rd = d.alias.encode(.{ .sp = true }), + .Rn = n.alias.encode(.{ .sp = true }), + .imm3 = switch (extended_register_explicit.amount) { + 0...4 => |amount| amount, + else => unreachable, + }, + .option = extended_register_explicit.option, + .Rm = extended_register_explicit.register.alias.encode(.{}), + .sf = sf, + }, + } } }; + }, + .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ + .register = extended_register.register, + .option = extended_register.extend, + .amount = switch (extended_register.extend) { + .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount, + }, + } }, + .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } }, + .shifted_immediate => |shifted_immediate| { + return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{ + .sub = .{ + .Rd = d.alias.encode(.{ .sp = true }), + .Rn = n.alias.encode(.{ .sp = true }), + .imm12 = shifted_immediate.immediate, + .sh = shifted_immediate.lsl, + .sf = sf, + }, + } } }; + }, + .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp) + .{ .extended_register = .{ .register = register, .extend = switch (sf) { + .word => .{ .uxtw = 0 }, + .doubleword => .{ .uxtx = 0 }, + } } } + else + .{ .shifted_register = .{ .register = register } }, + .shifted_register_explicit => |shifted_register_explicit| { + assert(shifted_register_explicit.register.format.integer == sf); + return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{ + .sub = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm6 = switch (sf) { + .word => @as(u5, @intCast(shifted_register_explicit.amount)), + .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), + }, + .Rm = shifted_register_explicit.register.alias.encode(.{}), + .shift = switch (shifted_register_explicit.shift) { + .lsl, .lsr, .asr => |shift| shift, + .ror => unreachable, + }, + .sf = sf, + }, + } } }; + }, + .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ + .register = shifted_register.register, + .shift = shifted_register.shift, + .amount = switch (shifted_register.shift) { + .lsl, .lsr, .asr => |amount| amount, + .ror => unreachable, + }, + } }, + } + } + /// C6.2.362 SUBS (extended register) + /// C6.2.363 SUBS (immediate) + /// C6.2.364 SUBS (shifted register) + pub fn subs(d: Register, n: Register, form: union(enum) { + extended_register_explicit: struct { + register: Register, + option: DataProcessingRegister.AddSubtractExtendedRegister.Option, + amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount, + }, + extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend }, + immediate: u12, + shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" }, + register: Register, + shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, + shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, + }) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf); + form: switch (form) { + .extended_register_explicit => |extended_register_explicit| { + assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf()); + return .{ .data_processing_register = .{ .add_subtract_extended_register = .{ + .subs = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .sp = true }), + .imm3 = switch (extended_register_explicit.amount) { + 0...4 => |amount| amount, + else => unreachable, + }, + .option = extended_register_explicit.option, + .Rm = extended_register_explicit.register.alias.encode(.{}), + .sf = sf, + }, + } } }; + }, + .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ + .register = extended_register.register, + .option = extended_register.extend, + .amount = switch (extended_register.extend) { + .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount, + }, + } }, + .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } }, + .shifted_immediate => |shifted_immediate| { + return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{ + .subs = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .sp = true }), + .imm12 = shifted_immediate.immediate, + .sh = shifted_immediate.lsl, + .sf = sf, + }, + } } }; + }, + .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp) + .{ .extended_register = .{ .register = register, .extend = switch (sf) { + .word => .{ .uxtw = 0 }, + .doubleword => .{ .uxtx = 0 }, + } } } + else + .{ .shifted_register = .{ .register = register } }, + .shifted_register_explicit => |shifted_register_explicit| { + assert(shifted_register_explicit.register.format.integer == sf); + return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{ + .subs = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm6 = switch (sf) { + .word => @as(u5, @intCast(shifted_register_explicit.amount)), + .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), + }, + .Rm = shifted_register_explicit.register.alias.encode(.{}), + .shift = switch (shifted_register_explicit.shift) { + .lsl, .lsr, .asr => |shift| shift, + .ror => unreachable, + }, + .sf = sf, + }, + } } }; + }, + .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ + .register = shifted_register.register, + .shift = shifted_register.shift, + .amount = switch (shifted_register.shift) { + .lsl, .lsr, .asr => |amount| amount, + .ror => unreachable, + }, + } }, + } + } + /// C6.2.365 SVC + pub fn svc(imm: u16) Instruction { + return .{ .branch_exception_generating_system = .{ .exception_generating = .{ + .svc = .{ .imm16 = imm }, + } } }; + } + /// C6.2.372 SYS + pub fn sys(op1: u3, n: u4, m: u4, op2: u3, t: Register) Instruction { + assert(t.format.integer == .doubleword); + return .{ .branch_exception_generating_system = .{ .system = .{ + .sys = .{ + .Rt = t.alias.encode(.{}), + .op2 = op2, + .CRm = m, + .CRn = n, + .op1 = op1, + }, + } } }; + } + /// C6.2.373 SYSL + pub fn sysl(t: Register, op1: u3, n: u4, m: u4, op2: u3) Instruction { + assert(t.format.integer == .doubleword); + return .{ .branch_exception_generating_system = .{ .system = .{ + .sysl = .{ + .Rt = t.alias.encode(.{}), + .op2 = op2, + .CRm = m, + .CRn = n, + .op1 = op1, + }, + } } }; + } + /// C6.2.374 TBNZ + pub fn tbnz(t: Register, imm: u6, label: i16) Instruction { + return .{ .branch_exception_generating_system = .{ .test_branch_immediate = .{ + .tbnz = .{ + .Rt = t.alias.encode(.{}), + .imm14 = @intCast(@shrExact(label, 2)), + .b40 = @truncate(switch (t.format.integer) { + .word => @as(u5, @intCast(imm)), + .doubleword => imm, + }), + .b5 = @intCast(imm >> 5), + }, + } } }; + } + /// C6.2.375 TBZ + pub fn tbz(t: Register, imm: u6, label: i16) Instruction { + return .{ .branch_exception_generating_system = .{ .test_branch_immediate = .{ + .tbz = .{ + .Rt = t.alias.encode(.{}), + .imm14 = @intCast(@shrExact(label, 2)), + .b40 = @truncate(switch (t.format.integer) { + .word => @as(u5, @intCast(imm)), + .doubleword => imm, + }), + .b5 = @intCast(imm >> 5), + }, + } } }; + } + /// C6.2.376 TCANCEL + pub fn tcancel(imm: u16) Instruction { + return .{ .branch_exception_generating_system = .{ .exception_generating = .{ + .tcancel = .{ .imm16 = imm }, + } } }; + } + /// C6.2.385 UBFM + pub fn ubfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and bitmask.validBitfield(sf)); + return .{ .data_processing_immediate = .{ .bitfield = .{ + .ubfm = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .imm = bitmask, + .sf = sf, + }, + } } }; + } + /// C7.2.355 UCVTF (scalar, integer) + pub fn ucvtf(d: Register, n: Register) Instruction { + return .{ .data_processing_vector = .{ .convert_float_integer = .{ + .ucvtf = .{ + .Rd = d.alias.encode(.{ .V = true }), + .Rn = n.alias.encode(.{}), + .ftype = switch (d.format.scalar) { + else => unreachable, + .single => .single, + .double => .double, + .half => .half, + }, + .sf = n.format.integer, + }, + } } }; + } + /// C6.2.387 UDF + pub fn udf(imm: u16) Instruction { + return .{ .reserved = .{ + .udf = .{ .imm16 = imm }, + } }; + } + /// C6.2.388 UDIV + pub fn udiv(d: Register, n: Register, m: Register) Instruction { + const sf = d.format.integer; + assert(n.format.integer == sf and m.format.integer == sf); + return .{ .data_processing_register = .{ .data_processing_two_source = .{ + .udiv = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + .sf = sf, + }, + } } }; + } + /// C6.2.389 UMADDL + pub fn umaddl(d: Register, n: Register, m: Register, a: Register) Instruction { + assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword); + return .{ .data_processing_register = .{ .data_processing_three_source = .{ + .umaddl = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Ra = a.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + }, + } } }; + } + /// C6.2.391 UMSUBL + pub fn umsubl(d: Register, n: Register, m: Register, a: Register) Instruction { + assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword); + return .{ .data_processing_register = .{ .data_processing_three_source = .{ + .umsubl = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Ra = a.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + }, + } } }; + } + /// C7.2.371 UMOV + pub fn umov(d: Register, n: Register) Instruction { + const sf = d.format.integer; + const vs = n.format.element.size; + switch (vs) { + else => unreachable, + .byte, .half, .single => assert(sf == .word), + .double => assert(sf == .doubleword), + } + return .{ .data_processing_vector = .{ .simd_copy = .{ + .umov = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{ .V = true }), + .imm5 = switch (vs) { + else => unreachable, + .byte => @as(u5, @as(u4, @intCast(n.format.element.index))) << 1 | @as(u5, 0b1) << 0, + .half => @as(u5, @as(u3, @intCast(n.format.element.index))) << 2 | @as(u5, 0b10) << 0, + .single => @as(u5, @as(u2, @intCast(n.format.element.index))) << 3 | @as(u5, 0b100) << 0, + .double => @as(u5, @as(u1, @intCast(n.format.element.index))) << 4 | @as(u5, 0b1000) << 0, + }, + .Q = sf, + }, + } } }; + } + /// C6.2.392 UMULH + pub fn umulh(d: Register, n: Register, m: Register) Instruction { + assert(d.format.integer == .doubleword and n.format.integer == .doubleword and m.format.integer == .doubleword); + return .{ .data_processing_register = .{ .data_processing_three_source = .{ + .umulh = .{ + .Rd = d.alias.encode(.{}), + .Rn = n.alias.encode(.{}), + .Rm = m.alias.encode(.{}), + }, + } } }; + } + /// C6.2.396 WFE + pub fn wfe() Instruction { + return .{ .branch_exception_generating_system = .{ .hints = .{ + .wfe = .{}, + } } }; + } + /// C6.2.398 WFI + pub fn wfi() Instruction { + return .{ .branch_exception_generating_system = .{ .hints = .{ + .wfi = .{}, + } } }; + } + /// C6.2.402 YIELD + pub fn yield() Instruction { + return .{ .branch_exception_generating_system = .{ .hints = .{ + .yield = .{}, + } } }; + } + + pub const size = @divExact(@bitSizeOf(Backing), 8); + pub const Backing = u32; + pub fn read(mem: *const [size]u8) Instruction { + return @bitCast(std.mem.readInt(Backing, mem, .little)); + } + pub fn write(inst: Instruction, mem: *[size]u8) void { + std.mem.writeInt(Backing, mem, @bitCast(inst), .little); + } + + pub fn format(inst: Instruction, writer: *std.Io.Writer) std.Io.Writer.Error!void { + const dis: aarch64.Disassemble = .{}; + try dis.printInstruction(inst, writer); + } + + comptime { + @setEvalBranchQuota(68_000); + verify(@typeName(Instruction), Instruction); + } + fn verify(name: []const u8, Type: type) void { + switch (@typeInfo(Type)) { + .@"union" => |info| { + if (info.layout != .@"packed" or @bitSizeOf(Type) != @bitSizeOf(Backing)) { + @compileLog(name ++ " should have u32 abi"); + } + for (info.fields) |field| verify(name ++ "." ++ field.name, field.type); + }, + .@"struct" => |info| { + if (info.layout != .@"packed" or info.backing_integer != Backing) { + @compileLog(name ++ " should have u32 abi"); + } + var bit_offset = 0; + for (info.fields) |field| { + if (std.mem.startsWith(u8, field.name, "encoded")) { + if (if (std.fmt.parseInt(u5, field.name["encoded".len..], 10)) |encoded_bit_offset| encoded_bit_offset != bit_offset else |_| true) { + @compileError(std.fmt.comptimePrint("{s}.{s} should be named encoded{d}", .{ name, field.name, bit_offset })); + } + if (field.default_value_ptr != null) { + @compileError(std.fmt.comptimePrint("{s}.{s} should be named decoded{d}", .{ name, field.name, bit_offset })); + } + } else if (std.mem.startsWith(u8, field.name, "decoded")) { + if (if (std.fmt.parseInt(u5, field.name["decoded".len..], 10)) |decoded_bit_offset| decoded_bit_offset != bit_offset else |_| true) { + @compileError(std.fmt.comptimePrint("{s}.{s} should be named decoded{d}", .{ name, field.name, bit_offset })); + } + if (field.default_value_ptr == null) { + @compileError(std.fmt.comptimePrint("{s}.{s} should be named encoded{d}", .{ name, field.name, bit_offset })); + } + } + bit_offset += @bitSizeOf(field.type); + } + }, + else => @compileError(name ++ " has an unexpected field type"), + } + } +}; + +const aarch64 = @import("../aarch64.zig"); +const assert = std.debug.assert; +const std = @import("std"); diff --git a/src/codegen/aarch64/instructions.zon b/src/codegen/aarch64/instructions.zon new file mode 100644 index 0000000000..4aacf85e01 --- /dev/null +++ b/src/codegen/aarch64/instructions.zon @@ -0,0 +1,1343 @@ +.{ + // C6.2.3 ADD (extended register) + .{ + .pattern = "ADD , , ", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + }, + .encode = .{ .add, .Wd, .Wn, .{ .register = .Wm } }, + }, + .{ + .pattern = "ADD , , , #", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + .extend = .{ .extend = .{ .size = .word } }, + .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } }, + }, + .encode = .{ .add, .Wd, .Wn, .{ .extended_register_explicit = .{ .register = .Wm, .option = .extend, .amount = .amount } } }, + }, + .{ + .pattern = "ADD , , ", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .add, .Xd, .Xn, .{ .register = .Xm } }, + }, + .{ + .pattern = "ADD , , , #", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + .extend = .{ .extend = .{ .size = .word } }, + .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } }, + }, + .encode = .{ .add, .Xd, .Xn, .{ .extended_register_explicit = .{ .register = .Wm, .option = .extend, .amount = .amount } } }, + }, + .{ + .pattern = "ADD , , , #", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .extend = .{ .extend = .{ .size = .doubleword } }, + .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } }, + }, + .encode = .{ .add, .Xd, .Xn, .{ .extended_register_explicit = .{ .register = .Xm, .option = .extend, .amount = .amount } } }, + }, + // C6.2.4 ADD (immediate) + .{ + .pattern = "ADD , , #", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, + .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } }, + }, + .encode = .{ .add, .Wd, .Wn, .{ .immediate = .imm } }, + }, + .{ + .pattern = "ADD , , #, LSL #", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, + .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } }, + .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } }, + }, + .encode = .{ .add, .Wd, .Wn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } }, + }, + .{ + .pattern = "ADD , , #", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, + .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } }, + }, + .encode = .{ .add, .Xd, .Xn, .{ .immediate = .imm } }, + }, + .{ + .pattern = "ADD , , #, LSL #", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, + .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } }, + .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } }, + }, + .encode = .{ .add, .Xd, .Xn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } }, + }, + // C6.2.5 ADD (shifted register) + .{ + .pattern = "ADD , , ", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + }, + .encode = .{ .add, .Wd, .Wn, .{ .register = .Wm } }, + }, + .{ + .pattern = "ADD , , , #", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + .shift = .{ .shift = .{ .allow_ror = false } }, + .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, + }, + .encode = .{ .add, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } }, + }, + .{ + .pattern = "ADD , , ", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .add, .Xd, .Xn, .{ .register = .Xm } }, + }, + .{ + .pattern = "ADD , , , #", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .shift = .{ .shift = .{ .allow_ror = false } }, + .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, + }, + .encode = .{ .add, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } }, + }, + // C6.2.13 AND (shifted register) + .{ + .pattern = "AND , , ", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + }, + .encode = .{ .@"and", .Wd, .Wn, .{ .register = .Wm } }, + }, + .{ + .pattern = "AND , , , #", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + .shift = .{ .shift = .{} }, + .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, + }, + .encode = .{ .@"and", .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } }, + }, + .{ + .pattern = "AND , , ", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .@"and", .Xd, .Xn, .{ .register = .Xm } }, + }, + .{ + .pattern = "AND , , , #", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .shift = .{ .shift = .{} }, + .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, + }, + .encode = .{ .@"and", .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } }, + }, + // C6.2.15 ANDS (shifted register) + .{ + .pattern = "ANDS , , ", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + }, + .encode = .{ .ands, .Wd, .Wn, .{ .register = .Wm } }, + }, + .{ + .pattern = "ANDS , , , #", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + .shift = .{ .shift = .{} }, + .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, + }, + .encode = .{ .ands, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } }, + }, + .{ + .pattern = "ANDS , , ", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .ands, .Xd, .Xn, .{ .register = .Xm } }, + }, + .{ + .pattern = "ANDS , , , #", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .shift = .{ .shift = .{} }, + .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, + }, + .encode = .{ .ands, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } }, + }, + // C6.2.35 BLR + .{ + .pattern = "BLR ", + .symbols = .{ + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .blr, .Xn }, + }, + // C6.2.30 BFM + .{ + .pattern = "BFM , , #, #", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, + .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, + }, + .encode = .{ .bfm, .Wd, .Wn, .{ .N = .word, .immr = .immr, .imms = .imms } }, + }, + .{ + .pattern = "BFM , , #, #", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, + .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, + }, + .encode = .{ .bfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .immr, .imms = .imms } }, + }, + // C6.2.37 BR + .{ + .pattern = "BR ", + .symbols = .{ + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .br, .Xn }, + }, + // C6.2.40 BRK + .{ + .pattern = "BRK #", + .symbols = .{ + .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, + }, + .encode = .{ .brk, .imm }, + }, + // C6.2.56 CLREX + .{ + .pattern = "CLREX", + .symbols = .{}, + .encode = .{ .clrex, 0b1111 }, + }, + .{ + .pattern = "CLREX #", + .symbols = .{ + .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 } } }, + }, + .encode = .{ .clrex, .imm }, + }, + // C6.2.109 DC + .{ + .pattern = "DC IVAC, ", + .symbols = .{ + .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .sys, 0b000, 0b0111, 0b0110, 0b001, .Xt }, + }, + .{ + .pattern = "DC ISW, ", + .symbols = .{ + .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .sys, 0b000, 0b0111, 0b0110, 0b010, .Xt }, + }, + .{ + .pattern = "DC CSW, ", + .symbols = .{ + .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .sys, 0b000, 0b0111, 0b1010, 0b010, .Xt }, + }, + .{ + .pattern = "DC CISW, ", + .symbols = .{ + .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .sys, 0b000, 0b0111, 0b1110, 0b010, .Xt }, + }, + .{ + .pattern = "DC ZVA, ", + .symbols = .{ + .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .sys, 0b011, 0b0111, 0b0100, 0b001, .Xt }, + }, + .{ + .pattern = "DC CVAC, ", + .symbols = .{ + .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .sys, 0b011, 0b0111, 0b1010, 0b001, .Xt }, + }, + .{ + .pattern = "DC CVAU, ", + .symbols = .{ + .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .sys, 0b011, 0b0111, 0b1011, 0b001, .Xt }, + }, + .{ + .pattern = "DC CIVAC, ", + .symbols = .{ + .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .sys, 0b011, 0b0111, 0b1110, 0b001, .Xt }, + }, + // C6.2.110 DCPS1 + .{ + .pattern = "DCPS1", + .symbols = .{}, + .encode = .{ .dcps1, 0 }, + }, + .{ + .pattern = "DCPS1 #", + .symbols = .{ + .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, + }, + .encode = .{ .dcps1, .imm }, + }, + // C6.2.111 DCPS2 + .{ + .pattern = "DCPS2", + .symbols = .{}, + .encode = .{ .dcps2, 0 }, + }, + .{ + .pattern = "DCPS2 #", + .symbols = .{ + .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, + }, + .encode = .{ .dcps2, .imm }, + }, + // C6.2.112 DCPS3 + .{ + .pattern = "DCPS3", + .symbols = .{}, + .encode = .{ .dcps3, 0 }, + }, + .{ + .pattern = "DCPS3 #", + .symbols = .{ + .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, + }, + .encode = .{ .dcps3, .imm }, + }, + // C6.2.116 DSB + .{ + .pattern = "DSB