From 27d2848e0096d31cb42cb258a89ed276ec26434e Mon Sep 17 00:00:00 2001
From: Krzysztof Wolicki Der Teufel
Date: Tue, 7 Mar 2023 00:22:48 +0100
Subject: [PATCH 001/216] autodoc: Add struct to tryResolveRefPath
fix rendering of fieldRef in exprName
---
lib/docs/main.js | 6 +++---
src/Autodoc.zig | 19 +++++++++++++++++++
2 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/lib/docs/main.js b/lib/docs/main.js
index fc99b2f861..4b946eb963 100644
--- a/lib/docs/main.js
+++ b/lib/docs/main.js
@@ -1139,9 +1139,9 @@ const NAV_MODES = {
return exprName(switchIndex, opts);
}
case "fieldRef": {
- const enumObj = exprName({ type: expr.fieldRef.type }, opts);
- const field =
- getAstNode(enumObj.src).fields[expr.fieldRef.index];
+ const field_idx = expr.fieldRef.index;
+ const type = getType(expr.fieldRef.type);
+ const field = getAstNode(type.src).fields[field_idx];
const name = getAstNode(field).name;
return name;
}
diff --git a/src/Autodoc.zig b/src/Autodoc.zig
index 15d90b104b..47b0c8d3c2 100644
--- a/src/Autodoc.zig
+++ b/src/Autodoc.zig
@@ -3616,6 +3616,25 @@ fn tryResolveRefPath(
continue :outer;
},
},
+ .@"struct" => |st| {
+ for (st) |field| {
+ if (std.mem.eql(u8, field.name, child_string)) {
+ path[i + 1] = field.val.expr;
+ continue :outer;
+ }
+ }
+
+ // if we got here, our search failed
+ printWithContext(
+ file,
+ inst_index,
+ "failed to match `{s}` in struct",
+ .{child_string},
+ );
+
+ path[i + 1] = (try self.cteTodo("match failure")).expr;
+ continue :outer;
+ },
}
}
From 6d74c0d1b41b52bca3d66092a48660f2ee4ae4f8 Mon Sep 17 00:00:00 2001
From: Ryan Liptak
Date: Wed, 8 Mar 2023 00:57:39 -0800
Subject: [PATCH 002/216] Add comments explaining BUFFER_OVERFLOW during
NtQueryInformationFile calls
---
lib/std/fs/file.zig | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index bf93a61239..5306909aea 100644
--- a/lib/std/fs/file.zig
+++ b/lib/std/fs/file.zig
@@ -379,6 +379,9 @@ pub const File = struct {
const rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &info, @sizeOf(windows.FILE_ALL_INFORMATION), .FileAllInformation);
switch (rc) {
.SUCCESS => {},
+ // Buffer overflow here indicates that there is more information available than was able to be stored in the buffer
+ // size provided. This is treated as success because the type of variable-length information that this would be relevant for
+ // (name, volume name, etc) we don't care about.
.BUFFER_OVERFLOW => {},
.INVALID_PARAMETER => unreachable,
.ACCESS_DENIED => return error.AccessDenied,
@@ -830,6 +833,9 @@ pub const File = struct {
const rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &info, @sizeOf(windows.FILE_ALL_INFORMATION), .FileAllInformation);
switch (rc) {
.SUCCESS => {},
+ // Buffer overflow here indicates that there is more information available than was able to be stored in the buffer
+ // size provided. This is treated as success because the type of variable-length information that this would be relevant for
+ // (name, volume name, etc) we don't care about.
.BUFFER_OVERFLOW => {},
.INVALID_PARAMETER => unreachable,
.ACCESS_DENIED => return error.AccessDenied,
From 93b35c69998398e962bff84f3e5006afa122fbde Mon Sep 17 00:00:00 2001
From: Ryan Liptak
Date: Wed, 8 Mar 2023 01:18:33 -0800
Subject: [PATCH 003/216] os.isCygwinPty: Fix a bug, replace kernel32 call, and
optimize
- Fixes the first few code units of the name being omitted (it was using `@sizeOf(FILE_NAME_INFO)` as the start of the name bytes, but that includes the length of the dummy [1]u16 field and padding; instead the start should be the offset of the dummy [1]u16 field)
- Replaces kernel32.GetFileInformationByHandleEx call with ntdll.NtQueryInformationFile
+ Contributes towards #1840
- Checks that the handle is a named pipe first before querying and checking the name, which is a much faster call than NtQueryInformationFile (this was about a 10x speedup in my probably-not-so-good/take-it-with-a-grain-of-salt benchmarking)
---
lib/std/os.zig | 48 +++++++++++++++++++++++++++---------
lib/std/os/windows.zig | 23 +++++++++++++++++
lib/std/os/windows/ntdll.zig | 9 +++++++
3 files changed, 69 insertions(+), 11 deletions(-)
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 821c544cc8..f69532cc49 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -3217,22 +3217,48 @@ pub fn isatty(handle: fd_t) bool {
pub fn isCygwinPty(handle: fd_t) bool {
if (builtin.os.tag != .windows) return false;
- const size = @sizeOf(windows.FILE_NAME_INFO);
- var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = [_]u8{0} ** (size + windows.MAX_PATH);
+ // If this is a MSYS2/cygwin pty, then it will be a named pipe with a name in one of these formats:
+ // msys-[...]-ptyN-[...]
+ // cygwin-[...]-ptyN-[...]
+ //
+ // Example: msys-1888ae32e00d56aa-pty0-to-master
- if (windows.kernel32.GetFileInformationByHandleEx(
- handle,
- windows.FileNameInfo,
- @ptrCast(*anyopaque, &name_info_bytes),
- name_info_bytes.len,
- ) == 0) {
- return false;
+ // First, just check that the handle is a named pipe.
+ // This allows us to avoid the more costly NtQueryInformationFile call
+ // for handles that aren't named pipes.
+ {
+ var io_status: windows.IO_STATUS_BLOCK = undefined;
+ var device_info: windows.FILE_FS_DEVICE_INFORMATION = undefined;
+ const rc = windows.ntdll.NtQueryVolumeInformationFile(handle, &io_status, &device_info, @sizeOf(windows.FILE_FS_DEVICE_INFORMATION), .FileFsDeviceInformation);
+ switch (rc) {
+ .SUCCESS => {},
+ else => return false,
+ }
+ if (device_info.DeviceType != windows.FILE_DEVICE_NAMED_PIPE) return false;
+ }
+
+ const name_bytes_offset = @offsetOf(windows.FILE_NAME_INFO, "FileName");
+ // `NAME_MAX` UTF-16 code units (2 bytes each)
+ // Note: This buffer may not be long enough to handle *all* possible paths (PATH_MAX_WIDE would be necessary for that),
+ // but because we only care about certain paths and we know they must be within a reasonable length,
+ // we can use this smaller buffer and just return false on any error from NtQueryInformationFile.
+ const num_name_bytes = windows.MAX_PATH * 2;
+ var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = [_]u8{0} ** (name_bytes_offset + num_name_bytes);
+
+ var io_status_block: windows.IO_STATUS_BLOCK = undefined;
+ const rc = windows.ntdll.NtQueryInformationFile(handle, &io_status_block, &name_info_bytes, @intCast(u32, name_info_bytes.len), .FileNameInformation);
+ switch (rc) {
+ .SUCCESS => {},
+ .INVALID_PARAMETER => unreachable,
+ else => return false,
}
const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
- const name_bytes = name_info_bytes[size .. size + @as(usize, name_info.FileNameLength)];
+ const name_bytes = name_info_bytes[name_bytes_offset .. name_bytes_offset + @as(usize, name_info.FileNameLength)];
const name_wide = mem.bytesAsSlice(u16, name_bytes);
- return mem.indexOf(u16, name_wide, &[_]u16{ 'm', 's', 'y', 's', '-' }) != null or
+ // Note: The name we get from NtQueryInformationFile will be prefixed with a '\', e.g. \msys-1888ae32e00d56aa-pty0-to-master
+ return (mem.startsWith(u16, name_wide, &[_]u16{ '\\', 'm', 's', 'y', 's', '-' }) or
+ mem.startsWith(u16, name_wide, &[_]u16{ '\\', 'c', 'y', 'g', 'w', 'i', 'n', '-' })) and
mem.indexOf(u16, name_wide, &[_]u16{ '-', 'p', 't', 'y' }) != null;
}
diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig
index b63fdb9f92..23aa378e9e 100644
--- a/lib/std/os/windows.zig
+++ b/lib/std/os/windows.zig
@@ -2472,6 +2472,29 @@ pub const FILE_INFORMATION_CLASS = enum(c_int) {
FileMaximumInformation,
};
+pub const FILE_FS_DEVICE_INFORMATION = extern struct {
+ DeviceType: DEVICE_TYPE,
+ Characteristics: ULONG,
+};
+
+pub const FS_INFORMATION_CLASS = enum(c_int) {
+ FileFsVolumeInformation = 1,
+ FileFsLabelInformation,
+ FileFsSizeInformation,
+ FileFsDeviceInformation,
+ FileFsAttributeInformation,
+ FileFsControlInformation,
+ FileFsFullSizeInformation,
+ FileFsObjectIdInformation,
+ FileFsDriverPathInformation,
+ FileFsVolumeFlagsInformation,
+ FileFsSectorSizeInformation,
+ FileFsDataCopyInformation,
+ FileFsMetadataSizeInformation,
+ FileFsFullSizeInformationEx,
+ FileFsMaximumInformation,
+};
+
pub const OVERLAPPED = extern struct {
Internal: ULONG_PTR,
InternalHigh: ULONG_PTR,
diff --git a/lib/std/os/windows/ntdll.zig b/lib/std/os/windows/ntdll.zig
index 8c5260c1bc..58cba356a2 100644
--- a/lib/std/os/windows/ntdll.zig
+++ b/lib/std/os/windows/ntdll.zig
@@ -18,6 +18,7 @@ const IO_STATUS_BLOCK = windows.IO_STATUS_BLOCK;
const LARGE_INTEGER = windows.LARGE_INTEGER;
const OBJECT_INFORMATION_CLASS = windows.OBJECT_INFORMATION_CLASS;
const FILE_INFORMATION_CLASS = windows.FILE_INFORMATION_CLASS;
+const FS_INFORMATION_CLASS = windows.FS_INFORMATION_CLASS;
const UNICODE_STRING = windows.UNICODE_STRING;
const RTL_OSVERSIONINFOW = windows.RTL_OSVERSIONINFOW;
const FILE_BASIC_INFORMATION = windows.FILE_BASIC_INFORMATION;
@@ -232,6 +233,14 @@ pub extern "ntdll" fn NtQueryObject(
ReturnLength: ?*ULONG,
) callconv(WINAPI) NTSTATUS;
+pub extern "ntdll" fn NtQueryVolumeInformationFile(
+ FileHandle: HANDLE,
+ IoStatusBlock: *IO_STATUS_BLOCK,
+ FsInformation: *anyopaque,
+ Length: ULONG,
+ FsInformationClass: FS_INFORMATION_CLASS,
+) callconv(WINAPI) NTSTATUS;
+
pub extern "ntdll" fn RtlWakeAddressAll(
Address: ?*const anyopaque,
) callconv(WINAPI) void;
From 7e3591bedd41bde8bcca892885376e2f4a8163a3 Mon Sep 17 00:00:00 2001
From: r00ster91
Date: Wed, 8 Mar 2023 19:25:53 +0100
Subject: [PATCH 004/216] std.json.parseInternal: use switches instead of ifs
---
lib/std/json.zig | 41 ++++++++++++++++++-----------------------
1 file changed, 18 insertions(+), 23 deletions(-)
diff --git a/lib/std/json.zig b/lib/std/json.zig
index 0cce71b1e6..9d24ebaff4 100644
--- a/lib/std/json.zig
+++ b/lib/std/json.zig
@@ -1534,30 +1534,25 @@ fn parseInternal(
child_options.allow_trailing_data = true;
var found = false;
inline for (structInfo.fields, 0..) |field, i| {
- // TODO: using switches here segfault the compiler (#2727?)
- if ((stringToken.escapes == .None and mem.eql(u8, field.name, key_source_slice)) or (stringToken.escapes == .Some and (field.name.len == stringToken.decodedLength() and encodesTo(field.name, key_source_slice)))) {
- // if (switch (stringToken.escapes) {
- // .None => mem.eql(u8, field.name, key_source_slice),
- // .Some => (field.name.len == stringToken.decodedLength() and encodesTo(field.name, key_source_slice)),
- // }) {
+ if (switch (stringToken.escapes) {
+ .None => mem.eql(u8, field.name, key_source_slice),
+ .Some => (field.name.len == stringToken.decodedLength() and encodesTo(field.name, key_source_slice)),
+ }) {
if (fields_seen[i]) {
- // switch (options.duplicate_field_behavior) {
- // .UseFirst => {},
- // .Error => {},
- // .UseLast => {},
- // }
- if (options.duplicate_field_behavior == .UseFirst) {
- // unconditonally ignore value. for comptime fields, this skips check against default_value
- parseFree(field.type, try parse(field.type, tokens, child_options), child_options);
- found = true;
- break;
- } else if (options.duplicate_field_behavior == .Error) {
- return error.DuplicateJSONField;
- } else if (options.duplicate_field_behavior == .UseLast) {
- if (!field.is_comptime) {
- parseFree(field.type, @field(r, field.name), child_options);
- }
- fields_seen[i] = false;
+ switch (options.duplicate_field_behavior) {
+ .UseFirst => {
+ // unconditonally ignore value. for comptime fields, this skips check against default_value
+ parseFree(field.type, try parse(field.type, tokens, child_options), child_options);
+ found = true;
+ break;
+ },
+ .Error => return error.DuplicateJSONField,
+ .UseLast => {
+ if (!field.is_comptime) {
+ parseFree(field.type, @field(r, field.name), child_options);
+ }
+ fields_seen[i] = false;
+ },
}
}
if (field.is_comptime) {
From c0789b4814989f2d91d3d2145d227dcdec3e2770 Mon Sep 17 00:00:00 2001
From: r00ster91
Date: Wed, 8 Mar 2023 19:26:03 +0100
Subject: [PATCH 005/216] std.json.stringify: support [*:0]const u8
---
lib/std/json.zig | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/lib/std/json.zig b/lib/std/json.zig
index 9d24ebaff4..590040efba 100644
--- a/lib/std/json.zig
+++ b/lib/std/json.zig
@@ -2350,10 +2350,13 @@ pub fn stringify(
return stringify(value.*, options, out_stream);
},
},
- // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972)
- .Slice => {
- if (ptr_info.child == u8 and options.string == .String and std.unicode.utf8ValidateSlice(value)) {
- try encodeJsonString(value, options, out_stream);
+ .Many, .Slice => {
+ if (ptr_info.size == .Many and ptr_info.sentinel == null)
+ @compileError("unable to stringify type '" ++ @typeName(T) ++ "' without sentinel");
+ const slice = if (ptr_info.size == .Many) mem.span(value) else value;
+
+ if (ptr_info.child == u8 and options.string == .String and std.unicode.utf8ValidateSlice(slice)) {
+ try encodeJsonString(slice, options, out_stream);
return;
}
@@ -2362,7 +2365,7 @@ pub fn stringify(
if (child_options.whitespace) |*whitespace| {
whitespace.indent_level += 1;
}
- for (value, 0..) |x, i| {
+ for (slice, 0..) |x, i| {
if (i != 0) {
try out_stream.writeByte(',');
}
@@ -2371,7 +2374,7 @@ pub fn stringify(
}
try stringify(x, child_options, out_stream);
}
- if (value.len != 0) {
+ if (slice.len != 0) {
if (options.whitespace) |whitespace| {
try whitespace.outputIndent(out_stream);
}
@@ -2526,6 +2529,12 @@ test "stringify string" {
try teststringify("\"\\/\"", "/", StringifyOptions{ .string = .{ .String = .{ .escape_solidus = true } } });
}
+test "stringify many-item sentinel-terminated string" {
+ try teststringify("\"hello\"", @as([*:0]const u8, "hello"), StringifyOptions{});
+ try teststringify("\"with\\nescapes\\r\"", @as([*:0]const u8, "with\nescapes\r"), StringifyOptions{ .string = .{ .String = .{ .escape_unicode = true } } });
+ try teststringify("\"with unicode\\u0001\"", @as([*:0]const u8, "with unicode\u{1}"), StringifyOptions{ .string = .{ .String = .{ .escape_unicode = true } } });
+}
+
test "stringify tagged unions" {
try teststringify("42", union(enum) {
Foo: u32,
@@ -2712,7 +2721,7 @@ test "encodesTo" {
try testing.expectEqual(true, encodesTo("withąunicode😂", "with\\u0105unicode\\ud83d\\ude02"));
}
-test "issue 14600" {
+test "deserializing string with escape sequence into sentinel slice" {
const json = "\"\\n\"";
var token_stream = std.json.TokenStream.init(json);
const options = ParseOptions{ .allocator = std.testing.allocator };
From 76afdd0586dc646bee1f20fd9ff23c044d70a211 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Thu, 16 Mar 2023 17:11:44 +0100
Subject: [PATCH 006/216] link: move macOS kernel inode cache invalidation to
MachO linker
---
src/link.zig | 21 +--------------------
src/link/MachO.zig | 17 +++++++++++++++++
src/link/MachO/zld.zig | 1 +
3 files changed, 19 insertions(+), 20 deletions(-)
diff --git a/src/link.zig b/src/link.zig
index e68f9c97d0..a919ffa999 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -418,26 +418,7 @@ pub const File = struct {
.Exe => {},
}
switch (base.tag) {
- .macho => if (base.file) |f| {
- if (build_options.only_c) unreachable;
- if (comptime builtin.target.isDarwin() and builtin.target.cpu.arch == .aarch64) {
- if (base.options.target.cpu.arch == .aarch64) {
- // XNU starting with Big Sur running on arm64 is caching inodes of running binaries.
- // Any change to the binary will effectively invalidate the kernel's cache
- // resulting in a SIGKILL on each subsequent run. Since when doing incremental
- // linking we're modifying a binary in-place, this will end up with the kernel
- // killing it on every subsequent run. To circumvent it, we will copy the file
- // into a new inode, remove the original file, and rename the copy to match
- // the original file. This is super messy, but there doesn't seem any other
- // way to please the XNU.
- const emit = base.options.emit orelse return;
- try emit.directory.handle.copyFile(emit.sub_path, emit.directory.handle, emit.sub_path, .{});
- }
- }
- f.close();
- base.file = null;
- },
- .coff, .elf, .plan9, .wasm => if (base.file) |f| {
+ .coff, .elf, .macho, .plan9, .wasm => if (base.file) |f| {
if (build_options.only_c) unreachable;
if (base.intermediary_basename != null) {
// The file we have open is not the final file that we want to
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index eaf16e4009..368914e1be 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -662,6 +662,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
if (codesig) |*csig| {
try self.writeCodeSignature(comp, csig); // code signing always comes last
+ const emit = self.base.options.emit.?;
+ try invalidateKernelCache(emit.directory.handle, emit.sub_path);
}
if (self.d_sym) |*d_sym| {
@@ -691,6 +693,21 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
self.cold_start = false;
}
+
+/// XNU starting with Big Sur running on arm64 is caching inodes of running binaries.
+/// Any change to the binary will effectively invalidate the kernel's cache
+/// resulting in a SIGKILL on each subsequent run. Since when doing incremental
+/// linking we're modifying a binary in-place, this will end up with the kernel
+/// killing it on every subsequent run. To circumvent it, we will copy the file
+/// into a new inode, remove the original file, and rename the copy to match
+/// the original file. This is super messy, but there doesn't seem any other
+/// way to please the XNU.
+pub fn invalidateKernelCache(dir: std.fs.Dir, sub_path: []const u8) !void {
+ if (comptime builtin.target.isDarwin() and builtin.target.cpu.arch == .aarch64) {
+ try dir.copyFile(sub_path, dir, sub_path, .{});
+ }
+}
+
inline fn conformUuid(out: *[Md5.digest_length]u8) void {
// LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
out[6] = (out[6] & 0x0F) | (3 << 4);
diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig
index a901e4fd4b..a7c7bc41b9 100644
--- a/src/link/MachO/zld.zig
+++ b/src/link/MachO/zld.zig
@@ -4172,6 +4172,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
if (codesig) |*csig| {
try zld.writeCodeSignature(comp, csig); // code signing always comes last
+ try MachO.invalidateKernelCache(directory.handle, zld.options.emit.?.sub_path);
}
}
From c31007bb47a4d1d62917324a33e9a9a6cd1df5a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?=
Date: Fri, 17 Mar 2023 13:16:34 +0200
Subject: [PATCH 007/216] fix copy-paste errors
--sysroot was copy-pasted instead of --maxrss from above. Also, make it less likely in other places for this to be repeated.
I found this by accident when reviewing f51413d2cf0bd87079dace7f6481d2a361a19ea6
---
lib/build_runner.zig | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/lib/build_runner.zig b/lib/build_runner.zig
index 930bccdc0f..00e7c5b65d 100644
--- a/lib/build_runner.zig
+++ b/lib/build_runner.zig
@@ -142,13 +142,13 @@ pub fn main() !void {
};
} else if (mem.eql(u8, arg, "--sysroot")) {
const sysroot = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected argument after --sysroot\n\n", .{});
+ std.debug.print("Expected argument after {s}\n\n", .{arg});
usageAndErr(builder, false, stderr_stream);
};
builder.sysroot = sysroot;
} else if (mem.eql(u8, arg, "--maxrss")) {
const max_rss_text = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected argument after --sysroot\n\n", .{});
+ std.debug.print("Expected argument after {s}\n\n", .{arg});
usageAndErr(builder, false, stderr_stream);
};
// TODO: support shorthand such as "2GiB", "2GB", or "2G"
@@ -160,28 +160,28 @@ pub fn main() !void {
};
} else if (mem.eql(u8, arg, "--search-prefix")) {
const search_prefix = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected argument after --search-prefix\n\n", .{});
+ std.debug.print("Expected argument after {s}\n\n", .{arg});
usageAndErr(builder, false, stderr_stream);
};
builder.addSearchPrefix(search_prefix);
} else if (mem.eql(u8, arg, "--libc")) {
const libc_file = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected argument after --libc\n\n", .{});
+ std.debug.print("Expected argument after {s}\n\n", .{arg});
usageAndErr(builder, false, stderr_stream);
};
builder.libc_file = libc_file;
} else if (mem.eql(u8, arg, "--color")) {
const next_arg = nextArg(args, &arg_idx) orelse {
- std.debug.print("expected [auto|on|off] after --color", .{});
+ std.debug.print("Expected [auto|on|off] after {s}\n\n", .{arg});
usageAndErr(builder, false, stderr_stream);
};
color = std.meta.stringToEnum(Color, next_arg) orelse {
- std.debug.print("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
+ std.debug.print("Expected [auto|on|off] after {s}, found '{s}'\n\n", .{ arg, next_arg });
usageAndErr(builder, false, stderr_stream);
};
} else if (mem.eql(u8, arg, "--zig-lib-dir")) {
builder.zig_lib_dir = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected argument after --zig-lib-dir\n\n", .{});
+ std.debug.print("Expected argument after {s}\n\n", .{arg});
usageAndErr(builder, false, stderr_stream);
};
} else if (mem.eql(u8, arg, "--debug-log")) {
@@ -196,7 +196,7 @@ pub fn main() !void {
builder.debug_compile_errors = true;
} else if (mem.eql(u8, arg, "--glibc-runtimes")) {
builder.glibc_runtimes_dir = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected argument after --glibc-runtimes\n\n", .{});
+ std.debug.print("Expected argument after {s}\n\n", .{arg});
usageAndErr(builder, false, stderr_stream);
};
} else if (mem.eql(u8, arg, "--verbose-link")) {
From ee705e3ac71205142a4457acd2677f7be921d62b Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Fri, 17 Mar 2023 17:54:47 +0100
Subject: [PATCH 008/216] macho+zld: clean up opening and closing of file
descriptors
---
src/link/MachO/zld.zig | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig
index a7c7bc41b9..931352545e 100644
--- a/src/link/MachO/zld.zig
+++ b/src/link/MachO/zld.zig
@@ -3665,16 +3665,17 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
} else {
const page_size = macho_file.page_size;
const sub_path = options.emit.?.sub_path;
- if (macho_file.base.file == null) {
- macho_file.base.file = try directory.handle.createFile(sub_path, .{
- .truncate = true,
- .read = true,
- .mode = link.determineMode(options.*),
- });
- }
+
+ const file = try directory.handle.createFile(sub_path, .{
+ .truncate = true,
+ .read = true,
+ .mode = link.determineMode(options.*),
+ });
+ defer file.close();
+
var zld = Zld{
.gpa = gpa,
- .file = macho_file.base.file.?,
+ .file = file,
.page_size = macho_file.page_size,
.options = options,
};
From bddf138e7285eefb86ef880e1200a929193da40b Mon Sep 17 00:00:00 2001
From: Luuk de Gram
Date: Wed, 8 Mar 2023 06:27:03 +0100
Subject: [PATCH 009/216] wasm-link: fix storing decls in the right segment
When a decl is `undefined` is must be stored in the data segment when
the build mode is safe. For unsafe optimize modes, it must be stored
in the bss segment instead.
For mutable decls where the atom contains all zeroes, it must always
be stored in the bss segment. All other values will result in the
atom being stored in the data segment.
---
src/link/Wasm.zig | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index e998a8d50e..01100add4b 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -2828,22 +2828,31 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
const decl = mod.declPtr(entry.key_ptr.*);
if (decl.isExtern()) continue;
const atom_index = entry.value_ptr.*;
+ const atom = wasm.getAtomPtr(atom_index);
if (decl.ty.zigTypeTag() == .Fn) {
try wasm.parseAtom(atom_index, .function);
} else if (decl.getVariable()) |variable| {
if (!variable.is_mutable) {
try wasm.parseAtom(atom_index, .{ .data = .read_only });
} else if (variable.init.isUndefDeep()) {
- try wasm.parseAtom(atom_index, .{ .data = .uninitialized });
+ // for safe build modes, we store the atom in the data segment,
+ // whereas for unsafe build modes we store it in bss.
+ const is_initialized = wasm.base.options.optimize_mode == .Debug or
+ wasm.base.options.optimize_mode == .ReleaseSafe;
+ try wasm.parseAtom(atom_index, .{ .data = if (is_initialized) .initialized else .uninitialized });
} else {
- try wasm.parseAtom(atom_index, .{ .data = .initialized });
+ // when the decl is all zeroes, we store the atom in the bss segment,
+ // in all other cases it will be in the data segment.
+ const is_zeroes = for (atom.code.items) |byte| {
+ if (byte != 0) break false;
+ } else true;
+ try wasm.parseAtom(atom_index, .{ .data = if (is_zeroes) .uninitialized else .initialized });
}
} else {
try wasm.parseAtom(atom_index, .{ .data = .read_only });
}
// also parse atoms for a decl's locals
- const atom = wasm.getAtomPtr(atom_index);
for (atom.locals.items) |local_atom_index| {
try wasm.parseAtom(local_atom_index, .{ .data = .read_only });
}
From d0fb1ef9625b55cc71b41438265f596a00d63749 Mon Sep 17 00:00:00 2001
From: Luuk de Gram
Date: Wed, 8 Mar 2023 06:42:23 +0100
Subject: [PATCH 010/216] wasm-link: update bss linker test
Updates the linker test to verify the various cases where we must
store the data in the bss segment.
---
test/link/wasm/bss/build.zig | 108 ++++++++++++++++++++++++-----------
test/link/wasm/bss/lib2.zig | 5 ++
2 files changed, 79 insertions(+), 34 deletions(-)
create mode 100644 test/link/wasm/bss/lib2.zig
diff --git a/test/link/wasm/bss/build.zig b/test/link/wasm/bss/build.zig
index bba2e7c602..4a26e78a12 100644
--- a/test/link/wasm/bss/build.zig
+++ b/test/link/wasm/bss/build.zig
@@ -6,38 +6,78 @@ pub fn build(b: *std.Build) void {
const test_step = b.step("test", "Test");
b.default_step = test_step;
- const lib = b.addSharedLibrary(.{
- .name = "lib",
- .root_source_file = .{ .path = "lib.zig" },
- .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
- .optimize = .Debug,
- });
- lib.use_llvm = false;
- lib.use_lld = false;
- lib.strip = false;
- // to make sure the bss segment is emitted, we must import memory
- lib.import_memory = true;
- lib.install();
-
- const check_lib = lib.checkObject();
-
- // since we import memory, make sure it exists with the correct naming
- check_lib.checkStart("Section import");
- check_lib.checkNext("entries 1");
- check_lib.checkNext("module env"); // default module name is "env"
- check_lib.checkNext("name memory"); // as per linker specification
-
- // since we are importing memory, ensure it's not exported
- check_lib.checkNotPresent("Section export");
-
- // validate the name of the stack pointer
- check_lib.checkStart("Section custom");
- check_lib.checkNext("type data_segment");
- check_lib.checkNext("names 2");
- check_lib.checkNext("index 0");
- check_lib.checkNext("name .rodata");
- check_lib.checkNext("index 1"); // bss section always last
- check_lib.checkNext("name .bss");
-
- test_step.dependOn(&check_lib.step);
+ add(b, test_step, .Debug, true);
+ add(b, test_step, .ReleaseFast, false);
+ add(b, test_step, .ReleaseSmall, false);
+ add(b, test_step, .ReleaseSafe, true);
+}
+
+fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.OptimizeMode, is_safe: bool) void {
+ {
+ const lib = b.addSharedLibrary(.{
+ .name = "lib",
+ .root_source_file = .{ .path = "lib.zig" },
+ .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+ .optimize = optimize_mode,
+ });
+ lib.use_llvm = false;
+ lib.use_lld = false;
+ lib.strip = false;
+ // to make sure the bss segment is emitted, we must import memory
+ lib.import_memory = true;
+
+ const check_lib = lib.checkObject();
+
+ // since we import memory, make sure it exists with the correct naming
+ check_lib.checkStart("Section import");
+ check_lib.checkNext("entries 1");
+ check_lib.checkNext("module env"); // default module name is "env"
+ check_lib.checkNext("name memory"); // as per linker specification
+
+ // since we are importing memory, ensure it's not exported
+ check_lib.checkNotPresent("Section export");
+
+ // validate the name of the stack pointer
+ check_lib.checkStart("Section custom");
+ check_lib.checkNext("type data_segment");
+ check_lib.checkNext("names 2");
+ check_lib.checkNext("index 0");
+ check_lib.checkNext("name .rodata");
+ // for safe optimization modes `undefined` is stored in data instead of bss.
+ if (is_safe) {
+ check_lib.checkNext("index 1");
+ check_lib.checkNext("name .data");
+ check_lib.checkNotPresent("name .bss");
+ } else {
+ check_lib.checkNext("index 1"); // bss section always last
+ check_lib.checkNext("name .bss");
+ }
+ test_step.dependOn(&check_lib.step);
+ }
+
+ // verify zero'd declaration is stored in bss for all optimization modes.
+ {
+ const lib = b.addSharedLibrary(.{
+ .name = "lib",
+ .root_source_file = .{ .path = "lib2.zig" },
+ .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+ .optimize = optimize_mode,
+ });
+ lib.use_llvm = false;
+ lib.use_lld = false;
+ lib.strip = false;
+ // to make sure the bss segment is emitted, we must import memory
+ lib.import_memory = true;
+
+ const check_lib = lib.checkObject();
+ check_lib.checkStart("Section custom");
+ check_lib.checkNext("type data_segment");
+ check_lib.checkNext("names 2");
+ check_lib.checkNext("index 0");
+ check_lib.checkNext("name .rodata");
+ check_lib.checkNext("index 1");
+ check_lib.checkNext("name .bss");
+
+ test_step.dependOn(&check_lib.step);
+ }
}
diff --git a/test/link/wasm/bss/lib2.zig b/test/link/wasm/bss/lib2.zig
new file mode 100644
index 0000000000..9f43128880
--- /dev/null
+++ b/test/link/wasm/bss/lib2.zig
@@ -0,0 +1,5 @@
+pub var bss: u32 = 0;
+
+export fn foo() void {
+ _ = bss;
+}
From 46171bf6c89dc2c2b8f155c8511b62e5cd52e3bc Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Sat, 18 Mar 2023 19:05:06 +0100
Subject: [PATCH 011/216] macho+zld: clean up how to interface with link.zig
and openPath()
---
src/link/MachO.zig | 71 ++++++++++++++++++++++++++++------------------
1 file changed, 43 insertions(+), 28 deletions(-)
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 368914e1be..2f76c49667 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -60,6 +60,17 @@ pub const SearchStrategy = enum {
dylibs_first,
};
+/// Mode of operation of the linker.
+pub const Mode = enum {
+ /// Incremental mode will preallocate segments/sections and is compatible with
+ /// watch and HCS modes of operation.
+ incremental,
+ /// Zld mode will link relocatables in a traditional, one-shot
+ /// fashion (default for LLVM backend). It acts as a drop-in replacement for
+ /// LLD.
+ zld,
+};
+
const Section = struct {
header: macho.section_64,
segment_index: u8,
@@ -98,10 +109,7 @@ d_sym: ?DebugSymbols = null,
/// For x86_64 that's 4KB, whereas for aarch64, that's 16KB.
page_size: u16,
-/// Mode of operation: incremental - will preallocate segments/sections and is compatible with
-/// watch and HCS modes of operation; one_shot - will link relocatables in a traditional, one-shot
-/// fashion (default for LLVM backend).
-mode: enum { incremental, one_shot },
+mode: Mode,
dyld_info_cmd: macho.dyld_info_command = .{},
symtab_cmd: macho.symtab_command = .{},
@@ -314,33 +322,42 @@ pub const default_headerpad_size: u32 = 0x1000;
pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
assert(options.target.ofmt == .macho);
- if (options.emit == null or options.module == null) {
+ if (options.emit == null) {
return createEmpty(allocator, options);
}
const emit = options.emit.?;
- const self = try createEmpty(allocator, options);
- errdefer {
- self.base.file = null;
- self.base.destroy();
- }
+ const mode: Mode = mode: {
+ if (options.use_llvm or options.module == null or options.cache_mode == .whole)
+ break :mode .zld;
+ break :mode .incremental;
+ };
+ const sub_path = if (mode == .zld) blk: {
+ if (options.module == null) {
+ // No point in opening a file, we would not write anything to it.
+ // Initialize with empty.
+ return createEmpty(allocator, options);
+ }
+ // Open a temporary object file, not the final output file because we
+ // want to link with LLD.
+ break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{
+ emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
+ });
+ } else emit.sub_path;
+ errdefer if (mode == .zld) allocator.free(sub_path);
- if (build_options.have_llvm and options.use_llvm and options.module != null) {
+ const self = try createEmpty(allocator, options);
+ errdefer self.base.destroy();
+
+ if (mode == .zld) {
// TODO this intermediary_basename isn't enough; in the case of `zig build-exe`,
// we also want to put the intermediary object file in the cache while the
// main emit directory is the cwd.
- self.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{
- emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
- });
+ self.base.intermediary_basename = sub_path;
+ return self;
}
- if (self.base.intermediary_basename != null) switch (options.output_mode) {
- .Obj => return self,
- .Lib => if (options.link_mode == .Static) return self,
- else => {},
- };
-
- const file = try emit.directory.handle.createFile(emit.sub_path, .{
+ const file = try emit.directory.handle.createFile(sub_path, .{
.truncate = false,
.read = true,
.mode = link.determineMode(options),
@@ -348,23 +365,21 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
errdefer file.close();
self.base.file = file;
- if (self.mode == .one_shot) return self;
-
if (!options.strip and options.module != null) {
// Create dSYM bundle.
- log.debug("creating {s}.dSYM bundle", .{emit.sub_path});
+ log.debug("creating {s}.dSYM bundle", .{sub_path});
const d_sym_path = try fmt.allocPrint(
allocator,
"{s}.dSYM" ++ fs.path.sep_str ++ "Contents" ++ fs.path.sep_str ++ "Resources" ++ fs.path.sep_str ++ "DWARF",
- .{emit.sub_path},
+ .{sub_path},
);
defer allocator.free(d_sym_path);
var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{});
defer d_sym_bundle.close();
- const d_sym_file = try d_sym_bundle.createFile(emit.sub_path, .{
+ const d_sym_file = try d_sym_bundle.createFile(sub_path, .{
.truncate = false,
.read = true,
});
@@ -413,7 +428,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
},
.page_size = page_size,
.mode = if (use_llvm or options.module == null or options.cache_mode == .whole)
- .one_shot
+ .zld
else
.incremental,
};
@@ -447,7 +462,7 @@ pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) li
}
switch (self.mode) {
- .one_shot => return zld.linkWithZld(self, comp, prog_node),
+ .zld => return zld.linkWithZld(self, comp, prog_node),
.incremental => return self.flushModule(comp, prog_node),
}
}
From 887abd0f33af15d69c0473e2fb139b490f4ecc8f Mon Sep 17 00:00:00 2001
From: square
Date: Sat, 18 Mar 2023 18:25:52 +0100
Subject: [PATCH 012/216] delete `--prominent-compile-errors` from help
---
lib/build_runner.zig | 1 -
src/main.zig | 1 -
2 files changed, 2 deletions(-)
diff --git a/lib/build_runner.zig b/lib/build_runner.zig
index 00e7c5b65d..bfc6ab77f6 100644
--- a/lib/build_runner.zig
+++ b/lib/build_runner.zig
@@ -949,7 +949,6 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
\\ -l, --list-steps Print available steps
\\ --verbose Print commands before executing them
\\ --color [auto|off|on] Enable or disable colored error messages
- \\ --prominent-compile-errors Output compile errors formatted for a human to read
\\ -fsummary Print the build summary, even on success
\\ -fno-summary Omit the build summary, even on failure
\\ -j Limit concurrent jobs (default is to use all CPU cores)
diff --git a/src/main.zig b/src/main.zig
index e28bdf34cf..db28a5b09b 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -4260,7 +4260,6 @@ pub const usage_build =
\\ --global-cache-dir [path] Override path to global Zig cache directory
\\ --zig-lib-dir [arg] Override path to Zig lib directory
\\ --build-runner [file] Override path to build runner
- \\ --prominent-compile-errors Output compile errors formatted for a human to read
\\ -h, --help Print this help and exit
\\
;
From 49d37e2d179948f526f500043c6ea9ae324e9476 Mon Sep 17 00:00:00 2001
From: Nicolas Sterchele
Date: Sat, 18 Mar 2023 08:37:33 +0100
Subject: [PATCH 013/216] build-step: remove latest LogStep ref
LogStep was removed during the build parallel enhancement made in this
commit 58edefc6d1716c0731ee2fe672ec8d073651aafb
---
lib/std/Build/Step.zig | 2 --
1 file changed, 2 deletions(-)
diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig
index 88580a6cbc..0c05a64b1c 100644
--- a/lib/std/Build/Step.zig
+++ b/lib/std/Build/Step.zig
@@ -79,7 +79,6 @@ pub const Id = enum {
install_artifact,
install_file,
install_dir,
- log,
remove_dir,
fmt,
translate_c,
@@ -99,7 +98,6 @@ pub const Id = enum {
.install_artifact => Build.InstallArtifactStep,
.install_file => Build.InstallFileStep,
.install_dir => Build.InstallDirStep,
- .log => Build.LogStep,
.remove_dir => Build.RemoveDirStep,
.fmt => Build.FmtStep,
.translate_c => Build.TranslateCStep,
From b0024c48841b78a962918cd4ab20459ba6451050 Mon Sep 17 00:00:00 2001
From: Luuk de Gram
Date: Sun, 12 Mar 2023 15:23:58 +0100
Subject: [PATCH 014/216] wasm-linker: basic TLS support
Linker now parses segments with regards to TLS segments. If the name
represents a TLS segment but does not contain the TLS flag, we set it
manually as the object file is created using an older compiler (LLVM).
For now we panic when we find a TLS relocation and implement those
later.
---
src/link/Wasm.zig | 19 +++++++++++++++++++
src/link/Wasm/Atom.zig | 7 +++++++
src/link/Wasm/Object.zig | 6 ++++++
src/link/Wasm/Symbol.zig | 4 ++++
src/link/Wasm/types.zig | 29 +++++++++++++++++++++--------
5 files changed, 57 insertions(+), 8 deletions(-)
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index e998a8d50e..287f880d92 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -894,6 +894,13 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
_ = wasm.resolved_symbols.swapRemove(loc);
}
+
+ if (!wasm.base.options.shared_memory) {
+ if (wasm.undefs.fetchSwapRemove("__tls_base")) |kv| {
+ const loc = try wasm.createSyntheticSymbol("__tls_base", .global);
+ try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
+ }
+ }
}
// Tries to find a global symbol by its name. Returns null when not found,
@@ -2224,6 +2231,18 @@ fn setupMemory(wasm: *Wasm) !void {
while (data_seg_it.next()) |entry| {
const segment = &wasm.segments.items[entry.value_ptr.*];
memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, segment.alignment);
+
+ // set TLS-related symbols
+ if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
+ if (wasm.findGlobalSymbol("__tls_base")) |loc| {
+ const sym = loc.getSymbol(wasm);
+ sym.index = try wasm.globals.append(wasm.base.allocator, wasm.imports.globalCount, .{
+ .global_type = .{ .valtype = .i32_const, .mutable = false },
+ .init = .{ .i32_const = @intCast(i32, memory_ptr) },
+ });
+ }
+ }
+
memory_ptr += segment.size;
segment.offset = offset;
offset += segment.size;
diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig
index 0c9d761f05..7d2f5a6696 100644
--- a/src/link/Wasm/Atom.zig
+++ b/src/link/Wasm/Atom.zig
@@ -126,10 +126,12 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {
.R_WASM_TABLE_INDEX_SLEB,
.R_WASM_TABLE_NUMBER_LEB,
.R_WASM_TYPE_INDEX_LEB,
+ .R_WASM_MEMORY_ADDR_TLS_SLEB,
=> leb.writeUnsignedFixed(5, atom.code.items[reloc.offset..][0..5], @intCast(u32, value)),
.R_WASM_MEMORY_ADDR_LEB64,
.R_WASM_MEMORY_ADDR_SLEB64,
.R_WASM_TABLE_INDEX_SLEB64,
+ .R_WASM_MEMORY_ADDR_TLS_SLEB64,
=> leb.writeUnsignedFixed(10, atom.code.items[reloc.offset..][0..10], value),
}
}
@@ -190,5 +192,10 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa
const rel_value = @intCast(i32, target_atom.offset + offset) + relocation.addend;
return @intCast(u32, rel_value);
},
+ .R_WASM_MEMORY_ADDR_TLS_SLEB,
+ .R_WASM_MEMORY_ADDR_TLS_SLEB64,
+ => {
+ @panic("TODO: Implement TLS relocations");
+ },
}
}
diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig
index 45c9464ec8..4b918064c1 100644
--- a/src/link/Wasm/Object.zig
+++ b/src/link/Wasm/Object.zig
@@ -674,6 +674,12 @@ fn Parser(comptime ReaderType: type) type {
segment.alignment,
segment.flags,
});
+
+ // support legacy object files that specified being TLS by the name instead of the TLS flag.
+ if (!segment.isTLS() and (std.mem.startsWith(u8, segment.name, ".tdata") or std.mem.startsWith(u8, segment.name, ".tbss"))) {
+ // set the flag so we can simply check for the flag in the rest of the linker.
+ segment.flags |= @enumToInt(types.Segment.Flags.WASM_SEG_FLAG_TLS);
+ }
}
parser.object.segment_info = segments;
},
diff --git a/src/link/Wasm/Symbol.zig b/src/link/Wasm/Symbol.zig
index 156b507a32..8a1c4c5fdb 100644
--- a/src/link/Wasm/Symbol.zig
+++ b/src/link/Wasm/Symbol.zig
@@ -90,6 +90,10 @@ pub fn requiresImport(symbol: Symbol) bool {
return true;
}
+pub fn isTLS(symbol: Symbol) bool {
+ return symbol.flags & @enumToInt(Flag.WASM_SYM_TLS) != 0;
+}
+
pub fn hasFlag(symbol: Symbol, flag: Flag) bool {
return symbol.flags & @enumToInt(flag) != 0;
}
diff --git a/src/link/Wasm/types.zig b/src/link/Wasm/types.zig
index 964ba04ba0..a65e352c46 100644
--- a/src/link/Wasm/types.zig
+++ b/src/link/Wasm/types.zig
@@ -38,6 +38,8 @@ pub const Relocation = struct {
R_WASM_TABLE_INDEX_SLEB64 = 18,
R_WASM_TABLE_INDEX_I64 = 19,
R_WASM_TABLE_NUMBER_LEB = 20,
+ R_WASM_MEMORY_ADDR_TLS_SLEB = 21,
+ R_WASM_MEMORY_ADDR_TLS_SLEB64 = 25,
/// Returns true for relocation types where the `addend` field is present.
pub fn addendIsPresent(self: RelocationType) bool {
@@ -125,23 +127,34 @@ pub const Segment = struct {
/// Bitfield containing flags for a segment
flags: u32,
+ pub fn isTLS(segment: Segment) bool {
+ return segment.flags & @enumToInt(Flags.WASM_SEG_FLAG_TLS) != 0;
+ }
+
/// Returns the name as how it will be output into the final object
/// file or binary. When `merge_segments` is true, this will return the
/// short name. i.e. ".rodata". When false, it returns the entire name instead.
- pub fn outputName(self: Segment, merge_segments: bool) []const u8 {
- if (std.mem.startsWith(u8, self.name, ".synthetic")) return ".synthetic"; // always merge
- if (!merge_segments) return self.name;
- if (std.mem.startsWith(u8, self.name, ".rodata.")) {
+ pub fn outputName(segment: Segment, merge_segments: bool) []const u8 {
+ if (segment.isTLS()) {
+ return ".tdata";
+ } else if (!merge_segments) {
+ return segment.name;
+ } else if (std.mem.startsWith(u8, segment.name, ".rodata.")) {
return ".rodata";
- } else if (std.mem.startsWith(u8, self.name, ".text.")) {
+ } else if (std.mem.startsWith(u8, segment.name, ".text.")) {
return ".text";
- } else if (std.mem.startsWith(u8, self.name, ".data.")) {
+ } else if (std.mem.startsWith(u8, segment.name, ".data.")) {
return ".data";
- } else if (std.mem.startsWith(u8, self.name, ".bss.")) {
+ } else if (std.mem.startsWith(u8, segment.name, ".bss.")) {
return ".bss";
}
- return self.name;
+ return segment.name;
}
+
+ pub const Flags = enum(u32) {
+ WASM_SEG_FLAG_STRINGS = 0x1,
+ WASM_SEG_FLAG_TLS = 0x2,
+ };
};
pub const InitFunc = struct {
From 09abd53da701a5ef4db4b81463e2535e192a5eee Mon Sep 17 00:00:00 2001
From: Luuk de Gram
Date: Sun, 12 Mar 2023 16:02:02 +0100
Subject: [PATCH 015/216] wasm-linker: refactor Limits and add flags
Rather than adding the flags "on-demand" during limits writing,
we now properly parse them and store the flags within the limits
itself. This also allows us to store whether we're using shared-
memory or not. Only when the correct flag is set will we set the
max within `Limits` or else we will leave it `undefined`.
---
lib/std/wasm.zig | 16 +++++++++++++++-
src/link/Wasm.zig | 25 +++++++++++++++++--------
src/link/Wasm/Object.zig | 11 ++++++++---
3 files changed, 40 insertions(+), 12 deletions(-)
diff --git a/lib/std/wasm.zig b/lib/std/wasm.zig
index 25a0bb7abf..35d0ba4866 100644
--- a/lib/std/wasm.zig
+++ b/lib/std/wasm.zig
@@ -551,8 +551,22 @@ test "Wasm - valtypes" {
/// Limits classify the size range of resizeable storage associated with memory types and table types.
pub const Limits = struct {
+ flags: u8,
min: u32,
- max: ?u32,
+ max: u32,
+
+ pub const Flags = enum(u8) {
+ WASM_LIMITS_FLAG_HAS_MAX = 0x1,
+ WASM_LIMITS_FLAG_IS_SHARED = 0x2,
+ };
+
+ pub fn hasFlag(limits: Limits, flag: Flags) bool {
+ return limits.flags & @enumToInt(flag) != 0;
+ }
+
+ pub fn setFlag(limits: *Limits, flag: Flags) void {
+ limits.flags |= @enumToInt(flag);
+ }
};
/// Initialization expressions are used to set the initial value on an object
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 287f880d92..50846eecf1 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -111,7 +111,11 @@ functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, std.
/// Output global section
wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{},
/// Memory section
-memories: std.wasm.Memory = .{ .limits = .{ .min = 0, .max = null } },
+memories: std.wasm.Memory = .{ .limits = .{
+ .min = 0,
+ .max = undefined,
+ .flags = 0,
+} },
/// Output table section
tables: std.ArrayListUnmanaged(std.wasm.Table) = .{},
/// Output export section
@@ -396,7 +400,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
const loc = try wasm_bin.createSyntheticSymbol("__indirect_function_table", .table);
const symbol = loc.getSymbol(wasm_bin);
const table: std.wasm.Table = .{
- .limits = .{ .min = 0, .max = null }, // will be overwritten during `mapFunctionTable`
+ .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable`
.reftype = .funcref,
};
if (options.output_mode == .Obj or options.import_table) {
@@ -1524,7 +1528,7 @@ fn mapFunctionTable(wasm: *Wasm) void {
const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
const symbol = sym_loc.getSymbol(wasm);
const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count];
- table.limits = .{ .min = index, .max = index };
+ table.limits = .{ .min = index, .max = index, .flags = 0x1 };
}
}
@@ -2236,8 +2240,9 @@ fn setupMemory(wasm: *Wasm) !void {
if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
if (wasm.findGlobalSymbol("__tls_base")) |loc| {
const sym = loc.getSymbol(wasm);
- sym.index = try wasm.globals.append(wasm.base.allocator, wasm.imports.globalCount, .{
- .global_type = .{ .valtype = .i32_const, .mutable = false },
+ sym.index = @intCast(u32, wasm.wasm_globals.items.len) + wasm.imported_globals_count;
+ try wasm.wasm_globals.append(wasm.base.allocator, .{
+ .global_type = .{ .valtype = .i32, .mutable = false },
.init = .{ .i32_const = @intCast(i32, memory_ptr) },
});
}
@@ -2305,6 +2310,10 @@ fn setupMemory(wasm: *Wasm) !void {
return error.MemoryTooBig;
}
wasm.memories.limits.max = @intCast(u32, max_memory / page_size);
+ wasm.memories.limits.setFlag(.WASM_LIMITS_FLAG_HAS_MAX);
+ if (wasm.base.options.shared_memory) {
+ wasm.memories.limits.setFlag(.WASM_LIMITS_FLAG_IS_SHARED);
+ }
log.debug("Maximum memory pages: {?d}", .{wasm.memories.limits.max});
}
}
@@ -3517,10 +3526,10 @@ fn emitNameSubsection(wasm: *Wasm, section_id: std.wasm.NameSubsection, names: a
}
fn emitLimits(writer: anytype, limits: std.wasm.Limits) !void {
- try leb.writeULEB128(writer, @boolToInt(limits.max != null));
+ try writer.writeByte(limits.flags);
try leb.writeULEB128(writer, limits.min);
- if (limits.max) |max| {
- try leb.writeULEB128(writer, max);
+ if (limits.hasFlag(.WASM_LIMITS_FLAG_HAS_MAX)) {
+ try leb.writeULEB128(writer, limits.max);
}
}
diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig
index 4b918064c1..92336efbf2 100644
--- a/src/link/Wasm/Object.zig
+++ b/src/link/Wasm/Object.zig
@@ -852,12 +852,17 @@ fn readEnum(comptime T: type, reader: anytype) !T {
}
fn readLimits(reader: anytype) !std.wasm.Limits {
- const flags = try readLeb(u1, reader);
+ const flags = try reader.readByte();
const min = try readLeb(u32, reader);
- return std.wasm.Limits{
+ var limits: std.wasm.Limits = .{
+ .flags = flags,
.min = min,
- .max = if (flags == 0) null else try readLeb(u32, reader),
+ .max = undefined,
};
+ if (limits.hasFlag(.WASM_LIMITS_FLAG_HAS_MAX)) {
+ limits.max = try readLeb(u32, reader);
+ }
+ return limits;
}
fn readInit(reader: anytype) !std.wasm.InitExpression {
From fb9d3cd50e9a6d112277d7de158ef857162c01d9 Mon Sep 17 00:00:00 2001
From: Luuk de Gram
Date: Mon, 13 Mar 2023 19:30:33 +0100
Subject: [PATCH 016/216] wasm-linker: feature verifiction for shared-mem
When the user enables shared-memory, we must ensure the linked objects
have the 'atomics' and 'bulk-memory' features allowed.
---
src/link/Wasm.zig | 41 ++++++++++++++++++++++++++++++++++++----
src/link/Wasm/Object.zig | 4 ++--
src/link/Wasm/types.zig | 12 ++++++++----
3 files changed, 47 insertions(+), 10 deletions(-)
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 50846eecf1..5792e57b89 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -795,6 +795,8 @@ fn validateFeatures(
// when false, we fail linking. We only verify this after a loop to catch all invalid features.
var valid_feature_set = true;
+ // will be set to true when there's any TLS segment found in any of the object files
+ var has_tls = false;
// When the user has given an explicit list of features to enable,
// we extract them and insert each into the 'allowed' list.
@@ -825,6 +827,12 @@ fn validateFeatures(
},
}
}
+
+ for (object.segment_info) |segment| {
+ if (segment.isTLS()) {
+ has_tls = true;
+ }
+ }
}
// when we infer the features, we allow each feature found in the 'used' set
@@ -836,7 +844,7 @@ fn validateFeatures(
allowed[used_index] = is_enabled;
emit_features_count.* += @boolToInt(is_enabled);
} else if (is_enabled and !allowed[used_index]) {
- log.err("feature '{s}' not allowed, but used by linked object", .{(@intToEnum(types.Feature.Tag, used_index)).toString()});
+ log.err("feature '{}' not allowed, but used by linked object", .{@intToEnum(types.Feature.Tag, used_index)});
log.err(" defined in '{s}'", .{wasm.objects.items[used_set >> 1].name});
valid_feature_set = false;
}
@@ -846,6 +854,30 @@ fn validateFeatures(
return error.InvalidFeatureSet;
}
+ if (wasm.base.options.shared_memory) {
+ const disallowed_feature = disallowed[@enumToInt(types.Feature.Tag.shared_mem)];
+ if (@truncate(u1, disallowed_feature) != 0) {
+ log.err(
+ "shared-memory is disallowed by '{s}' because it wasn't compiled with 'atomics' and 'bulk-memory' features enabled",
+ .{wasm.objects.items[disallowed_feature >> 1].name},
+ );
+ valid_feature_set = false;
+ }
+
+ for ([_]types.Feature.Tag{ .atomics, .bulk_memory }) |feature| {
+ if (!allowed[@enumToInt(feature)]) {
+ log.err("feature '{}' is not used but is required for shared-memory", .{feature});
+ }
+ }
+ }
+
+ if (has_tls) {
+ for ([_]types.Feature.Tag{ .atomics, .bulk_memory }) |feature| {
+ if (!allowed[@enumToInt(feature)]) {
+ log.err("feature '{}' is not used but is required for thread-local storage", .{feature});
+ }
+ }
+ }
// For each linked object, validate the required and disallowed features
for (wasm.objects.items) |object| {
var object_used_features = [_]bool{false} ** known_features_count;
@@ -854,7 +886,7 @@ fn validateFeatures(
// from here a feature is always used
const disallowed_feature = disallowed[@enumToInt(feature.tag)];
if (@truncate(u1, disallowed_feature) != 0) {
- log.err("feature '{s}' is disallowed, but used by linked object", .{feature.tag.toString()});
+ log.err("feature '{}' is disallowed, but used by linked object", .{feature.tag});
log.err(" disallowed by '{s}'", .{wasm.objects.items[disallowed_feature >> 1].name});
log.err(" used in '{s}'", .{object.name});
valid_feature_set = false;
@@ -867,7 +899,7 @@ fn validateFeatures(
for (required, 0..) |required_feature, feature_index| {
const is_required = @truncate(u1, required_feature) != 0;
if (is_required and !object_used_features[feature_index]) {
- log.err("feature '{s}' is required but not used in linked object", .{(@intToEnum(types.Feature.Tag, feature_index)).toString()});
+ log.err("feature '{}' is required but not used in linked object", .{@intToEnum(types.Feature.Tag, feature_index)});
log.err(" required by '{s}'", .{wasm.objects.items[required_feature >> 1].name});
log.err(" missing in '{s}'", .{object.name});
valid_feature_set = false;
@@ -3432,7 +3464,8 @@ fn emitFeaturesSection(binary_bytes: *std.ArrayList(u8), enabled_features: []con
if (enabled) {
const feature: types.Feature = .{ .prefix = .used, .tag = @intToEnum(types.Feature.Tag, feature_index) };
try leb.writeULEB128(writer, @enumToInt(feature.prefix));
- const string = feature.tag.toString();
+ var buf: [100]u8 = undefined;
+ const string = try std.fmt.bufPrint(&buf, "{}", .{feature.tag});
try leb.writeULEB128(writer, @intCast(u32, string.len));
try writer.writeAll(string);
}
diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig
index 92336efbf2..c2243bdf10 100644
--- a/src/link/Wasm/Object.zig
+++ b/src/link/Wasm/Object.zig
@@ -601,8 +601,8 @@ fn Parser(comptime ReaderType: type) type {
});
for (relocations) |*relocation| {
- const rel_type = try leb.readULEB128(u8, reader);
- const rel_type_enum = @intToEnum(types.Relocation.RelocationType, rel_type);
+ const rel_type = try reader.readByte();
+ const rel_type_enum = std.meta.intToEnum(types.Relocation.RelocationType, rel_type) catch return error.MalformedSection;
relocation.* = .{
.relocation_type = rel_type_enum,
.offset = try leb.readULEB128(u32, reader),
diff --git a/src/link/Wasm/types.zig b/src/link/Wasm/types.zig
index a65e352c46..d19f32b862 100644
--- a/src/link/Wasm/types.zig
+++ b/src/link/Wasm/types.zig
@@ -50,6 +50,8 @@ pub const Relocation = struct {
.R_WASM_MEMORY_ADDR_LEB64,
.R_WASM_MEMORY_ADDR_SLEB64,
.R_WASM_MEMORY_ADDR_I64,
+ .R_WASM_MEMORY_ADDR_TLS_SLEB,
+ .R_WASM_MEMORY_ADDR_TLS_SLEB64,
.R_WASM_FUNCTION_OFFSET_I32,
.R_WASM_SECTION_OFFSET_I32,
=> true,
@@ -218,8 +220,10 @@ pub const Feature = struct {
return @intToEnum(Tag, @enumToInt(feature));
}
- pub fn toString(tag: Tag) []const u8 {
- return switch (tag) {
+ pub fn format(tag: Tag, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void {
+ _ = fmt;
+ _ = opt;
+ try writer.writeAll(switch (tag) {
.atomics => "atomics",
.bulk_memory => "bulk-memory",
.exception_handling => "exception-handling",
@@ -233,7 +237,7 @@ pub const Feature = struct {
.simd128 => "simd128",
.tail_call => "tail-call",
.shared_mem => "shared-mem",
- };
+ });
}
};
@@ -246,7 +250,7 @@ pub const Feature = struct {
pub fn format(feature: Feature, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void {
_ = opt;
_ = fmt;
- try writer.print("{c} {s}", .{ feature.prefix, feature.tag.toString() });
+ try writer.print("{c} {}", .{ feature.prefix, feature.tag });
}
};
From 00af3a79aede098c60eeff38ad72fa399b9d3ccf Mon Sep 17 00:00:00 2001
From: Luuk de Gram
Date: Tue, 14 Mar 2023 19:31:45 +0100
Subject: [PATCH 017/216] wasm-linker: emit 'data count' & segment flags
When linking with shared-memory enabled, we must ensure to emit
the "data count" section as well as emit the correct segment flags
to tell the runtime/loader that each segment is passive. This is
required as we don't emit the offsets for such segments but instead
initialize each segment (for each thread) during runtime.
---
src/link/Wasm.zig | 54 ++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 49 insertions(+), 5 deletions(-)
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 5792e57b89..720e10fe03 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -180,6 +180,16 @@ pub const Segment = struct {
alignment: u32,
size: u32,
offset: u32,
+ flags: u32,
+
+ pub const Flag = enum(u32) {
+ WASM_DATA_SEGMENT_IS_PASSIVE = 0x01,
+ WASM_DATA_SEGMENT_HAS_MEMINDEX = 0x02,
+ };
+
+ pub fn isPassive(segment: Segment) bool {
+ return segment.flags & @enumToInt(Flag.WASM_DATA_SEGMENT_IS_PASSIVE) != 0;
+ }
};
pub const Export = struct {
@@ -1673,6 +1683,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
.alignment = atom.alignment,
.size = atom.size,
.offset = 0,
+ .flags = 0,
});
}
@@ -1711,10 +1722,15 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
break :result index;
} else {
const index = @intCast(u32, wasm.segments.items.len);
+ var flags: u32 = 0;
+ if (wasm.base.options.shared_memory) {
+ flags |= @enumToInt(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
+ }
try wasm.segments.append(wasm.base.allocator, .{
.alignment = atom.alignment,
.size = 0,
.offset = 0,
+ .flags = flags,
});
gop.value_ptr.* = index;
@@ -2365,7 +2381,16 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32
const result = try wasm.data_segments.getOrPut(wasm.base.allocator, segment_info.outputName(merge_segment));
if (!result.found_existing) {
result.value_ptr.* = index;
- try wasm.appendDummySegment();
+ var flags: u32 = 0;
+ if (wasm.base.options.shared_memory) {
+ flags |= @enumToInt(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
+ }
+ try wasm.segments.append(wasm.base.allocator, .{
+ .alignment = 1,
+ .size = 0,
+ .offset = 0,
+ .flags = flags,
+ });
return index;
} else return result.value_ptr.*;
},
@@ -2439,6 +2464,7 @@ fn appendDummySegment(wasm: *Wasm) !void {
.alignment = 1,
.size = 0,
.offset = 0,
+ .flags = 0,
});
}
@@ -3147,6 +3173,19 @@ fn writeToFile(
section_count += 1;
}
+ // When the shared-memory option is enabled, we *must* emit the 'data count' section.
+ const data_segments_count = wasm.data_segments.count() - @boolToInt(wasm.data_segments.contains(".bss") and import_memory);
+ if (data_segments_count != 0 and wasm.base.options.shared_memory) {
+ const header_offset = try reserveVecSectionHeader(&binary_bytes);
+ try writeVecSectionHeader(
+ binary_bytes.items,
+ header_offset,
+ .data_count,
+ @intCast(u32, binary_bytes.items.len - header_offset - header_size),
+ @intCast(u32, data_segments_count),
+ );
+ }
+
// Code section
var code_section_size: u32 = 0;
if (wasm.code_section_index) |code_index| {
@@ -3197,7 +3236,7 @@ fn writeToFile(
}
// Data section
- if (wasm.data_segments.count() != 0) {
+ if (data_segments_count != 0) {
const header_offset = try reserveVecSectionHeader(&binary_bytes);
var it = wasm.data_segments.iterator();
@@ -3212,10 +3251,15 @@ fn writeToFile(
segment_count += 1;
var atom_index = wasm.atoms.get(segment_index).?;
- // flag and index to memory section (currently, there can only be 1 memory section in wasm)
- try leb.writeULEB128(binary_writer, @as(u32, 0));
+ try leb.writeULEB128(binary_writer, segment.flags);
+ if (segment.flags & @enumToInt(Wasm.Segment.Flag.WASM_DATA_SEGMENT_HAS_MEMINDEX) != 0) {
+ try leb.writeULEB128(binary_writer, @as(u32, 0)); // memory is always index 0 as we only have 1 memory entry
+ }
+ // when a segment is passive, it's initialized during runtime.
+ if (!segment.isPassive()) {
+ try emitInit(binary_writer, .{ .i32_const = @bitCast(i32, segment.offset) });
+ }
// offset into data section
- try emitInit(binary_writer, .{ .i32_const = @bitCast(i32, segment.offset) });
try leb.writeULEB128(binary_writer, segment.size);
// fill in the offset table and the data segments
From ff28c8b60080b24ae7d5e9d485b6aa47e8c8de9c Mon Sep 17 00:00:00 2001
From: Luuk de Gram
Date: Tue, 14 Mar 2023 19:51:30 +0100
Subject: [PATCH 018/216] wasm-linker: create TLS symbols
Initialize TLS symbols when shared-memory is enabled. Those symbols
will be called by synthetic functions created by the linker. (TODO).
---
src/link/Wasm.zig | 44 ++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 720e10fe03..d66facb912 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -443,6 +443,30 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
// at the end during `initializeCallCtorsFunction`.
}
+ // shared-memory symbols for TLS support
+ if (wasm_bin.base.options.shared_memory) {
+ {
+ const loc = try wasm_bin.createSyntheticSymbol("__tls_base", .global);
+ const symbol = loc.getSymbol(wasm_bin);
+ symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
+ }
+ {
+ const loc = try wasm_bin.createSyntheticSymbol("__tls_size", .global);
+ const symbol = loc.getSymbol(wasm_bin);
+ symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
+ }
+ {
+ const loc = try wasm_bin.createSyntheticSymbol("__tls_align", .global);
+ const symbol = loc.getSymbol(wasm_bin);
+ symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
+ }
+ {
+ const loc = try wasm_bin.createSyntheticSymbol("__wasm_tls_init", .function);
+ const symbol = loc.getSymbol(wasm_bin);
+ symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
+ }
+ }
+
// if (!options.strip and options.module != null) {
// wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, options.target);
// try wasm_bin.initDebugSections();
@@ -2286,12 +2310,28 @@ fn setupMemory(wasm: *Wasm) !void {
// set TLS-related symbols
if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
- if (wasm.findGlobalSymbol("__tls_base")) |loc| {
+ if (wasm.findGlobalSymbol("__tls_size")) |loc| {
const sym = loc.getSymbol(wasm);
sym.index = @intCast(u32, wasm.wasm_globals.items.len) + wasm.imported_globals_count;
try wasm.wasm_globals.append(wasm.base.allocator, .{
.global_type = .{ .valtype = .i32, .mutable = false },
- .init = .{ .i32_const = @intCast(i32, memory_ptr) },
+ .init = .{ .i32_const = @intCast(i32, segment.size) },
+ });
+ }
+ if (wasm.findGlobalSymbol("__tls_align")) |loc| {
+ const sym = loc.getSymbol(wasm);
+ sym.index = @intCast(u32, wasm.wasm_globals.items.len) + wasm.imported_globals_count;
+ try wasm.wasm_globals.append(wasm.base.allocator, .{
+ .global_type = .{ .valtype = .i32, .mutable = false },
+ .init = .{ .i32_const = @intCast(i32, segment.alignment) },
+ });
+ }
+ if (wasm.findGlobalSymbol("__tls_base")) |loc| {
+ const sym = loc.getSymbol(wasm);
+ sym.index = @intCast(u32, wasm.wasm_globals.items.len) + wasm.imported_globals_count;
+ try wasm.wasm_globals.append(wasm.base.allocator, .{
+ .global_type = .{ .valtype = .i32, .mutable = wasm.base.options.shared_memory },
+ .init = .{ .i32_const = if (wasm.base.options.shared_memory) @as(u32, 0) else @intCast(i32, memory_ptr) },
});
}
}
From 9d13c2257dcae11d9bc69035e55c33a7dda14a2b Mon Sep 17 00:00:00 2001
From: Luuk de Gram
Date: Wed, 15 Mar 2023 19:27:55 +0100
Subject: [PATCH 019/216] wasm-linker: implement TLS initialization function
Implements the TLS initialization function. This is a synthetic function
created by the linker. This will only be created when shared-memory is
enabled. This function will be called during thread creation, if there's
any TLS symbols, which will initialize the TLS segment using the
bulk-memory feature.
---
src/link/Wasm.zig | 75 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 72 insertions(+), 3 deletions(-)
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index d66facb912..5d4ab2961b 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -1990,10 +1990,23 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
try writer.writeByte(std.wasm.opcode(.end));
}
- const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?;
+ try wasm.createSyntheticFunction(
+ "__wasm_call_ctors",
+ std.wasm.Type{ .params = &.{}, .returns = &.{} },
+ &function_body,
+ );
+}
+
+fn createSyntheticFunction(
+ wasm: *Wasm,
+ symbol_name: []const u8,
+ func_ty: std.wasm.Type,
+ function_body: *std.ArrayList(u8),
+) !void {
+ const loc = wasm.findGlobalSymbol(symbol_name) orelse
+ try wasm.createSyntheticSymbol(symbol_name, .function);
const symbol = loc.getSymbol(wasm);
- // create type (() -> nil) as we do not have any parameters or return value.
- const ty_index = try wasm.putOrGetFuncType(.{ .params = &[_]std.wasm.Valtype{}, .returns = &[_]std.wasm.Valtype{} });
+ const ty_index = try wasm.putOrGetFuncType(func_ty);
// create function with above type
const func_index = wasm.imported_functions_count + @intCast(u32, wasm.functions.count());
try wasm.functions.putNoClobber(
@@ -2025,6 +2038,60 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
atom.offset = prev_atom.offset + prev_atom.size;
}
+fn initializeTLSFunction(wasm: *Wasm) !void {
+ if (!wasm.base.options.shared_memory) return;
+
+ var function_body = std.ArrayList(u8).init(wasm.base.allocator);
+ defer function_body.deinit();
+ const writer = function_body.writer();
+
+ // locals
+ try writer.writeByte(0);
+
+ // If there's a TLS segment, initialize it during runtime using the bulk-memory feature
+ if (wasm.data_segments.getIndex(".tdata")) |data_index| {
+ const segment_index = wasm.data_segments.entries.items(.value)[data_index];
+ const segment = wasm.segments.items[segment_index];
+
+ const param_local: u32 = 0;
+
+ try writer.writeByte(std.wasm.opcode(.local_get));
+ try leb.writeULEB128(writer, param_local);
+
+ const tls_base_loc = wasm.findGlobalSymbol("__tls_base").?;
+ try writer.writeByte(std.wasm.opcode(.global_get));
+ try leb.writeULEB128(writer, tls_base_loc.getSymbol(wasm).index);
+
+ // load stack values for the bulk-memory operation
+ {
+ try writer.writeByte(std.wasm.opcode(.local_get));
+ try leb.writeULEB128(writer, param_local);
+
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, @as(u32, 0)); //segment offset
+
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, @as(u32, segment.size)); //segment offset
+ }
+
+ // perform the bulk-memory operation to initialize the data segment
+ try writer.writeByte(std.wasm.opcode(.prefixed));
+ try leb.writeULEB128(writer, @enumToInt(std.wasm.PrefixedOpcode.memory_init));
+ // segment immediate
+ try leb.writeULEB128(writer, @intCast(u32, data_index));
+ // memory index immediate (always 0)
+ try leb.writeULEB128(writer, @as(u32, 0));
+ }
+
+ try writer.writeByte(std.wasm.opcode(.end));
+
+ try wasm.createSyntheticFunction(
+ "__wasm_init_tls",
+ std.wasm.Type{ .params = &.{.i32}, .returns = &.{} },
+ &function_body,
+ );
+}
+
fn setupImports(wasm: *Wasm) !void {
log.debug("Merging imports", .{});
var discarded_it = wasm.discarded.keyIterator();
@@ -2872,6 +2939,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
try wasm.mergeSections();
try wasm.mergeTypes();
try wasm.initializeCallCtorsFunction();
+ try wasm.initializeTLSFunction();
try wasm.setupExports();
try wasm.writeToFile(enabled_features, emit_features_count, arena);
@@ -2991,6 +3059,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
try wasm.mergeSections();
try wasm.mergeTypes();
try wasm.initializeCallCtorsFunction();
+ try wasm.initializeTLSFunction();
try wasm.setupExports();
try wasm.writeToFile(enabled_features, emit_features_count, arena);
}
From 9fce1df4cdab57951137c0da2b44fbe6da2442f2 Mon Sep 17 00:00:00 2001
From: Luuk de Gram
Date: Fri, 17 Mar 2023 06:32:37 +0100
Subject: [PATCH 020/216] wasm-linker: implement runtime TLS relocations
---
src/link/Wasm.zig | 63 ++++++++++++++++++++++++++++++++++++++++
src/link/Wasm/Object.zig | 28 ++++++++++++++----
src/link/Wasm/types.zig | 12 --------
3 files changed, 86 insertions(+), 17 deletions(-)
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 5d4ab2961b..eaaabcc89a 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -139,6 +139,8 @@ archives: std.ArrayListUnmanaged(Archive) = .{},
/// A map of global names (read: offset into string table) to their symbol location
globals: std.AutoHashMapUnmanaged(u32, SymbolLoc) = .{},
+/// The list of GOT symbols and their location
+got_symbols: std.ArrayListUnmanaged(SymbolLoc) = .{},
/// Maps discarded symbols and their positions to the location of the symbol
/// it was resolved to
discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .{},
@@ -635,6 +637,15 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
return true;
}
+fn requiresTLSReloc(wasm: *const Wasm) bool {
+ for (wasm.got_symbols.items) |loc| {
+ if (loc.getSymbol(wasm).isTLS()) {
+ return true;
+ }
+ }
+ return false;
+}
+
fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
const object: Object = wasm.objects.items[object_index];
log.debug("Resolving symbols in object: '{s}'", .{object.name});
@@ -813,6 +824,48 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {
}
}
+fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
+ // When we have TLS GOT entries and shared memory is enabled,
+ // we must perform runtime relocations or else we don't create the function.
+ if (!wasm.base.options.shared_memory or !wasm.requiresTLSReloc()) {
+ return;
+ }
+
+ // const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs");
+ var function_body = std.ArrayList(u8).init(wasm.base.allocator);
+ defer function_body.deinit();
+ const writer = function_body.writer();
+
+ // locals (we have none)
+ try writer.writeByte(0);
+ for (wasm.got_symbols.items, 0..) |got_loc, got_index| {
+ const sym: *Symbol = got_loc.getSymbol(wasm);
+ if (!sym.isTLS()) continue; // only relocate TLS symbols
+ if (sym.tag == .data and sym.isDefined()) {
+ // get __tls_base
+ try writer.writeByte(std.wasm.opcode(.global_get));
+ try leb.writeULEB128(writer, wasm.findGlobalSymbol("__tls_base").?.getSymbol(wasm).index);
+
+ // add the virtual address of the symbol
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, sym.virtual_address);
+ } else if (sym.tag == .function) {
+ @panic("TODO: relocate GOT entry of function");
+ } else continue;
+
+ try writer.writeByte(std.wasm.opcode(.i32_add));
+ try writer.writeByte(std.wasm.opcode(.global_set));
+ try leb.writeULEB128(writer, wasm.imported_globals_count + @intCast(u32, wasm.wasm_globals.items.len + got_index));
+ }
+ try writer.writeByte(std.wasm.opcode(.end));
+
+ try wasm.createSyntheticFunction(
+ "__wasm_apply_global_tls_relocs",
+ std.wasm.Type{ .params = &.{}, .returns = &.{} },
+ &function_body,
+ );
+}
+
fn validateFeatures(
wasm: *const Wasm,
to_emit: *[@typeInfo(types.Feature.Tag).Enum.fields.len]bool,
@@ -2083,6 +2136,14 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
try leb.writeULEB128(writer, @as(u32, 0));
}
+ // If we have to perform any TLS relocations, call the corresponding function
+ // which performs all runtime TLS relocations. This is a synthetic function,
+ // generated by the linker.
+ if (wasm.findGlobalSymbol("__wasm_apply_global_tls_relocs")) |loc| {
+ try writer.writeByte(std.wasm.opcode(.call));
+ try leb.writeULEB128(writer, loc.getSymbol(wasm).index);
+ }
+
try writer.writeByte(std.wasm.opcode(.end));
try wasm.createSyntheticFunction(
@@ -2939,6 +3000,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
try wasm.mergeSections();
try wasm.mergeTypes();
try wasm.initializeCallCtorsFunction();
+ try wasm.setupTLSRelocationsFunction();
try wasm.initializeTLSFunction();
try wasm.setupExports();
try wasm.writeToFile(enabled_features, emit_features_count, arena);
@@ -3059,6 +3121,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
try wasm.mergeSections();
try wasm.mergeTypes();
try wasm.initializeCallCtorsFunction();
+ try wasm.setupTLSRelocationsFunction();
try wasm.initializeTLSFunction();
try wasm.setupExports();
try wasm.writeToFile(enabled_features, emit_features_count, arena);
diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig
index c2243bdf10..363648971a 100644
--- a/src/link/Wasm/Object.zig
+++ b/src/link/Wasm/Object.zig
@@ -930,11 +930,29 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b
reloc.offset -= relocatable_data.offset;
try atom.relocs.append(gpa, reloc);
- if (relocation.isTableIndex()) {
- try wasm_bin.function_table.put(gpa, .{
- .file = object_index,
- .index = relocation.index,
- }, 0);
+ switch (relocation.relocation_type) {
+ .R_WASM_TABLE_INDEX_I32,
+ .R_WASM_TABLE_INDEX_I64,
+ .R_WASM_TABLE_INDEX_SLEB,
+ .R_WASM_TABLE_INDEX_SLEB64,
+ => {
+ try wasm_bin.function_table.put(gpa, .{
+ .file = object_index,
+ .index = relocation.index,
+ }, 0);
+ },
+ .R_WASM_GLOBAL_INDEX_I32,
+ .R_WASM_GLOBAL_INDEX_LEB,
+ => {
+ const sym = object.symtable[relocation.index];
+ if (sym.tag != .global) {
+ try wasm_bin.got_symbols.append(
+ wasm_bin.base.allocator,
+ .{ .file = object_index, .index = relocation.index },
+ );
+ }
+ },
+ else => {},
}
}
}
diff --git a/src/link/Wasm/types.zig b/src/link/Wasm/types.zig
index d19f32b862..801c25e9d9 100644
--- a/src/link/Wasm/types.zig
+++ b/src/link/Wasm/types.zig
@@ -71,18 +71,6 @@ pub const Relocation = struct {
};
}
- /// Returns true when the relocation represents a table index relocatable
- pub fn isTableIndex(self: Relocation) bool {
- return switch (self.relocation_type) {
- .R_WASM_TABLE_INDEX_I32,
- .R_WASM_TABLE_INDEX_I64,
- .R_WASM_TABLE_INDEX_SLEB,
- .R_WASM_TABLE_INDEX_SLEB64,
- => true,
- else => false,
- };
- }
-
pub fn format(self: Relocation, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
_ = fmt;
_ = options;
From 09d6938df9246bac20e84f5512743e96bccdfa3d Mon Sep 17 00:00:00 2001
From: Luuk de Gram
Date: Fri, 17 Mar 2023 07:09:01 +0100
Subject: [PATCH 021/216] wasm: add atomics opcodes and refactoring
This adds the atomic opcodes for the Threads proposal to the
WebAssembly specification: https://github.com/WebAssembly/threads
PrefixedOpcode has been renamed to MiscOpcode as there's multiple
types of prefixed opcodes. This naming is similar to other tools
such as LLVM. As we now use the 0xFE prefix, we moved the
function_index MIR instruction as it was occupying the same value.
This commit includes renaming all related opcodes.
---
lib/std/wasm.zig | 92 ++++++++++++++++++++++++++++++++++++++-
src/arch/wasm/CodeGen.zig | 14 +++---
src/arch/wasm/Emit.zig | 18 +++++---
src/arch/wasm/Mir.zig | 23 ++++++----
src/link/Wasm.zig | 4 +-
5 files changed, 126 insertions(+), 25 deletions(-)
diff --git a/lib/std/wasm.zig b/lib/std/wasm.zig
index 35d0ba4866..d54e998b67 100644
--- a/lib/std/wasm.zig
+++ b/lib/std/wasm.zig
@@ -189,7 +189,9 @@ pub const Opcode = enum(u8) {
i64_extend16_s = 0xC3,
i64_extend32_s = 0xC4,
- prefixed = 0xFC,
+ misc_prefix = 0xFC,
+ simd_prefix = 0xFD,
+ atomics_prefix = 0xFE,
_,
};
@@ -217,7 +219,7 @@ test "Wasm - opcodes" {
/// Opcodes that require a prefix `0xFC`
/// Each opcode represents a varuint32, meaning
/// they are encoded as leb128 in binary.
-pub const PrefixedOpcode = enum(u32) {
+pub const MiscOpcode = enum(u32) {
i32_trunc_sat_f32_s = 0x00,
i32_trunc_sat_f32_u = 0x01,
i32_trunc_sat_f64_s = 0x02,
@@ -239,6 +241,12 @@ pub const PrefixedOpcode = enum(u32) {
_,
};
+/// Returns the integer value of an `MiscOpcode`. Used by the Zig compiler
+/// to write instructions to the wasm binary file
+pub fn miscOpcode(op: MiscOpcode) u32 {
+ return @enumToInt(op);
+}
+
/// Simd opcodes that require a prefix `0xFD`.
/// Each opcode represents a varuint32, meaning
/// they are encoded as leb128 in binary.
@@ -510,6 +518,86 @@ pub fn simdOpcode(op: SimdOpcode) u32 {
return @enumToInt(op);
}
+/// Simd opcodes that require a prefix `0xFE`.
+/// Each opcode represents a varuint32, meaning
+/// they are encoded as leb128 in binary.
+pub const AtomicsOpcode = enum(u32) {
+ memory_atomic_notify = 0x00,
+ memory_atomic_wait32 = 0x01,
+ memory_atomic_wait64 = 0x02,
+ atomic_fence = 0x03,
+ i32_atomic_load = 0x10,
+ i64_atomic_load = 0x11,
+ i32_atomic_load8_u = 0x12,
+ i32_atomic_load16_u = 0x13,
+ i64_atomic_load8_u = 0x14,
+ i64_atomic_load16_u = 0x15,
+ i64_atomic_load32_u = 0x16,
+ i32_atomic_store = 0x17,
+ i64_atomic_store = 0x18,
+ i32_atomic_store8 = 0x19,
+ i32_atomic_store16 = 0x1A,
+ i64_atomic_store8 = 0x1B,
+ i64_atomic_store16 = 0x1C,
+ i64_atomic_store32 = 0x1D,
+ i32_atomic_rmw_add = 0x1E,
+ i64_atomic_rmw_add = 0x1F,
+ i32_atomic_rmw8_add_u = 0x20,
+ i32_atomic_rmw16_add_u = 0x21,
+ i64_atomic_rmw8_add_u = 0x22,
+ i64_atomic_rmw16_add_u = 0x23,
+ i64_atomic_rmw32_add_u = 0x24,
+ i32_atomic_rmw_sub = 0x25,
+ i64_atomic_rmw_sub = 0x26,
+ i32_atomic_rmw8_sub_u = 0x27A,
+ i32_atomic_rmw16_sub_u = 0x28A,
+ i64_atomic_rmw8_sub_u = 0x29A,
+ i64_atomic_rmw16_sub_u = 0x2A,
+ i64_atomic_rmw32_sub_u = 0x2B,
+ i32_atomic_rmw_and = 0x2C,
+ i64_atomic_rmw_and = 0x2D,
+ i32_atomic_rmw8_and_u = 0x2E,
+ i32_atomic_rmw16_and_u = 0x2F,
+ i64_atomic_rmw8_and_u = 0x30,
+ i64_atomic_rmw16_and_u = 0x31,
+ i64_atomic_rmw32_and_u = 0x32,
+ i32_atomic_rmw_or = 0x33,
+ i64_atomic_rmw_or = 0x34,
+ i32_atomic_rmw8_or_u = 0x35,
+ i32_atomic_rmw16_or_u = 0x36,
+ i64_atomic_rmw8_or_u = 0x37,
+ i64_atomic_rmw16_or_u = 0x38,
+ i64_atomic_rmw32_or_u = 0x39,
+ i32_atomic_rmw_xor = 0x3A,
+ i64_atomic_rmw_xor = 0x3B,
+ i32_atomic_rmw8_xor_u = 0x3C,
+ i32_atomic_rmw16_xor_u = 0x3D,
+ i64_atomic_rmw8_xor_u = 0x3E,
+ i64_atomic_rmw16_xor_u = 0x3F,
+ i64_atomic_rmw32_xor_u = 0x40,
+ i32_atomic_rmw_xchg = 0x41,
+ i64_atomic_rmw_xchg = 0x42,
+ i32_atomic_rmw8_xchg_u = 0x43,
+ i32_atomic_rmw16_xchg_u = 0x44,
+ i64_atomic_rmw8_xchg_u = 0x45,
+ i64_atomic_rmw16_xchg_u = 0x46,
+ i64_atomic_rmw32_xchg_u = 0x47,
+
+ i32_atomic_rmw_cmpxchg = 0x48,
+ i64_atomic_rmw_cmpxchg = 0x49,
+ i32_atomic_rmw8_cmpxchg_u = 0x4A,
+ i32_atomic_rmw16_cmpxchg_u = 0x4B,
+ i64_atomic_rmw8_cmpxchg_u = 0x4C,
+ i64_atomic_rmw16_cmpxchg_u = 0x4D,
+ i64_atomic_rmw32_cmpxchg_u = 0x4E,
+};
+
+/// Returns the integer value of an `AtomicsOpcode`. Used by the Zig compiler
+/// to write instructions to the wasm binary file
+pub fn atomicsOpcode(op: AtomicsOpcode) u32 {
+ return @enumToInt(op);
+}
+
/// Enum representing all Wasm value types as per spec:
/// https://webassembly.github.io/spec/core/binary/types.html
pub const Valtype = enum(u8) {
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index e79129ddb8..c05f07a602 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -895,10 +895,10 @@ fn addTag(func: *CodeGen, tag: Mir.Inst.Tag) error{OutOfMemory}!void {
try func.addInst(.{ .tag = tag, .data = .{ .tag = {} } });
}
-fn addExtended(func: *CodeGen, opcode: wasm.PrefixedOpcode) error{OutOfMemory}!void {
+fn addExtended(func: *CodeGen, opcode: wasm.MiscOpcode) error{OutOfMemory}!void {
const extra_index = @intCast(u32, func.mir_extra.items.len);
try func.mir_extra.append(func.gpa, @enumToInt(opcode));
- try func.addInst(.{ .tag = .extended, .data = .{ .payload = extra_index } });
+ try func.addInst(.{ .tag = .misc_prefix, .data = .{ .payload = extra_index } });
}
fn addLabel(func: *CodeGen, tag: Mir.Inst.Tag, label: u32) error{OutOfMemory}!void {
@@ -925,7 +925,7 @@ fn addImm128(func: *CodeGen, index: u32) error{OutOfMemory}!void {
try func.mir_extra.ensureUnusedCapacity(func.gpa, 5);
func.mir_extra.appendAssumeCapacity(std.wasm.simdOpcode(.v128_const));
func.mir_extra.appendSliceAssumeCapacity(@alignCast(4, mem.bytesAsSlice(u32, &simd_values)));
- try func.addInst(.{ .tag = .simd, .data = .{ .payload = extra_index } });
+ try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
}
fn addFloat64(func: *CodeGen, float: f64) error{OutOfMemory}!void {
@@ -2310,7 +2310,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
offset + lhs.offset(),
ty.abiAlignment(func.target),
});
- return func.addInst(.{ .tag = .simd, .data = .{ .payload = extra_index } });
+ return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
},
},
.Pointer => {
@@ -2420,7 +2420,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
offset + operand.offset(),
ty.abiAlignment(func.target),
});
- try func.addInst(.{ .tag = .simd, .data = .{ .payload = extra_index } });
+ try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
return WValue{ .stack = {} };
}
@@ -4477,7 +4477,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
operand.offset(),
elem_ty.abiAlignment(func.target),
});
- try func.addInst(.{ .tag = .simd, .data = .{ .payload = extra_index } });
+ try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
try func.addLabel(.local_set, result.local.value);
return func.finishAir(inst, result, &.{ty_op.operand});
},
@@ -4493,7 +4493,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
try func.emitWValue(operand);
const extra_index = @intCast(u32, func.mir_extra.items.len);
try func.mir_extra.append(func.gpa, opcode);
- try func.addInst(.{ .tag = .simd, .data = .{ .payload = extra_index } });
+ try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
try func.addLabel(.local_set, result.local.value);
return func.finishAir(inst, result, &.{ty_op.operand});
},
diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig
index 7d44d3622f..5982d3b48c 100644
--- a/src/arch/wasm/Emit.zig
+++ b/src/arch/wasm/Emit.zig
@@ -239,8 +239,9 @@ pub fn emitMir(emit: *Emit) InnerError!void {
.i64_clz => try emit.emitTag(tag),
.i64_ctz => try emit.emitTag(tag),
- .extended => try emit.emitExtended(inst),
- .simd => try emit.emitSimd(inst),
+ .misc_prefix => try emit.emitExtended(inst),
+ .simd_prefix => try emit.emitSimd(inst),
+ .atomics_prefix => try emit.emitAtomic(inst),
}
}
}
@@ -433,9 +434,9 @@ fn emitExtended(emit: *Emit, inst: Mir.Inst.Index) !void {
const extra_index = emit.mir.instructions.items(.data)[inst].payload;
const opcode = emit.mir.extra[extra_index];
const writer = emit.code.writer();
- try emit.code.append(0xFC);
+ try emit.code.append(std.wasm.opcode(.misc_prefix));
try leb128.writeULEB128(writer, opcode);
- switch (@intToEnum(std.wasm.PrefixedOpcode, opcode)) {
+ switch (@intToEnum(std.wasm.MiscOpcode, opcode)) {
// bulk-memory opcodes
.data_drop => {
const segment = emit.mir.extra[extra_index + 1];
@@ -472,7 +473,7 @@ fn emitSimd(emit: *Emit, inst: Mir.Inst.Index) !void {
const extra_index = emit.mir.instructions.items(.data)[inst].payload;
const opcode = emit.mir.extra[extra_index];
const writer = emit.code.writer();
- try emit.code.append(0xFD);
+ try emit.code.append(std.wasm.opcode(.simd_prefix));
try leb128.writeULEB128(writer, opcode);
switch (@intToEnum(std.wasm.SimdOpcode, opcode)) {
.v128_store,
@@ -496,10 +497,15 @@ fn emitSimd(emit: *Emit, inst: Mir.Inst.Index) !void {
.f32x4_splat,
.f64x2_splat,
=> {}, // opcode already written
- else => |tag| return emit.fail("TODO: Implement simd instruction: {s}\n", .{@tagName(tag)}),
+ else => |tag| return emit.fail("TODO: Implement simd instruction: {s}", .{@tagName(tag)}),
}
}
+fn emitAtomic(emit: *Emit, inst: Mir.Inst.Index) !void {
+ _ = inst;
+ return emit.fail("TODO: Implement atomics instructions", .{});
+}
+
fn emitMemFill(emit: *Emit) !void {
try emit.code.append(0xFC);
try emit.code.append(0x0B);
diff --git a/src/arch/wasm/Mir.zig b/src/arch/wasm/Mir.zig
index 2d59c09e18..4c550d8637 100644
--- a/src/arch/wasm/Mir.zig
+++ b/src/arch/wasm/Mir.zig
@@ -87,6 +87,13 @@ pub const Inst = struct {
///
/// Uses `label`
call_indirect = 0x11,
+ /// Contains a symbol to a function pointer
+ /// uses `label`
+ ///
+ /// Note: This uses `0x16` as value which is reserved by the WebAssembly
+ /// specification but unused, meaning we must update this if the specification were to
+ /// use this value.
+ function_index = 0x16,
/// Pops three values from the stack and pushes
/// the first or second value dependent on the third value.
/// Uses `tag`
@@ -510,24 +517,24 @@ pub const Inst = struct {
i64_extend16_s = 0xC3,
/// Uses `tag`
i64_extend32_s = 0xC4,
- /// The instruction consists of an extension opcode.
+ /// The instruction consists of a prefixed opcode.
/// The prefixed opcode can be found at payload's index.
///
/// The `data` field depends on the extension instruction and
/// may contain additional data.
- extended = 0xFC,
+ misc_prefix = 0xFC,
/// The instruction consists of a simd opcode.
/// The actual simd-opcode is found at payload's index.
///
/// The `data` field depends on the simd instruction and
/// may contain additional data.
- simd = 0xFD,
- /// Contains a symbol to a function pointer
- /// uses `label`
+ simd_prefix = 0xFD,
+ /// The instruction consists of an atomics opcode.
+ /// The actual atomics-opcode is found at payload's index.
///
- /// Note: This uses `0xFE` as value as it is unused and not reserved
- /// by the wasm specification, making it safe to use.
- function_index = 0xFE,
+ /// The `data` field depends on the atomics instruction and
+ /// may contain additional data.
+ atomics_prefix = 0xFE,
/// Contains a symbol to a memory address
/// Uses `label`
///
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index eaaabcc89a..5175f760d1 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -2128,8 +2128,8 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
}
// perform the bulk-memory operation to initialize the data segment
- try writer.writeByte(std.wasm.opcode(.prefixed));
- try leb.writeULEB128(writer, @enumToInt(std.wasm.PrefixedOpcode.memory_init));
+ try writer.writeByte(std.wasm.opcode(.misc_prefix));
+ try leb.writeULEB128(writer, std.wasm.miscOpcode(.memory_init));
// segment immediate
try leb.writeULEB128(writer, @intCast(u32, data_index));
// memory index immediate (always 0)
From 4e0d7154b1a701b906f3d9c5401dc0109253971f Mon Sep 17 00:00:00 2001
From: Luuk de Gram
Date: Sat, 18 Mar 2023 16:02:30 +0100
Subject: [PATCH 022/216] wasm-linker: implement __wasm_init_memory & flag
Implements the __wasm_init_memory and __wasm_init_memory_flag synthetic
function and symbol.
The former will initialize all passive segments during runtime. For the
bss section we will fill it with zeroes, whereas the other segments
will simply be initialized only.
The latter stores the offset into the linear data section, after all
heap memory that is part of the Wasm module. Any memory initialized
at runtime starts from this offset.
---
src/link/Wasm.zig | 203 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 203 insertions(+)
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 5175f760d1..31169b5de1 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -192,6 +192,14 @@ pub const Segment = struct {
pub fn isPassive(segment: Segment) bool {
return segment.flags & @enumToInt(Flag.WASM_DATA_SEGMENT_IS_PASSIVE) != 0;
}
+
+ /// For a given segment, determines if it needs passive initialization
+ fn needsPassiveInitialization(segment: Segment, import_mem: bool, name: []const u8) bool {
+ if (import_mem and !std.mem.eql(u8, name, ".bss")) {
+ return true;
+ }
+ return segment.isPassive();
+ }
};
pub const Export = struct {
@@ -824,6 +832,178 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {
}
}
+fn setupInitMemoryFunction(wasm: *Wasm) !void {
+ // Passive segments are used to avoid memory being reinitialized on each
+ // thread's instantiation. These passive segments are initialized and
+ // dropped in __wasm_init_memory, which is registered as the start function
+ // We also initialize bss segments (using memory.fill) as part of this
+ // function.
+ if (!wasm.hasPassiveInitializationSegments()) {
+ return;
+ }
+
+ const flag_address: u32 = if (wasm.base.options.shared_memory) address: {
+ // when we have passive initialization segments and shared memory
+ // `setupMemory` will create this symbol and set its virtual address.
+ const loc = wasm.findGlobalSymbol("__wasm_init_memory_flag").?;
+ break :address loc.getSymbol(wasm).virtual_address;
+ } else 0;
+
+ var function_body = std.ArrayList(u8).init(wasm.base.allocator);
+ defer function_body.deinit();
+ const writer = function_body.writer();
+
+ // we have 0 locals
+ try leb.writeULEB128(writer, @as(u32, 0));
+
+ if (wasm.base.options.shared_memory) {
+ // destination blocks
+ // based on values we jump to corresponding label
+ try writer.writeByte(std.wasm.opcode(.block)); // $drop
+ try writer.writeByte(std.wasm.block_empty); // block type
+
+ try writer.writeByte(std.wasm.opcode(.block)); // $wait
+ try writer.writeByte(std.wasm.block_empty); // block type
+
+ try writer.writeByte(std.wasm.opcode(.block)); // $init
+ try writer.writeByte(std.wasm.block_empty); // block type
+
+ // atomically check
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, flag_address);
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, @as(u32, 0));
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, @as(u32, 1));
+ try writer.writeByte(std.wasm.opcode(.atomics_prefix));
+ try leb.writeULEB128(writer, std.wasm.atomicsOpcode(.i32_atomic_rmw_cmpxchg));
+ try leb.writeULEB128(writer, @as(u32, 2)); // alignment
+ try leb.writeULEB128(writer, @as(u32, 0)); // offset
+
+ // based on the value from the atomic check, jump to the label.
+ try writer.writeByte(std.wasm.opcode(.br_table));
+ try leb.writeULEB128(writer, @as(u32, 2)); // length of the table (we have 3 blocks but because of the mandatory default the length is 2).
+ try leb.writeULEB128(writer, @as(u32, 0)); // $init
+ try leb.writeULEB128(writer, @as(u32, 1)); // $wait
+ try leb.writeULEB128(writer, @as(u32, 2)); // $drop
+ try writer.writeByte(std.wasm.opcode(.end));
+ }
+
+ var it = wasm.data_segments.iterator();
+ var segment_index: u32 = 0;
+ while (it.next()) |entry| : (segment_index += 1) {
+ const segment: Segment = wasm.segments.items[entry.value_ptr.*];
+ if (segment.needsPassiveInitialization(wasm.base.options.import_memory, entry.key_ptr.*)) {
+ // For passive BSS segments we can simple issue a memory.fill(0).
+ // For non-BSS segments we do a memory.init. Both these
+ // instructions take as their first argument the destination
+ // address.
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, segment.offset);
+
+ if (wasm.base.options.shared_memory and std.mem.eql(u8, entry.key_ptr.*, ".tdata")) {
+ // When we initialize the TLS segment we also set the `__tls_base`
+ // global. This allows the runtime to use this static copy of the
+ // TLS data for the first/main thread.
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, segment.offset);
+ try writer.writeByte(std.wasm.opcode(.global_set));
+ const loc = wasm.findGlobalSymbol("__tls_base").?;
+ try leb.writeULEB128(writer, loc.getSymbol(wasm).index);
+ }
+
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, @as(u32, 0));
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, segment.size);
+ try writer.writeByte(std.wasm.opcode(.misc_prefix));
+ if (std.mem.eql(u8, entry.key_ptr.*, ".bss")) {
+ // fill bss segment with zeroes
+ try leb.writeULEB128(writer, std.wasm.miscOpcode(.memory_fill));
+ } else {
+ // initialize the segment
+ try leb.writeULEB128(writer, std.wasm.miscOpcode(.memory_init));
+ try leb.writeULEB128(writer, segment_index);
+ }
+ try writer.writeByte(0); // memory index immediate
+ }
+ }
+
+ if (wasm.base.options.shared_memory) {
+ // we set the init memory flag to value '2'
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, flag_address);
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, @as(u32, 2));
+ try writer.writeByte(std.wasm.opcode(.atomics_prefix));
+ try leb.writeULEB128(writer, std.wasm.atomicsOpcode(.i32_atomic_store));
+ try leb.writeULEB128(writer, @as(u32, 2)); // alignment
+ try leb.writeULEB128(writer, @as(u32, 0)); // offset
+
+ // notify any waiters for segment initialization completion
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, flag_address);
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeILEB128(writer, @as(i32, -1)); // number of waiters
+ try writer.writeByte(std.wasm.opcode(.atomics_prefix));
+ try leb.writeULEB128(writer, std.wasm.atomicsOpcode(.memory_atomic_notify));
+ try leb.writeULEB128(writer, @as(u32, 2)); // alignment
+ try leb.writeULEB128(writer, @as(u32, 0)); // offset
+ try writer.writeByte(std.wasm.opcode(.drop));
+
+ // branch and drop segments
+ try writer.writeByte(std.wasm.opcode(.br));
+ try leb.writeULEB128(writer, @as(u32, 1));
+
+ // wait for thread to initialize memory segments
+ try writer.writeByte(std.wasm.opcode(.end)); // end $wait
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, flag_address);
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeULEB128(writer, @as(u32, 1)); // expected flag value
+ try writer.writeByte(std.wasm.opcode(.i32_const));
+ try leb.writeILEB128(writer, @as(i32, -1)); // timeout
+ try writer.writeByte(std.wasm.opcode(.atomics_prefix));
+ try leb.writeULEB128(writer, std.wasm.atomicsOpcode(.memory_atomic_wait32));
+ try leb.writeULEB128(writer, @as(u32, 2)); // alignment
+ try leb.writeULEB128(writer, @as(u32, 0)); // offset
+ try writer.writeByte(std.wasm.opcode(.drop));
+
+ try writer.writeByte(std.wasm.opcode(.end)); // end $drop
+ }
+
+ it.reset();
+ segment_index = 0;
+ while (it.next()) |entry| : (segment_index += 1) {
+ const name = entry.key_ptr.*;
+ const segment: Segment = wasm.segments.items[entry.value_ptr.*];
+ if (segment.needsPassiveInitialization(wasm.base.options.import_memory, name) and
+ !std.mem.eql(u8, name, ".bss"))
+ {
+ // The TLS region should not be dropped since its is needed
+ // during the initialization of each thread (__wasm_init_tls).
+ if (wasm.base.options.shared_memory and std.mem.eql(u8, name, ".tdata")) {
+ continue;
+ }
+
+ try writer.writeByte(std.wasm.opcode(.misc_prefix));
+ try leb.writeULEB128(writer, std.wasm.miscOpcode(.data_drop));
+ try leb.writeULEB128(writer, segment_index);
+ }
+ }
+
+ // End of the function body
+ try writer.writeByte(std.wasm.opcode(.end));
+
+ try wasm.createSyntheticFunction(
+ "__wasm_init_memory",
+ std.wasm.Type{ .params = &.{}, .returns = &.{} },
+ &function_body,
+ );
+}
+
+/// Constructs a synthetic function that performs runtime relocations for
+/// TLS symbols. This function is called by `__wasm_init_tls`.
fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
// When we have TLS GOT entries and shared memory is enabled,
// we must perform runtime relocations or else we don't create the function.
@@ -2469,6 +2649,16 @@ fn setupMemory(wasm: *Wasm) !void {
offset += segment.size;
}
+ // create the memory init flag which is used by the init memory function
+ if (wasm.base.options.shared_memory and wasm.hasPassiveInitializationSegments()) {
+ // align to pointer size
+ memory_ptr = mem.alignForwardGeneric(u64, memory_ptr, 4);
+ const loc = try wasm.createSyntheticSymbol("__wasm_init_memory_flag", .data);
+ const sym = loc.getSymbol(wasm);
+ sym.virtual_address = @intCast(u32, memory_ptr);
+ memory_ptr += 4;
+ }
+
if (!place_stack_first and !is_obj) {
memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment);
memory_ptr += stack_size;
@@ -3000,6 +3190,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
try wasm.mergeSections();
try wasm.mergeTypes();
try wasm.initializeCallCtorsFunction();
+ try wasm.setupInitMemoryFunction();
try wasm.setupTLSRelocationsFunction();
try wasm.initializeTLSFunction();
try wasm.setupExports();
@@ -3121,6 +3312,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
try wasm.mergeSections();
try wasm.mergeTypes();
try wasm.initializeCallCtorsFunction();
+ try wasm.setupInitMemoryFunction();
try wasm.setupTLSRelocationsFunction();
try wasm.initializeTLSFunction();
try wasm.setupExports();
@@ -4473,6 +4665,17 @@ fn emitDataRelocations(
try writeCustomSectionHeader(binary_bytes.items, header_offset, size);
}
+fn hasPassiveInitializationSegments(wasm: *const Wasm) bool {
+ var it = wasm.data_segments.iterator();
+ while (it.next()) |entry| {
+ const segment: Segment = wasm.segments.items[entry.value_ptr.*];
+ if (segment.needsPassiveInitialization(wasm.base.options.import_memory, entry.key_ptr.*)) {
+ return true;
+ }
+ }
+ return false;
+}
+
pub fn getTypeIndex(wasm: *const Wasm, func_type: std.wasm.Type) ?u32 {
var index: u32 = 0;
while (index < wasm.func_types.items.len) : (index += 1) {
From a23ef3783bb5357376acdce12f73b0285636d6cf Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Thu, 16 Mar 2023 12:13:19 +0100
Subject: [PATCH 023/216] os.zig: expose ptrace wrapper for darwin and linux
---
lib/std/os.zig | 53 +++++++++++++++++++++++++++++++++++++-------------
1 file changed, 40 insertions(+), 13 deletions(-)
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 25cc4e34c4..d49db10a2f 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -7129,22 +7129,49 @@ pub fn timerfd_gettime(fd: i32) TimerFdGetError!linux.itimerspec {
pub const PtraceError = error{
DeviceBusy,
+ InputOutput,
+ Overflow,
ProcessNotFound,
PermissionDenied,
} || UnexpectedError;
-/// TODO on other OSes
-pub fn ptrace(request: i32, pid: pid_t, addr: ?[*]u8, signal: i32) PtraceError!void {
- switch (builtin.os.tag) {
- .macos, .ios, .tvos, .watchos => {},
- else => @compileError("TODO implement ptrace"),
- }
- return switch (errno(system.ptrace(request, pid, addr, signal))) {
- .SUCCESS => {},
- .SRCH => error.ProcessNotFound,
- .INVAL => unreachable,
- .PERM => error.PermissionDenied,
- .BUSY => error.DeviceBusy,
- else => |err| return unexpectedErrno(err),
+pub fn ptrace(request: u32, pid: pid_t, addr: usize, signal: usize) PtraceError!void {
+ if (builtin.os.tag == .windows or builtin.os.tag == .wasi)
+ @compileError("Unsupported OS");
+
+ return switch (builtin.os.tag) {
+ .linux => switch (errno(linux.ptrace(request, pid, addr, signal, 0))) {
+ .SUCCESS => {},
+ .SRCH => error.ProcessNotFound,
+ .FAULT => unreachable,
+ .INVAL => unreachable,
+ .IO => return error.InputOutput,
+ .PERM => error.PermissionDenied,
+ .BUSY => error.DeviceBusy,
+ else => |err| return unexpectedErrno(err),
+ },
+
+ .macos, .ios, .tvos, .watchos => switch (errno(darwin.ptrace(
+ math.cast(i32, request) orelse return error.Overflow,
+ pid,
+ @intToPtr(?[*]u8, addr),
+ math.cast(i32, signal) orelse return error.Overflow,
+ ))) {
+ .SUCCESS => {},
+ .SRCH => error.ProcessNotFound,
+ .INVAL => unreachable,
+ .PERM => error.PermissionDenied,
+ .BUSY => error.DeviceBusy,
+ else => |err| return unexpectedErrno(err),
+ },
+
+ else => switch (errno(system.ptrace(request, pid, addr, signal))) {
+ .SUCCESS => {},
+ .SRCH => error.ProcessNotFound,
+ .INVAL => unreachable,
+ .PERM => error.PermissionDenied,
+ .BUSY => error.DeviceBusy,
+ else => |err| return unexpectedErrno(err),
+ },
};
}
From e35c8a2fd6bb0eb16b45e76a39f4602f1161f357 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Thu, 16 Mar 2023 18:09:23 +0100
Subject: [PATCH 024/216] link: use std.os.ptrace wrapper on linux
---
src/link.zig | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/src/link.zig b/src/link.zig
index a919ffa999..c91d621305 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -389,11 +389,8 @@ pub const File = struct {
try emit.directory.handle.copyFile(emit.sub_path, emit.directory.handle, tmp_sub_path, .{});
try emit.directory.handle.rename(tmp_sub_path, emit.sub_path);
switch (builtin.os.tag) {
- .linux => {
- switch (std.os.errno(std.os.linux.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0, 0))) {
- .SUCCESS => {},
- else => |errno| log.warn("ptrace failure: {s}", .{@tagName(errno)}),
- }
+ .linux => std.os.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| {
+ log.warn("ptrace failure: {s}", .{@errorName(err)});
},
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
@@ -430,11 +427,8 @@ pub const File = struct {
if (base.child_pid) |pid| {
switch (builtin.os.tag) {
- .linux => {
- switch (std.os.errno(std.os.linux.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0, 0))) {
- .SUCCESS => {},
- else => |errno| log.warn("ptrace failure: {s}", .{@tagName(errno)}),
- }
+ .linux => std.os.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0) catch |err| {
+ log.warn("ptrace failure: {s}", .{@errorName(err)});
},
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
From 266c81322e4e7b6c0b7f0a7fe9873b092aef7f54 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Thu, 16 Mar 2023 18:48:16 +0100
Subject: [PATCH 025/216] darwin: resurrect posix_spawn wrappers
---
lib/std/c/darwin.zig | 369 ++++++++++++++++++++++++++++++++++---------
1 file changed, 298 insertions(+), 71 deletions(-)
diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig
index 75267cc171..ef31bc6d53 100644
--- a/lib/std/c/darwin.zig
+++ b/lib/std/c/darwin.zig
@@ -203,47 +203,6 @@ pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) kern_retu
pub extern "c" fn malloc_size(?*const anyopaque) usize;
pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int;
-pub const posix_spawnattr_t = *opaque {};
-pub const posix_spawn_file_actions_t = *opaque {};
-pub extern "c" fn posix_spawnattr_init(attr: *posix_spawnattr_t) c_int;
-pub extern "c" fn posix_spawnattr_destroy(attr: *posix_spawnattr_t) c_int;
-pub extern "c" fn posix_spawnattr_setflags(attr: *posix_spawnattr_t, flags: c_short) c_int;
-pub extern "c" fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, flags: *c_short) c_int;
-pub extern "c" fn posix_spawn_file_actions_init(actions: *posix_spawn_file_actions_t) c_int;
-pub extern "c" fn posix_spawn_file_actions_destroy(actions: *posix_spawn_file_actions_t) c_int;
-pub extern "c" fn posix_spawn_file_actions_addclose(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
-pub extern "c" fn posix_spawn_file_actions_addopen(
- actions: *posix_spawn_file_actions_t,
- filedes: fd_t,
- path: [*:0]const u8,
- oflag: c_int,
- mode: mode_t,
-) c_int;
-pub extern "c" fn posix_spawn_file_actions_adddup2(
- actions: *posix_spawn_file_actions_t,
- filedes: fd_t,
- newfiledes: fd_t,
-) c_int;
-pub extern "c" fn posix_spawn_file_actions_addinherit_np(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
-pub extern "c" fn posix_spawn_file_actions_addchdir_np(actions: *posix_spawn_file_actions_t, path: [*:0]const u8) c_int;
-pub extern "c" fn posix_spawn_file_actions_addfchdir_np(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
-pub extern "c" fn posix_spawn(
- pid: *pid_t,
- path: [*:0]const u8,
- actions: ?*const posix_spawn_file_actions_t,
- attr: ?*const posix_spawnattr_t,
- argv: [*:null]?[*:0]const u8,
- env: [*:null]?[*:0]const u8,
-) c_int;
-pub extern "c" fn posix_spawnp(
- pid: *pid_t,
- path: [*:0]const u8,
- actions: ?*const posix_spawn_file_actions_t,
- attr: ?*const posix_spawnattr_t,
- argv: [*:null]?[*:0]const u8,
- env: [*:null]?[*:0]const u8,
-) c_int;
-
pub extern "c" fn kevent64(
kq: c_int,
changelist: [*]const kevent64_s,
@@ -2176,18 +2135,6 @@ pub const E = enum(u16) {
_,
};
-pub fn getKernError(err: kern_return_t) KernE {
- return @intToEnum(KernE, @truncate(u32, @intCast(usize, err)));
-}
-
-pub fn unexpectedKernError(err: KernE) std.os.UnexpectedError {
- if (std.os.unexpected_error_tracing) {
- std.debug.print("unexpected errno: {d}\n", .{@enumToInt(err)});
- std.debug.dumpCurrentStackTrace(null);
- }
- return error.Unexpected;
-}
-
/// Kernel return values
pub const KernE = enum(u32) {
SUCCESS = 0,
@@ -3063,6 +3010,29 @@ pub const CPUFAMILY = enum(u32) {
_,
};
+pub const PT = struct {
+ pub const TRACE_ME = 0;
+ pub const READ_I = 1;
+ pub const READ_D = 2;
+ pub const READ_U = 3;
+ pub const WRITE_I = 4;
+ pub const WRITE_D = 5;
+ pub const WRITE_U = 6;
+ pub const CONTINUE = 7;
+ pub const KILL = 8;
+ pub const STEP = 9;
+ pub const DETACH = 11;
+ pub const SIGEXC = 12;
+ pub const THUPDATE = 13;
+ pub const ATTACHEXC = 14;
+ pub const FORCEQUOTA = 30;
+ pub const DENY_ATTACH = 31;
+};
+
+pub const caddr_t = ?[*]u8;
+
+pub extern "c" fn ptrace(request: c_int, pid: pid_t, addr: caddr_t, data: c_int) c_int;
+
pub const POSIX_SPAWN_RESETIDS = 0x0001;
pub const POSIX_SPAWN_SETPGROUP = 0x0002;
pub const POSIX_SPAWN_SETSIGDEF = 0x0004;
@@ -3074,26 +3044,283 @@ pub const POSIX_SPAWN_SETSID = 0x0400;
pub const _POSIX_SPAWN_RESLIDE = 0x0800;
pub const POSIX_SPAWN_CLOEXEC_DEFAULT = 0x4000;
-pub const PT_TRACE_ME = 0;
-pub const PT_READ_I = 1;
-pub const PT_READ_D = 2;
-pub const PT_READ_U = 3;
-pub const PT_WRITE_I = 4;
-pub const PT_WRITE_D = 5;
-pub const PT_WRITE_U = 6;
-pub const PT_CONTINUE = 7;
-pub const PT_KILL = 8;
-pub const PT_STEP = 9;
-pub const PT_DETACH = 11;
-pub const PT_SIGEXC = 12;
-pub const PT_THUPDATE = 13;
-pub const PT_ATTACHEXC = 14;
-pub const PT_FORCEQUOTA = 30;
-pub const PT_DENY_ATTACH = 31;
+pub const posix_spawnattr_t = *opaque {};
+pub const posix_spawn_file_actions_t = *opaque {};
+pub extern "c" fn posix_spawnattr_init(attr: *posix_spawnattr_t) c_int;
+pub extern "c" fn posix_spawnattr_destroy(attr: *posix_spawnattr_t) c_int;
+pub extern "c" fn posix_spawnattr_setflags(attr: *posix_spawnattr_t, flags: c_short) c_int;
+pub extern "c" fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, flags: *c_short) c_int;
+pub extern "c" fn posix_spawn_file_actions_init(actions: *posix_spawn_file_actions_t) c_int;
+pub extern "c" fn posix_spawn_file_actions_destroy(actions: *posix_spawn_file_actions_t) c_int;
+pub extern "c" fn posix_spawn_file_actions_addclose(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
+pub extern "c" fn posix_spawn_file_actions_addopen(
+ actions: *posix_spawn_file_actions_t,
+ filedes: fd_t,
+ path: [*:0]const u8,
+ oflag: c_int,
+ mode: mode_t,
+) c_int;
+pub extern "c" fn posix_spawn_file_actions_adddup2(
+ actions: *posix_spawn_file_actions_t,
+ filedes: fd_t,
+ newfiledes: fd_t,
+) c_int;
+pub extern "c" fn posix_spawn_file_actions_addinherit_np(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
+pub extern "c" fn posix_spawn_file_actions_addchdir_np(actions: *posix_spawn_file_actions_t, path: [*:0]const u8) c_int;
+pub extern "c" fn posix_spawn_file_actions_addfchdir_np(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
+pub extern "c" fn posix_spawn(
+ pid: *pid_t,
+ path: [*:0]const u8,
+ actions: ?*const posix_spawn_file_actions_t,
+ attr: ?*const posix_spawnattr_t,
+ argv: [*:null]?[*:0]const u8,
+ env: [*:null]?[*:0]const u8,
+) c_int;
+pub extern "c" fn posix_spawnp(
+ pid: *pid_t,
+ path: [*:0]const u8,
+ actions: ?*const posix_spawn_file_actions_t,
+ attr: ?*const posix_spawnattr_t,
+ argv: [*:null]?[*:0]const u8,
+ env: [*:null]?[*:0]const u8,
+) c_int;
-pub const caddr_t = ?[*]u8;
+pub const PosixSpawn = struct {
+ const errno = std.os.errno;
+ const unexpectedErrno = std.os.unexpectedErrno;
-pub extern "c" fn ptrace(request: c_int, pid: pid_t, addr: caddr_t, data: c_int) c_int;
+ pub const Error = error{
+ SystemResources,
+ InvalidFileDescriptor,
+ NameTooLong,
+ TooBig,
+ PermissionDenied,
+ InputOutput,
+ FileSystem,
+ FileNotFound,
+ InvalidExe,
+ NotDir,
+ FileBusy,
+ /// Returned when the child fails to execute either in the pre-exec() initialization step, or
+ /// when exec(3) is invoked.
+ ChildExecFailed,
+ } || std.os.UnexpectedError;
+
+ pub const Attr = struct {
+ attr: posix_spawnattr_t,
+
+ pub fn init() Error!Attr {
+ var attr: posix_spawnattr_t = undefined;
+ switch (errno(posix_spawnattr_init(&attr))) {
+ .SUCCESS => return Attr{ .attr = attr },
+ .NOMEM => return error.SystemResources,
+ .INVAL => unreachable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
+ pub fn deinit(self: *Attr) void {
+ defer self.* = undefined;
+ switch (errno(posix_spawnattr_destroy(&self.attr))) {
+ .SUCCESS => return,
+ .INVAL => unreachable, // Invalid parameters.
+ else => unreachable,
+ }
+ }
+
+ pub fn get(self: Attr) Error!u16 {
+ var flags: c_short = undefined;
+ switch (errno(posix_spawnattr_getflags(&self.attr, &flags))) {
+ .SUCCESS => return @bitCast(u16, flags),
+ .INVAL => unreachable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
+ pub fn set(self: *Attr, flags: u16) Error!void {
+ switch (errno(posix_spawnattr_setflags(&self.attr, @bitCast(c_short, flags)))) {
+ .SUCCESS => return,
+ .INVAL => unreachable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+ };
+
+ pub const Actions = struct {
+ actions: posix_spawn_file_actions_t,
+
+ pub fn init() Error!Actions {
+ var actions: posix_spawn_file_actions_t = undefined;
+ switch (errno(posix_spawn_file_actions_init(&actions))) {
+ .SUCCESS => return Actions{ .actions = actions },
+ .NOMEM => return error.SystemResources,
+ .INVAL => unreachable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
+ pub fn deinit(self: *Actions) void {
+ defer self.* = undefined;
+ switch (errno(posix_spawn_file_actions_destroy(&self.actions))) {
+ .SUCCESS => return,
+ .INVAL => unreachable, // Invalid parameters.
+ else => unreachable,
+ }
+ }
+
+ pub fn open(self: *Actions, fd: fd_t, path: []const u8, flags: u32, mode: mode_t) Error!void {
+ const posix_path = try std.os.toPosixPath(path);
+ return self.openZ(fd, &posix_path, flags, mode);
+ }
+
+ pub fn openZ(self: *Actions, fd: fd_t, path: [*:0]const u8, flags: u32, mode: mode_t) Error!void {
+ switch (errno(posix_spawn_file_actions_addopen(&self.actions, fd, path, @bitCast(c_int, flags), mode))) {
+ .SUCCESS => return,
+ .BADF => return error.InvalidFileDescriptor,
+ .NOMEM => return error.SystemResources,
+ .NAMETOOLONG => return error.NameTooLong,
+ .INVAL => unreachable, // the value of file actions is invalid
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
+ pub fn close(self: *Actions, fd: fd_t) Error!void {
+ switch (errno(posix_spawn_file_actions_addclose(&self.actions, fd))) {
+ .SUCCESS => return,
+ .BADF => return error.InvalidFileDescriptor,
+ .NOMEM => return error.SystemResources,
+ .INVAL => unreachable, // the value of file actions is invalid
+ .NAMETOOLONG => unreachable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
+ pub fn dup2(self: *Actions, fd: fd_t, newfd: fd_t) Error!void {
+ switch (errno(posix_spawn_file_actions_adddup2(&self.actions, fd, newfd))) {
+ .SUCCESS => return,
+ .BADF => return error.InvalidFileDescriptor,
+ .NOMEM => return error.SystemResources,
+ .INVAL => unreachable, // the value of file actions is invalid
+ .NAMETOOLONG => unreachable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
+ pub fn inherit(self: *Actions, fd: fd_t) Error!void {
+ switch (errno(posix_spawn_file_actions_addinherit_np(&self.actions, fd))) {
+ .SUCCESS => return,
+ .BADF => return error.InvalidFileDescriptor,
+ .NOMEM => return error.SystemResources,
+ .INVAL => unreachable, // the value of file actions is invalid
+ .NAMETOOLONG => unreachable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
+ pub fn chdir(self: *Actions, path: []const u8) Error!void {
+ const posix_path = try std.os.toPosixPath(path);
+ return self.chdirZ(&posix_path);
+ }
+
+ pub fn chdirZ(self: *Actions, path: [*:0]const u8) Error!void {
+ switch (errno(posix_spawn_file_actions_addchdir_np(&self.actions, path))) {
+ .SUCCESS => return,
+ .NOMEM => return error.SystemResources,
+ .NAMETOOLONG => return error.NameTooLong,
+ .BADF => unreachable,
+ .INVAL => unreachable, // the value of file actions is invalid
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
+ pub fn fchdir(self: *Actions, fd: fd_t) Error!void {
+ switch (errno(posix_spawn_file_actions_addfchdir_np(&self.actions, fd))) {
+ .SUCCESS => return,
+ .BADF => return error.InvalidFileDescriptor,
+ .NOMEM => return error.SystemResources,
+ .INVAL => unreachable, // the value of file actions is invalid
+ .NAMETOOLONG => unreachable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+ };
+
+ pub fn spawn(
+ path: []const u8,
+ actions: ?Actions,
+ attr: ?Attr,
+ argv: [*:null]?[*:0]const u8,
+ envp: [*:null]?[*:0]const u8,
+ ) Error!pid_t {
+ const posix_path = try std.os.toPosixPath(path);
+ return spawnZ(&posix_path, actions, attr, argv, envp);
+ }
+
+ pub fn spawnZ(
+ path: [*:0]const u8,
+ actions: ?Actions,
+ attr: ?Attr,
+ argv: [*:null]?[*:0]const u8,
+ envp: [*:null]?[*:0]const u8,
+ ) Error!pid_t {
+ var pid: pid_t = undefined;
+ switch (errno(posix_spawn(
+ &pid,
+ path,
+ if (actions) |a| &a.actions else null,
+ if (attr) |a| &a.attr else null,
+ argv,
+ envp,
+ ))) {
+ .SUCCESS => return pid,
+ .@"2BIG" => return error.TooBig,
+ .NOMEM => return error.SystemResources,
+ .BADF => return error.InvalidFileDescriptor,
+ .ACCES => return error.PermissionDenied,
+ .IO => return error.InputOutput,
+ .LOOP => return error.FileSystem,
+ .NAMETOOLONG => return error.NameTooLong,
+ .NOENT => return error.FileNotFound,
+ .NOEXEC => return error.InvalidExe,
+ .NOTDIR => return error.NotDir,
+ .TXTBSY => return error.FileBusy,
+ .BADARCH => return error.InvalidExe,
+ .BADEXEC => return error.InvalidExe,
+ .FAULT => unreachable,
+ .INVAL => unreachable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
+ pub fn waitpid(pid: pid_t, flags: u32) Error!std.os.WaitPidResult {
+ var status: c_int = undefined;
+ while (true) {
+ const rc = waitpid(pid, &status, @intCast(c_int, flags));
+ switch (errno(rc)) {
+ .SUCCESS => return std.os.WaitPidResult{
+ .pid = @intCast(pid_t, rc),
+ .status = @bitCast(u32, status),
+ },
+ .INTR => continue,
+ .CHILD => return error.ChildExecFailed,
+ .INVAL => unreachable, // Invalid flags.
+ else => unreachable,
+ }
+ }
+ }
+};
+
+pub fn getKernError(err: kern_return_t) KernE {
+ return @intToEnum(KernE, @truncate(u32, @intCast(usize, err)));
+}
+
+pub fn unexpectedKernError(err: KernE) std.os.UnexpectedError {
+ if (std.os.unexpected_error_tracing) {
+ std.debug.print("unexpected errno: {d}\n", .{@enumToInt(err)});
+ std.debug.dumpCurrentStackTrace(null);
+ }
+ return error.Unexpected;
+}
pub const MachError = error{
/// Not enough permissions held to perform the requested kernel
From f1e25cf43ec60075a4fc6f3eceb5a3af1f9f0712 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Thu, 16 Mar 2023 20:41:46 +0100
Subject: [PATCH 026/216] macho: add hot-code swapping poc
---
build.zig | 2 +
lib/std/macho.zig | 4 +
src/link.zig | 16 ++++
src/link/MachO.zig | 55 +++++++++++--
src/link/MachO/Atom.zig | 16 +---
src/link/MachO/Relocation.zig | 146 ++++++++++++++--------------------
src/main.zig | 36 +++++++--
7 files changed, 165 insertions(+), 110 deletions(-)
diff --git a/build.zig b/build.zig
index 303495f6ba..60172eaebd 100644
--- a/build.zig
+++ b/build.zig
@@ -152,6 +152,7 @@ pub fn build(b: *std.Build) !void {
if (only_install_lib_files)
return;
+ const entitlements = b.option([]const u8, "entitlements", "Path to entitlements file for hot-code swapping without sudo on macOS");
const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");
const tracy_callstack = b.option(bool, "tracy-callstack", "Include callstack information with Tracy data. Does nothing if -Dtracy is not provided") orelse (tracy != null);
const tracy_allocation = b.option(bool, "tracy-allocation", "Include allocation information with Tracy data. Does nothing if -Dtracy is not provided") orelse (tracy != null);
@@ -173,6 +174,7 @@ pub fn build(b: *std.Build) !void {
exe.pie = pie;
exe.sanitize_thread = sanitize_thread;
exe.build_id = b.option(bool, "build-id", "Include a build id note") orelse false;
+ exe.entitlements = entitlements;
exe.install();
const compile_step = b.step("compile", "Build the self-hosted compiler");
diff --git a/lib/std/macho.zig b/lib/std/macho.zig
index 0c0c1a15cc..8f695b14b7 100644
--- a/lib/std/macho.zig
+++ b/lib/std/macho.zig
@@ -656,6 +656,10 @@ pub const segment_command_64 = extern struct {
pub fn segName(seg: *const segment_command_64) []const u8 {
return parseName(&seg.segname);
}
+
+ pub fn isWriteable(seg: segment_command_64) bool {
+ return seg.initprot & PROT.WRITE != 0;
+ }
};
pub const PROT = struct {
diff --git a/src/link.zig b/src/link.zig
index c91d621305..f1846f184c 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -392,6 +392,19 @@ pub const File = struct {
.linux => std.os.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| {
log.warn("ptrace failure: {s}", .{@errorName(err)});
},
+ .macos => {
+ const macho = base.cast(MachO).?;
+ if (macho.mach_task == null) {
+ if (std.os.darwin.machTaskForPid(pid)) |task| {
+ macho.mach_task = task;
+ std.os.ptrace(std.os.darwin.PT.ATTACHEXC, pid, 0, 0) catch |err| {
+ log.warn("ptrace failure: {s}", .{@errorName(err)});
+ };
+ } else |err| {
+ log.warn("failed to acquire Mach task for child process: {s}", .{@errorName(err)});
+ }
+ }
+ },
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
}
@@ -430,6 +443,9 @@ pub const File = struct {
.linux => std.os.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0) catch |err| {
log.warn("ptrace failure: {s}", .{@errorName(err)});
},
+ .macos => std.os.ptrace(std.os.darwin.PT.KILL, pid, 0, 0) catch |err| {
+ log.warn("ptrace failure: {s}", .{@errorName(err)});
+ },
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
}
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 2f76c49667..274c4dd9aa 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -221,6 +221,9 @@ lazy_bindings: BindingTable = .{},
/// Table of tracked Decls.
decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
+/// Mach task used when the compiler is in hot-code swapping mode.
+mach_task: ?std.os.darwin.MachTask = null,
+
const DeclMetadata = struct {
atom: Atom.Index,
section: u8,
@@ -584,7 +587,21 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
try self.allocateSpecialSymbols();
for (self.relocs.keys()) |atom_index| {
- try Atom.resolveRelocations(self, atom_index);
+ if (self.relocs.get(atom_index) == null) continue;
+
+ const atom = self.getAtom(atom_index);
+ const sym = atom.getSymbol(self);
+ const section = self.sections.get(sym.n_sect - 1).header;
+ const file_offset = section.offset + sym.n_value - section.addr;
+
+ var code = std.ArrayList(u8).init(self.base.allocator);
+ defer code.deinit();
+ try code.resize(atom.size);
+
+ const amt = try self.base.file.?.preadAll(code.items, file_offset);
+ if (amt != code.items.len) return error.InputOutput;
+
+ try self.writeAtom(atom_index, code.items);
}
if (build_options.enable_logging) {
@@ -1052,14 +1069,38 @@ pub fn parseDependentLibs(self: *MachO, syslibroot: ?[]const u8, dependent_libs:
}
}
-pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []const u8) !void {
+pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {
const atom = self.getAtom(atom_index);
const sym = atom.getSymbol(self);
const section = self.sections.get(sym.n_sect - 1);
const file_offset = section.header.offset + sym.n_value - section.header.addr;
log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset });
+
+ if (self.relocs.get(atom_index)) |relocs| {
+ try Atom.resolveRelocations(self, atom_index, relocs.items, code);
+ }
+
+ if (self.base.child_pid) |pid| blk: {
+ const task = self.mach_task orelse {
+ log.warn("cannot hot swap: no Mach task acquired for child process with pid {d}", .{pid});
+ break :blk;
+ };
+ self.writeAtomToMemory(task, section.segment_index, sym.n_value, code) catch |err| {
+ log.warn("cannot hot swap: writing to memory failed: {s}", .{@errorName(err)});
+ };
+ }
+
try self.base.file.?.pwriteAll(code, file_offset);
- try Atom.resolveRelocations(self, atom_index);
+}
+
+fn writeAtomToMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: u8, addr: u64, code: []const u8) !void {
+ const segment = self.segments.items[segment_index];
+ if (!segment.isWriteable()) {
+ try task.setCurrProtection(addr, code.len, macho.PROT.READ | macho.PROT.WRITE | macho.PROT.COPY);
+ }
+ defer if (!segment.isWriteable()) task.setCurrProtection(addr, code.len, segment.initprot) catch {};
+ const nwritten = try task.writeMem(addr, code, self.base.options.target.cpu.arch);
+ if (nwritten != code.len) return error.InputOutput;
}
fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void {
@@ -2063,7 +2104,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
else
try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
- const code = switch (res) {
+ var code = switch (res) {
.ok => code_buffer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
@@ -2115,7 +2156,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none, .{
.parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,
});
- const code = switch (res) {
+ var code = switch (res) {
.ok => code_buffer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
@@ -2202,7 +2243,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
.parent_atom_index = atom.getSymbolIndex().?,
});
- const code = switch (res) {
+ var code = switch (res) {
.ok => code_buffer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
@@ -2375,7 +2416,7 @@ pub fn getOutputSection(self: *MachO, sect: macho.section_64) !?u8 {
return sect_id;
}
-fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) !u64 {
+fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 {
const gpa = self.base.allocator;
const mod = self.base.options.module.?;
const decl = mod.declPtr(decl_index);
diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig
index 5fb94b7c13..36511dfd78 100644
--- a/src/link/MachO/Atom.zig
+++ b/src/link/MachO/Atom.zig
@@ -183,19 +183,11 @@ pub fn addLazyBinding(macho_file: *MachO, atom_index: Index, binding: Binding) !
try gop.value_ptr.append(gpa, binding);
}
-pub fn resolveRelocations(macho_file: *MachO, atom_index: Index) !void {
- const atom = macho_file.getAtom(atom_index);
- const relocs = macho_file.relocs.get(atom_index) orelse return;
- const source_sym = atom.getSymbol(macho_file);
- const source_section = macho_file.sections.get(source_sym.n_sect - 1).header;
- const file_offset = source_section.offset + source_sym.n_value - source_section.addr;
-
- log.debug("relocating '{s}'", .{atom.getName(macho_file)});
-
- for (relocs.items) |*reloc| {
+pub fn resolveRelocations(macho_file: *MachO, atom_index: Index, relocs: []Relocation, code: []u8) !void {
+ log.debug("relocating '{s}'", .{macho_file.getAtom(atom_index).getName(macho_file)});
+ for (relocs) |*reloc| {
if (!reloc.dirty) continue;
-
- try reloc.resolve(macho_file, atom_index, file_offset);
+ try reloc.resolve(macho_file, atom_index, code);
reloc.dirty = false;
}
}
diff --git a/src/link/MachO/Relocation.zig b/src/link/MachO/Relocation.zig
index 07e5cf1aa2..6beae8e8ea 100644
--- a/src/link/MachO/Relocation.zig
+++ b/src/link/MachO/Relocation.zig
@@ -50,7 +50,7 @@ pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {
return macho_file.getAtomIndexForSymbol(self.target);
}
-pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, base_offset: u64) !void {
+pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, code: []u8) !void {
const arch = macho_file.base.options.target.cpu.arch;
const atom = macho_file.getAtom(atom_index);
const source_sym = atom.getSymbol(macho_file);
@@ -68,42 +68,28 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, bas
});
switch (arch) {
- .aarch64 => return self.resolveAarch64(macho_file, source_addr, target_addr, base_offset),
- .x86_64 => return self.resolveX8664(macho_file, source_addr, target_addr, base_offset),
+ .aarch64 => return self.resolveAarch64(source_addr, target_addr, code),
+ .x86_64 => return self.resolveX8664(source_addr, target_addr, code),
else => unreachable,
}
}
fn resolveAarch64(
self: Relocation,
- macho_file: *MachO,
source_addr: u64,
target_addr: i64,
- base_offset: u64,
+ code: []u8,
) !void {
const rel_type = @intToEnum(macho.reloc_type_arm64, self.type);
if (rel_type == .ARM64_RELOC_UNSIGNED) {
- var buffer: [@sizeOf(u64)]u8 = undefined;
- const code = blk: {
- switch (self.length) {
- 2 => {
- mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, @bitCast(u64, target_addr)));
- break :blk buffer[0..4];
- },
- 3 => {
- mem.writeIntLittle(u64, &buffer, @bitCast(u64, target_addr));
- break :blk &buffer;
- },
- else => unreachable,
- }
+ return switch (self.length) {
+ 2 => mem.writeIntLittle(u32, code[self.offset..][0..4], @truncate(u32, @bitCast(u64, target_addr))),
+ 3 => mem.writeIntLittle(u64, code[self.offset..][0..8], @bitCast(u64, target_addr)),
+ else => unreachable,
};
- return macho_file.base.file.?.pwriteAll(code, base_offset + self.offset);
}
- var buffer: [@sizeOf(u32)]u8 = undefined;
- const amt = try macho_file.base.file.?.preadAll(&buffer, base_offset + self.offset);
- if (amt != buffer.len) return error.InputOutput;
-
+ var buffer = code[self.offset..][0..4];
switch (rel_type) {
.ARM64_RELOC_BRANCH26 => {
const displacement = math.cast(
@@ -114,10 +100,10 @@ fn resolveAarch64(
.unconditional_branch_immediate = mem.bytesToValue(meta.TagPayload(
aarch64.Instruction,
aarch64.Instruction.unconditional_branch_immediate,
- ), &buffer),
+ ), buffer),
};
inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));
- mem.writeIntLittle(u32, &buffer, inst.toU32());
+ mem.writeIntLittle(u32, buffer, inst.toU32());
},
.ARM64_RELOC_PAGE21,
.ARM64_RELOC_GOT_LOAD_PAGE21,
@@ -130,31 +116,31 @@ fn resolveAarch64(
.pc_relative_address = mem.bytesToValue(meta.TagPayload(
aarch64.Instruction,
aarch64.Instruction.pc_relative_address,
- ), &buffer),
+ ), buffer),
};
inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);
inst.pc_relative_address.immlo = @truncate(u2, pages);
- mem.writeIntLittle(u32, &buffer, inst.toU32());
+ mem.writeIntLittle(u32, buffer, inst.toU32());
},
.ARM64_RELOC_PAGEOFF12,
.ARM64_RELOC_GOT_LOAD_PAGEOFF12,
=> {
const narrowed = @truncate(u12, @intCast(u64, target_addr));
- if (isArithmeticOp(&buffer)) {
+ if (isArithmeticOp(buffer)) {
var inst = aarch64.Instruction{
.add_subtract_immediate = mem.bytesToValue(meta.TagPayload(
aarch64.Instruction,
aarch64.Instruction.add_subtract_immediate,
- ), &buffer),
+ ), buffer),
};
inst.add_subtract_immediate.imm12 = narrowed;
- mem.writeIntLittle(u32, &buffer, inst.toU32());
+ mem.writeIntLittle(u32, buffer, inst.toU32());
} else {
var inst = aarch64.Instruction{
.load_store_register = mem.bytesToValue(meta.TagPayload(
aarch64.Instruction,
aarch64.Instruction.load_store_register,
- ), &buffer),
+ ), buffer),
};
const offset: u12 = blk: {
if (inst.load_store_register.size == 0) {
@@ -170,7 +156,7 @@ fn resolveAarch64(
}
};
inst.load_store_register.offset = offset;
- mem.writeIntLittle(u32, &buffer, inst.toU32());
+ mem.writeIntLittle(u32, buffer, inst.toU32());
}
},
.ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => {
@@ -180,11 +166,11 @@ fn resolveAarch64(
size: u2,
};
const reg_info: RegInfo = blk: {
- if (isArithmeticOp(&buffer)) {
+ if (isArithmeticOp(buffer)) {
const inst = mem.bytesToValue(meta.TagPayload(
aarch64.Instruction,
aarch64.Instruction.add_subtract_immediate,
- ), &buffer);
+ ), buffer);
break :blk .{
.rd = inst.rd,
.rn = inst.rn,
@@ -194,7 +180,7 @@ fn resolveAarch64(
const inst = mem.bytesToValue(meta.TagPayload(
aarch64.Instruction,
aarch64.Instruction.load_store_register,
- ), &buffer);
+ ), buffer);
break :blk .{
.rd = inst.rt,
.rn = inst.rn,
@@ -214,72 +200,62 @@ fn resolveAarch64(
.sf = @truncate(u1, reg_info.size),
},
};
- mem.writeIntLittle(u32, &buffer, inst.toU32());
+ mem.writeIntLittle(u32, buffer, inst.toU32());
},
.ARM64_RELOC_POINTER_TO_GOT => {
const result = @intCast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr));
- mem.writeIntLittle(i32, &buffer, result);
+ mem.writeIntLittle(i32, buffer, result);
},
.ARM64_RELOC_SUBTRACTOR => unreachable,
.ARM64_RELOC_ADDEND => unreachable,
.ARM64_RELOC_UNSIGNED => unreachable,
}
- try macho_file.base.file.?.pwriteAll(&buffer, base_offset + self.offset);
}
fn resolveX8664(
self: Relocation,
- macho_file: *MachO,
source_addr: u64,
target_addr: i64,
- base_offset: u64,
+ code: []u8,
) !void {
const rel_type = @intToEnum(macho.reloc_type_x86_64, self.type);
- var buffer: [@sizeOf(u64)]u8 = undefined;
- const code = blk: {
- switch (rel_type) {
- .X86_64_RELOC_BRANCH,
- .X86_64_RELOC_GOT,
- .X86_64_RELOC_GOT_LOAD,
- .X86_64_RELOC_TLV,
- => {
- const displacement = @intCast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4);
- mem.writeIntLittle(u32, buffer[0..4], @bitCast(u32, displacement));
- break :blk buffer[0..4];
- },
- .X86_64_RELOC_SIGNED,
- .X86_64_RELOC_SIGNED_1,
- .X86_64_RELOC_SIGNED_2,
- .X86_64_RELOC_SIGNED_4,
- => {
- const correction: u3 = switch (rel_type) {
- .X86_64_RELOC_SIGNED => 0,
- .X86_64_RELOC_SIGNED_1 => 1,
- .X86_64_RELOC_SIGNED_2 => 2,
- .X86_64_RELOC_SIGNED_4 => 4,
- else => unreachable,
- };
- const displacement = @intCast(i32, target_addr - @intCast(i64, source_addr + correction + 4));
- mem.writeIntLittle(u32, buffer[0..4], @bitCast(u32, displacement));
- break :blk buffer[0..4];
- },
- .X86_64_RELOC_UNSIGNED => {
- switch (self.length) {
- 2 => {
- mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, @bitCast(u64, target_addr)));
- break :blk buffer[0..4];
- },
- 3 => {
- mem.writeIntLittle(u64, buffer[0..8], @bitCast(u64, target_addr));
- break :blk &buffer;
- },
- else => unreachable,
- }
- },
- .X86_64_RELOC_SUBTRACTOR => unreachable,
- }
- };
- try macho_file.base.file.?.pwriteAll(code, base_offset + self.offset);
+ switch (rel_type) {
+ .X86_64_RELOC_BRANCH,
+ .X86_64_RELOC_GOT,
+ .X86_64_RELOC_GOT_LOAD,
+ .X86_64_RELOC_TLV,
+ => {
+ const displacement = @intCast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4);
+ mem.writeIntLittle(u32, code[self.offset..][0..4], @bitCast(u32, displacement));
+ },
+ .X86_64_RELOC_SIGNED,
+ .X86_64_RELOC_SIGNED_1,
+ .X86_64_RELOC_SIGNED_2,
+ .X86_64_RELOC_SIGNED_4,
+ => {
+ const correction: u3 = switch (rel_type) {
+ .X86_64_RELOC_SIGNED => 0,
+ .X86_64_RELOC_SIGNED_1 => 1,
+ .X86_64_RELOC_SIGNED_2 => 2,
+ .X86_64_RELOC_SIGNED_4 => 4,
+ else => unreachable,
+ };
+ const displacement = @intCast(i32, target_addr - @intCast(i64, source_addr + correction + 4));
+ mem.writeIntLittle(u32, code[self.offset..][0..4], @bitCast(u32, displacement));
+ },
+ .X86_64_RELOC_UNSIGNED => {
+ switch (self.length) {
+ 2 => {
+ mem.writeIntLittle(u32, code[self.offset..][0..4], @truncate(u32, @bitCast(u64, target_addr)));
+ },
+ 3 => {
+ mem.writeIntLittle(u64, code[self.offset..][0..8], @bitCast(u64, target_addr));
+ },
+ else => unreachable,
+ }
+ },
+ .X86_64_RELOC_SUBTRACTOR => unreachable,
+ }
}
inline fn isArithmeticOp(inst: *const [4]u8) bool {
diff --git a/src/main.zig b/src/main.zig
index db28a5b09b..7d46f10a22 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -3851,15 +3851,39 @@ fn runOrTestHotSwap(
if (runtime_args_start) |i| {
try argv.appendSlice(all_args[i..]);
}
- var child = std.ChildProcess.init(argv.items, gpa);
- child.stdin_behavior = .Inherit;
- child.stdout_behavior = .Inherit;
- child.stderr_behavior = .Inherit;
+ switch (builtin.target.os.tag) {
+ .macos, .ios, .tvos, .watchos => {
+ const PosixSpawn = std.os.darwin.PosixSpawn;
+ var attr = try PosixSpawn.Attr.init();
+ defer attr.deinit();
+ const flags: u16 = std.os.darwin.POSIX_SPAWN_SETSIGDEF |
+ std.os.darwin.POSIX_SPAWN_SETSIGMASK |
+ std.os.darwin._POSIX_SPAWN_DISABLE_ASLR;
+ try attr.set(flags);
- try child.spawn();
+ var arena_allocator = std.heap.ArenaAllocator.init(gpa);
+ defer arena_allocator.deinit();
+ const arena = arena_allocator.allocator();
- return child.id;
+ const argv_buf = try arena.allocSentinel(?[*:0]u8, argv.items.len, null);
+ for (argv.items, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr;
+
+ const pid = try PosixSpawn.spawn(argv.items[0], null, attr, argv_buf, std.c.environ);
+ return pid;
+ },
+ else => {
+ var child = std.ChildProcess.init(argv.items, gpa);
+
+ child.stdin_behavior = .Inherit;
+ child.stdout_behavior = .Inherit;
+ child.stderr_behavior = .Inherit;
+
+ try child.spawn();
+
+ return child.id;
+ },
+ }
}
const AfterUpdateHook = union(enum) {
From 37192bcdcb38be2266133f6d46dce5a842984c06 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Fri, 17 Mar 2023 09:25:49 +0100
Subject: [PATCH 027/216] macos: HCS PoC working
---
lib/std/c/darwin.zig | 2 +-
src/link.zig | 15 +++++++++------
src/link/MachO.zig | 26 ++++++++++++++++++--------
src/main.zig | 31 ++++++++++++++-----------------
4 files changed, 42 insertions(+), 32 deletions(-)
diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig
index ef31bc6d53..4e5bc73c38 100644
--- a/lib/std/c/darwin.zig
+++ b/lib/std/c/darwin.zig
@@ -3316,7 +3316,7 @@ pub fn getKernError(err: kern_return_t) KernE {
pub fn unexpectedKernError(err: KernE) std.os.UnexpectedError {
if (std.os.unexpected_error_tracing) {
- std.debug.print("unexpected errno: {d}\n", .{@enumToInt(err)});
+ std.debug.print("unexpected error: {d}\n", .{@enumToInt(err)});
std.debug.dumpCurrentStackTrace(null);
}
return error.Unexpected;
diff --git a/src/link.zig b/src/link.zig
index f1846f184c..c87d5b5dd5 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -397,9 +397,10 @@ pub const File = struct {
if (macho.mach_task == null) {
if (std.os.darwin.machTaskForPid(pid)) |task| {
macho.mach_task = task;
- std.os.ptrace(std.os.darwin.PT.ATTACHEXC, pid, 0, 0) catch |err| {
- log.warn("ptrace failure: {s}", .{@errorName(err)});
- };
+ // TODO enable ones we register for exceptions
+ // std.os.ptrace(std.os.darwin.PT.ATTACHEXC, pid, 0, 0) catch |err| {
+ // log.warn("ptrace failure: {s}", .{@errorName(err)});
+ // };
} else |err| {
log.warn("failed to acquire Mach task for child process: {s}", .{@errorName(err)});
}
@@ -443,9 +444,11 @@ pub const File = struct {
.linux => std.os.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0) catch |err| {
log.warn("ptrace failure: {s}", .{@errorName(err)});
},
- .macos => std.os.ptrace(std.os.darwin.PT.KILL, pid, 0, 0) catch |err| {
- log.warn("ptrace failure: {s}", .{@errorName(err)});
- },
+ .macos => {},
+ // TODO see comment above in makeWritable
+ // .macos => std.os.ptrace(std.os.darwin.PT.DETACH, pid, 0, 0) catch |err| {
+ // log.warn("ptrace failure: {s}", .{@errorName(err)});
+ // },
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
}
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 274c4dd9aa..869061be38 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -587,7 +587,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
try self.allocateSpecialSymbols();
for (self.relocs.keys()) |atom_index| {
- if (self.relocs.get(atom_index) == null) continue;
+ const relocs = self.relocs.get(atom_index).?;
+ const needs_update = for (relocs.items) |reloc| {
+ if (reloc.dirty) break true;
+ } else false;
+
+ if (!needs_update) continue;
const atom = self.getAtom(atom_index);
const sym = atom.getSymbol(self);
@@ -1085,7 +1090,7 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {
log.warn("cannot hot swap: no Mach task acquired for child process with pid {d}", .{pid});
break :blk;
};
- self.writeAtomToMemory(task, section.segment_index, sym.n_value, code) catch |err| {
+ self.updateAtomInMemory(task, section.segment_index, sym.n_value, code) catch |err| {
log.warn("cannot hot swap: writing to memory failed: {s}", .{@errorName(err)});
};
}
@@ -1093,13 +1098,13 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {
try self.base.file.?.pwriteAll(code, file_offset);
}
-fn writeAtomToMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: u8, addr: u64, code: []const u8) !void {
+fn updateAtomInMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: u8, addr: u64, code: []const u8) !void {
const segment = self.segments.items[segment_index];
- if (!segment.isWriteable()) {
- try task.setCurrProtection(addr, code.len, macho.PROT.READ | macho.PROT.WRITE | macho.PROT.COPY);
- }
- defer if (!segment.isWriteable()) task.setCurrProtection(addr, code.len, segment.initprot) catch {};
- const nwritten = try task.writeMem(addr, code, self.base.options.target.cpu.arch);
+ const cpu_arch = self.base.options.target.cpu.arch;
+ const nwritten = if (!segment.isWriteable())
+ try task.writeMemProtected(addr, code, cpu_arch)
+ else
+ try task.writeMem(addr, code, cpu_arch);
if (nwritten != code.len) return error.InputOutput;
}
@@ -1109,6 +1114,7 @@ fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void {
}
fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {
+ log.debug("marking relocs dirty by target: {}", .{target});
// TODO: reverse-lookup might come in handy here
for (self.relocs.values()) |*relocs| {
for (relocs.items) |*reloc| {
@@ -1119,6 +1125,7 @@ fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {
}
fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {
+ log.debug("marking relocs dirty by address: {x}", .{addr});
for (self.relocs.values()) |*relocs| {
for (relocs.items) |*reloc| {
const target_atom_index = reloc.getTargetAtomIndex(self) orelse continue;
@@ -1743,6 +1750,8 @@ pub fn resolveDyldStubBinder(self: *MachO) !void {
if (self.dyld_stub_binder_index != null) return;
if (self.unresolved.count() == 0) return; // no need for a stub binder if we don't have any imports
+ log.debug("resolving dyld_stub_binder", .{});
+
const gpa = self.base.allocator;
const sym_index = try self.allocateSymbol();
const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
@@ -2829,6 +2838,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
if (self.linkedit_segment_cmd_index == null) {
self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
+
try self.segments.append(gpa, .{
.segname = makeStaticString("__LINKEDIT"),
.maxprot = macho.PROT.READ,
diff --git a/src/main.zig b/src/main.zig
index 7d46f10a22..551bd55c42 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -3320,21 +3320,20 @@ fn buildOutputType(
try server.listen(.{ .in = ip4_addr });
- while (true) {
- const conn = try server.accept();
- defer conn.stream.close();
+ const conn = try server.accept();
+ defer conn.stream.close();
- try serve(
- comp,
- .{ .handle = conn.stream.handle },
- .{ .handle = conn.stream.handle },
- test_exec_args.items,
- self_exe_path,
- arg_mode,
- all_args,
- runtime_args_start,
- );
- }
+ try serve(
+ comp,
+ .{ .handle = conn.stream.handle },
+ .{ .handle = conn.stream.handle },
+ test_exec_args.items,
+ self_exe_path,
+ arg_mode,
+ all_args,
+ runtime_args_start,
+ );
+ return cleanExit();
},
}
@@ -3465,9 +3464,7 @@ fn serve(
const hdr = try server.receiveMessage();
switch (hdr.tag) {
- .exit => {
- return cleanExit();
- },
+ .exit => return,
.update => {
assert(main_progress_node.recently_updated_child == null);
tracy.frameMark();
From 0aab3bda126b0221f81533b335c7a6a01749344b Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Fri, 17 Mar 2023 14:51:08 +0100
Subject: [PATCH 028/216] macho: add wrappers for attaching/detaching from HCS
process
---
src/link.zig | 23 +++++------------------
src/link/MachO.zig | 22 ++++++++++++++++++++++
2 files changed, 27 insertions(+), 18 deletions(-)
diff --git a/src/link.zig b/src/link.zig
index c87d5b5dd5..ae6c02c08b 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -392,19 +392,8 @@ pub const File = struct {
.linux => std.os.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| {
log.warn("ptrace failure: {s}", .{@errorName(err)});
},
- .macos => {
- const macho = base.cast(MachO).?;
- if (macho.mach_task == null) {
- if (std.os.darwin.machTaskForPid(pid)) |task| {
- macho.mach_task = task;
- // TODO enable ones we register for exceptions
- // std.os.ptrace(std.os.darwin.PT.ATTACHEXC, pid, 0, 0) catch |err| {
- // log.warn("ptrace failure: {s}", .{@errorName(err)});
- // };
- } else |err| {
- log.warn("failed to acquire Mach task for child process: {s}", .{@errorName(err)});
- }
- }
+ .macos => base.cast(MachO).?.ptraceAttach(pid) catch |err| {
+ log.warn("attaching failed with error: {s}", .{@errorName(err)});
},
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
@@ -444,11 +433,9 @@ pub const File = struct {
.linux => std.os.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0) catch |err| {
log.warn("ptrace failure: {s}", .{@errorName(err)});
},
- .macos => {},
- // TODO see comment above in makeWritable
- // .macos => std.os.ptrace(std.os.darwin.PT.DETACH, pid, 0, 0) catch |err| {
- // log.warn("ptrace failure: {s}", .{@errorName(err)});
- // },
+ .macos => base.cast(MachO).?.ptraceDetach(pid) catch |err| {
+ log.warn("detaching failed with error: {s}", .{@errorName(err)});
+ },
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
}
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 869061be38..3d0b8b2f77 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -3811,6 +3811,28 @@ pub fn allocatedVirtualSize(self: *MachO, start: u64) u64 {
return min_pos - start;
}
+pub fn ptraceAttach(self: *MachO, pid: std.os.pid_t) !void {
+ const mach_task = try std.os.darwin.machTaskForPid(pid);
+ log.debug("Mach task for pid {d}: {any}", .{ pid, mach_task });
+ self.mach_task = mach_task;
+
+ // TODO start exception handler in another thread
+
+ // TODO enable ones we register for exceptions
+ // try std.os.ptrace(std.os.darwin.PT.ATTACHEXC, pid, 0, 0);
+}
+
+pub fn ptraceDetach(self: *MachO, pid: std.os.pid_t) !void {
+ _ = pid;
+
+ // TODO stop exception handler
+
+ // TODO see comment in ptraceAttach
+ // try std.os.ptrace(std.os.darwin.PT.DETACH, pid, 0, 0);
+
+ self.mach_task = null;
+}
+
pub fn makeStaticString(bytes: []const u8) [16]u8 {
var buf = [_]u8{0} ** 16;
assert(bytes.len <= buf.len);
From 6f15eedff1bd32085808ab58f095ab549b493745 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Fri, 17 Mar 2023 15:16:31 +0100
Subject: [PATCH 029/216] darwin: put posix spawn constants in POSIX_SPAWN
struct
---
lib/std/c/darwin.zig | 22 ++++++++++++----------
src/main.zig | 10 +++++++---
2 files changed, 19 insertions(+), 13 deletions(-)
diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig
index 4e5bc73c38..eefa68e6a9 100644
--- a/lib/std/c/darwin.zig
+++ b/lib/std/c/darwin.zig
@@ -3033,16 +3033,18 @@ pub const caddr_t = ?[*]u8;
pub extern "c" fn ptrace(request: c_int, pid: pid_t, addr: caddr_t, data: c_int) c_int;
-pub const POSIX_SPAWN_RESETIDS = 0x0001;
-pub const POSIX_SPAWN_SETPGROUP = 0x0002;
-pub const POSIX_SPAWN_SETSIGDEF = 0x0004;
-pub const POSIX_SPAWN_SETSIGMASK = 0x0008;
-pub const POSIX_SPAWN_SETEXEC = 0x0040;
-pub const POSIX_SPAWN_START_SUSPENDED = 0x0080;
-pub const _POSIX_SPAWN_DISABLE_ASLR = 0x0100;
-pub const POSIX_SPAWN_SETSID = 0x0400;
-pub const _POSIX_SPAWN_RESLIDE = 0x0800;
-pub const POSIX_SPAWN_CLOEXEC_DEFAULT = 0x4000;
+pub const POSIX_SPAWN = struct {
+ pub const RESETIDS = 0x0001;
+ pub const SETPGROUP = 0x0002;
+ pub const SETSIGDEF = 0x0004;
+ pub const SETSIGMASK = 0x0008;
+ pub const SETEXEC = 0x0040;
+ pub const START_SUSPENDED = 0x0080;
+ pub const DISABLE_ASLR = 0x0100;
+ pub const SETSID = 0x0400;
+ pub const RESLIDE = 0x0800;
+ pub const CLOEXEC_DEFAULT = 0x4000;
+};
pub const posix_spawnattr_t = *opaque {};
pub const posix_spawn_file_actions_t = *opaque {};
diff --git a/src/main.zig b/src/main.zig
index 551bd55c42..961d649d38 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -3852,11 +3852,15 @@ fn runOrTestHotSwap(
switch (builtin.target.os.tag) {
.macos, .ios, .tvos, .watchos => {
const PosixSpawn = std.os.darwin.PosixSpawn;
+
var attr = try PosixSpawn.Attr.init();
defer attr.deinit();
- const flags: u16 = std.os.darwin.POSIX_SPAWN_SETSIGDEF |
- std.os.darwin.POSIX_SPAWN_SETSIGMASK |
- std.os.darwin._POSIX_SPAWN_DISABLE_ASLR;
+
+ // ASLR is probably a good default for better debugging experience/programming
+ // with hot-code updates in mind. However, we can also make it work with ASLR on.
+ const flags: u16 = std.os.darwin.POSIX_SPAWN.SETSIGDEF |
+ std.os.darwin.POSIX_SPAWN.SETSIGMASK |
+ std.os.darwin.POSIX_SPAWN.DISABLE_ASLR;
try attr.set(flags);
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
From 8f481dfc3c4f12327499485e3bf10fbbb1023186 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 18 Mar 2023 18:32:43 -0700
Subject: [PATCH 030/216] fix std.Build.OptionsStep
* use the same hash function as the rest of the steps
* fix race condition due to a macOS oddity.
* fix race condition due to file truncation (rename into place instead)
* integrate with marking Step.result_cached. check if the file already
exists with fs.access before doing anything else.
* use a directory so that the file basename can be "options.zig"
instead of a hash digest.
* better error reporting in case of file system failures.
---
lib/std/Build.zig | 4 +-
lib/std/Build/OptionsStep.zig | 82 +++++++++++++++++++++++--------
test/standalone.zig | 5 ++
test/standalone/options/build.zig | 7 +--
4 files changed, 71 insertions(+), 27 deletions(-)
diff --git a/lib/std/Build.zig b/lib/std/Build.zig
index 056a7ec639..5b974bb816 100644
--- a/lib/std/Build.zig
+++ b/lib/std/Build.zig
@@ -1737,7 +1737,7 @@ pub fn makeTempPath(b: *Build) []const u8 {
const rand_int = std.crypto.random.int(u64);
const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ hex64(rand_int);
const result_path = b.cache_root.join(b.allocator, &.{tmp_dir_sub_path}) catch @panic("OOM");
- fs.cwd().makePath(result_path) catch |err| {
+ b.cache_root.handle.makePath(tmp_dir_sub_path) catch |err| {
std.debug.print("unable to make tmp path '{s}': {s}\n", .{
result_path, @errorName(err),
});
@@ -1747,7 +1747,7 @@ pub fn makeTempPath(b: *Build) []const u8 {
/// There are a few copies of this function in miscellaneous places. Would be nice to find
/// a home for them.
-fn hex64(x: u64) [16]u8 {
+pub fn hex64(x: u64) [16]u8 {
const hex_charset = "0123456789abcdef";
var result: [16]u8 = undefined;
var i: usize = 0;
diff --git a/lib/std/Build/OptionsStep.zig b/lib/std/Build/OptionsStep.zig
index 859d0b68c9..a0e72e3695 100644
--- a/lib/std/Build/OptionsStep.zig
+++ b/lib/std/Build/OptionsStep.zig
@@ -241,33 +241,75 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
);
}
- var options_dir = try b.cache_root.handle.makeOpenPath("options", .{});
- defer options_dir.close();
+ const basename = "options.zig";
- const basename = self.hashContentsToFileName();
+ // Hash contents to file name.
+ var hash = b.cache.hash;
+ // Random bytes to make unique. Refresh this with new random bytes when
+ // implementation is modified in a non-backwards-compatible way.
+ hash.add(@as(u32, 0x38845ef8));
+ hash.addBytes(self.contents.items);
+ const sub_path = "c" ++ fs.path.sep_str ++ hash.final() ++ fs.path.sep_str ++ basename;
- try options_dir.writeFile(&basename, self.contents.items);
+ self.generated_file.path = try b.cache_root.join(b.allocator, &.{sub_path});
- self.generated_file.path = try b.cache_root.join(b.allocator, &.{ "options", &basename });
-}
+ // Optimize for the hot path. Stat the file, and if it already exists,
+ // cache hit.
+ if (b.cache_root.handle.access(sub_path, .{})) |_| {
+ // This is the hot path, success.
+ step.result_cached = true;
+ return;
+ } else |outer_err| switch (outer_err) {
+ error.FileNotFound => {
+ const sub_dirname = fs.path.dirname(sub_path).?;
+ b.cache_root.handle.makePath(sub_dirname) catch |e| {
+ return step.fail("unable to make path '{}{s}': {s}", .{
+ b.cache_root, sub_dirname, @errorName(e),
+ });
+ };
-fn hashContentsToFileName(self: *OptionsStep) [64]u8 {
- // TODO update to use the cache system instead of this
- // This implementation is copied from `WriteFileStep.make`
+ const rand_int = std.crypto.random.int(u64);
+ const tmp_sub_path = "tmp" ++ fs.path.sep_str ++
+ std.Build.hex64(rand_int) ++ fs.path.sep_str ++
+ basename;
+ const tmp_sub_path_dirname = fs.path.dirname(tmp_sub_path).?;
- var hash = std.crypto.hash.blake2.Blake2b384.init(.{});
+ b.cache_root.handle.makePath(tmp_sub_path_dirname) catch |err| {
+ return step.fail("unable to make temporary directory '{}{s}': {s}", .{
+ b.cache_root, tmp_sub_path_dirname, @errorName(err),
+ });
+ };
- // Random bytes to make OptionsStep unique. Refresh this with
- // new random bytes when OptionsStep implementation is modified
- // in a non-backwards-compatible way.
- hash.update("yL0Ya4KkmcCjBlP8");
- hash.update(self.contents.items);
+ b.cache_root.handle.writeFile(tmp_sub_path, self.contents.items) catch |err| {
+ return step.fail("unable to write options to '{}{s}': {s}", .{
+ b.cache_root, tmp_sub_path, @errorName(err),
+ });
+ };
- var digest: [48]u8 = undefined;
- hash.final(&digest);
- var hash_basename: [64]u8 = undefined;
- _ = fs.base64_encoder.encode(&hash_basename, &digest);
- return hash_basename;
+ b.cache_root.handle.rename(tmp_sub_path, sub_path) catch |err| switch (err) {
+ error.PathAlreadyExists => {
+ // Other process beat us to it. Clean up the temp file.
+ b.cache_root.handle.deleteFile(tmp_sub_path) catch |e| {
+ try step.addError("warning: unable to delete temp file '{}{s}': {s}", .{
+ b.cache_root, tmp_sub_path, @errorName(e),
+ });
+ };
+ step.result_cached = true;
+ return;
+ },
+ else => {
+ return step.fail("unable to rename options from '{}{s}' to '{}{s}': {s}", .{
+ b.cache_root, tmp_sub_path,
+ b.cache_root, sub_path,
+ @errorName(err),
+ });
+ },
+ };
+ },
+ else => |e| return step.fail("unable to access options file '{}{s}': {s}", .{
+ b.cache_root, sub_path, @errorName(e),
+ }),
+ }
}
const OptionArtifactArg = struct {
diff --git a/test/standalone.zig b/test/standalone.zig
index 4cf795a85f..98297e9578 100644
--- a/test/standalone.zig
+++ b/test/standalone.zig
@@ -213,6 +213,11 @@ pub const build_cases = [_]BuildCase{
.build_root = "test/standalone/issue_13030",
.import = @import("standalone/issue_13030/build.zig"),
},
+ // TODO restore this test
+ //.{
+ // .build_root = "test/standalone/options",
+ // .import = @import("standalone/options/build.zig"),
+ //},
};
const std = @import("std");
diff --git a/test/standalone/options/build.zig b/test/standalone/options/build.zig
index 5e894102a7..28e7e31eb7 100644
--- a/test/standalone/options/build.zig
+++ b/test/standalone/options/build.zig
@@ -1,13 +1,10 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
- const target = b.standardTargetOptions(.{});
- const optimize = b.standardOptimizeOption(.{});
-
const main = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" },
- .target = target,
- .optimize = optimize,
+ .target = .{},
+ .optimize = .Debug,
});
const options = b.addOptions();
From f026939a40b3567f1a798547391b398dc40db49a Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Sun, 19 Mar 2023 09:45:05 +0100
Subject: [PATCH 031/216] macho: enable hot update state only when on
compatible host
---
src/link/MachO.zig | 39 +++++++++++++++++++++++++++------------
1 file changed, 27 insertions(+), 12 deletions(-)
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 3d0b8b2f77..3ee2ccde2d 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -221,8 +221,13 @@ lazy_bindings: BindingTable = .{},
/// Table of tracked Decls.
decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
-/// Mach task used when the compiler is in hot-code swapping mode.
-mach_task: ?std.os.darwin.MachTask = null,
+/// Hot-code swapping state.
+hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},
+
+const is_hot_update_compatible = switch (builtin.target.os.tag) {
+ .macos => true,
+ else => false,
+};
const DeclMetadata = struct {
atom: Atom.Index,
@@ -303,6 +308,10 @@ pub const SymbolWithLoc = struct {
}
};
+const HotUpdateState = struct {
+ mach_task: ?std.os.darwin.MachTask = null,
+};
+
/// When allocating, the ideal_capacity is calculated by
/// actual_capacity + (actual_capacity / ideal_factor)
const ideal_factor = 3;
@@ -1085,14 +1094,16 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {
try Atom.resolveRelocations(self, atom_index, relocs.items, code);
}
- if (self.base.child_pid) |pid| blk: {
- const task = self.mach_task orelse {
- log.warn("cannot hot swap: no Mach task acquired for child process with pid {d}", .{pid});
- break :blk;
- };
- self.updateAtomInMemory(task, section.segment_index, sym.n_value, code) catch |err| {
- log.warn("cannot hot swap: writing to memory failed: {s}", .{@errorName(err)});
- };
+ if (is_hot_update_compatible) {
+ if (self.base.child_pid) |pid| blk: {
+ const task = self.hot_state.mach_task orelse {
+ log.warn("cannot hot swap: no Mach task acquired for child process with pid {d}", .{pid});
+ break :blk;
+ };
+ self.updateAtomInMemory(task, section.segment_index, sym.n_value, code) catch |err| {
+ log.warn("cannot hot swap: writing to memory failed: {s}", .{@errorName(err)});
+ };
+ }
}
try self.base.file.?.pwriteAll(code, file_offset);
@@ -3812,9 +3823,11 @@ pub fn allocatedVirtualSize(self: *MachO, start: u64) u64 {
}
pub fn ptraceAttach(self: *MachO, pid: std.os.pid_t) !void {
+ if (!is_hot_update_compatible) return;
+
const mach_task = try std.os.darwin.machTaskForPid(pid);
log.debug("Mach task for pid {d}: {any}", .{ pid, mach_task });
- self.mach_task = mach_task;
+ self.hot_state.mach_task = mach_task;
// TODO start exception handler in another thread
@@ -3823,6 +3836,8 @@ pub fn ptraceAttach(self: *MachO, pid: std.os.pid_t) !void {
}
pub fn ptraceDetach(self: *MachO, pid: std.os.pid_t) !void {
+ if (!is_hot_update_compatible) return;
+
_ = pid;
// TODO stop exception handler
@@ -3830,7 +3845,7 @@ pub fn ptraceDetach(self: *MachO, pid: std.os.pid_t) !void {
// TODO see comment in ptraceAttach
// try std.os.ptrace(std.os.darwin.PT.DETACH, pid, 0, 0);
- self.mach_task = null;
+ self.hot_state.mach_task = null;
}
pub fn makeStaticString(bytes: []const u8) [16]u8 {
From 6874b2930891363e1fc393d99f59f361eb69eada Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Sun, 19 Mar 2023 17:13:38 +0100
Subject: [PATCH 032/216] macho: fix 32bit build
---
src/link/MachO.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 3ee2ccde2d..151b947141 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -610,7 +610,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
var code = std.ArrayList(u8).init(self.base.allocator);
defer code.deinit();
- try code.resize(atom.size);
+ try code.resize(math.cast(usize, atom.size) orelse return error.Overflow);
const amt = try self.base.file.?.preadAll(code.items, file_offset);
if (amt != code.items.len) return error.InputOutput;
From 2fce991d2ab1dfc6d591b560607ef0edecc7db19 Mon Sep 17 00:00:00 2001
From: Ryan Liptak
Date: Wed, 8 Mar 2023 01:06:50 -0800
Subject: [PATCH 033/216] Remove std.os.windows.QueryInformationFile (a wrapper
of NtQueryInformationFile)
This function is unused, and the current implementation contains a few footguns:
- The current wrapper treats all possible errors as unexpected, even likely ones like BUFFER_OVERFLOW (which is returned if the size of the out_buffer is too small to contain all the variable-length members of the requested info, which the user may not actually care about)
- Each caller may need to handle errors differently, different errors might be possible depending on the FILE_INFORMATION_CLASS, etc, and making a wrapper that handles all of those different use-cases nicely seems like it'd be more trouble than it's worth (FILE_INFORMATION_CLASS has 76 different possible values)
If a wrapper for NtQueryInformationFile is wanted, then it should probably have wrapper functions per-use-case, like how QueryObjectName wraps NtQueryObject for the `ObjectNameInformation` class
---
lib/std/os/windows.zig | 17 -----------------
1 file changed, 17 deletions(-)
diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig
index 5576200ea5..28dac40c9a 100644
--- a/lib/std/os/windows.zig
+++ b/lib/std/os/windows.zig
@@ -1230,23 +1230,6 @@ test "GetFinalPathNameByHandle" {
_ = try GetFinalPathNameByHandle(handle, .{ .volume_name = .Dos }, buffer[0..required_len_in_u16]);
}
-pub const QueryInformationFileError = error{Unexpected};
-
-pub fn QueryInformationFile(
- handle: HANDLE,
- info_class: FILE_INFORMATION_CLASS,
- out_buffer: []u8,
-) QueryInformationFileError!void {
- var io: IO_STATUS_BLOCK = undefined;
- const len_bytes = std.math.cast(u32, out_buffer.len) orelse unreachable;
- const rc = ntdll.NtQueryInformationFile(handle, &io, out_buffer.ptr, len_bytes, info_class);
- switch (rc) {
- .SUCCESS => {},
- .INVALID_PARAMETER => unreachable,
- else => return unexpectedStatus(rc),
- }
-}
-
pub const GetFileSizeError = error{Unexpected};
pub fn GetFileSizeEx(hFile: HANDLE) GetFileSizeError!u64 {
From 30aeb41a19d3ac15c89190cd546cbe7c05c60ac8 Mon Sep 17 00:00:00 2001
From: Ganesan Rajagopal
Date: Mon, 5 Dec 2022 16:17:19 +0530
Subject: [PATCH 034/216] Fix linker segfault adding rpath to sharedlib
If the shared library is a relative path, dirname will return null causing a segfault. In the case I debugged, the current directory was already in RPATH so just ignoring this case seems a reasonable fix. After this fix "make" and "make test" pass for mimalloc.
Closes #13766
---
src/link/Elf.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index f1ab98372e..fcab34bf5e 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -1636,7 +1636,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
}
for (self.base.options.objects) |obj| {
if (Compilation.classifyFileExt(obj.path) == .shared_library) {
- const lib_dir_path = std.fs.path.dirname(obj.path).?;
+ const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue;
if ((try rpath_table.fetchPut(lib_dir_path, {})) == null) {
try argv.append("-rpath");
try argv.append(lib_dir_path);
From 30427ff794514d51cb5066b9e50113da998e0fd0 Mon Sep 17 00:00:00 2001
From: Reuben Dunnington
Date: Sun, 19 Mar 2023 16:23:05 -0700
Subject: [PATCH 035/216] Fix GetFileInformationByHandle compile error (#14829)
* Fix GetFileInformationByHandle compile error
The wrapper function was mistakenly referencing ntdll.zig when the actual function is declared in kernel32.zig.
* delete GetFileInformationByHandle since it's not used by the stdlib
---
lib/std/os/windows.zig | 15 ---------------
lib/std/os/windows/kernel32.zig | 5 -----
2 files changed, 20 deletions(-)
diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig
index 28dac40c9a..36b84d657b 100644
--- a/lib/std/os/windows.zig
+++ b/lib/std/os/windows.zig
@@ -1708,21 +1708,6 @@ pub fn LocalFree(hMem: HLOCAL) void {
assert(kernel32.LocalFree(hMem) == null);
}
-pub const GetFileInformationByHandleError = error{Unexpected};
-
-pub fn GetFileInformationByHandle(
- hFile: HANDLE,
-) GetFileInformationByHandleError!BY_HANDLE_FILE_INFORMATION {
- var info: BY_HANDLE_FILE_INFORMATION = undefined;
- const rc = ntdll.GetFileInformationByHandle(hFile, &info);
- if (rc == 0) {
- switch (kernel32.GetLastError()) {
- else => |err| return unexpectedError(err),
- }
- }
- return info;
-}
-
pub const SetFileTimeError = error{Unexpected};
pub fn SetFileTime(
diff --git a/lib/std/os/windows/kernel32.zig b/lib/std/os/windows/kernel32.zig
index 1fd8a406d5..942d7ddba7 100644
--- a/lib/std/os/windows/kernel32.zig
+++ b/lib/std/os/windows/kernel32.zig
@@ -202,11 +202,6 @@ pub extern "kernel32" fn GetModuleHandleW(lpModuleName: ?[*:0]const WCHAR) callc
pub extern "kernel32" fn GetLastError() callconv(WINAPI) Win32Error;
pub extern "kernel32" fn SetLastError(dwErrCode: Win32Error) callconv(WINAPI) void;
-pub extern "kernel32" fn GetFileInformationByHandle(
- hFile: HANDLE,
- lpFileInformation: *BY_HANDLE_FILE_INFORMATION,
-) callconv(WINAPI) BOOL;
-
pub extern "kernel32" fn GetFileInformationByHandleEx(
in_hFile: HANDLE,
in_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
From 5b5466626810302371b2d21c39e7ad04ea13a8dc Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Mon, 20 Mar 2023 16:12:51 +0100
Subject: [PATCH 036/216] macho+zld: relax assumption about dead strip atoms
uniqueness
In case the compiler outputted an object file that is not slicable
into subsections, entry point may overlap with a section atom which
is perfectly fine, so don't panic in that case.
---
src/link/MachO/dead_strip.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/link/MachO/dead_strip.zig b/src/link/MachO/dead_strip.zig
index 9dfd6226b4..a132ecb2de 100644
--- a/src/link/MachO/dead_strip.zig
+++ b/src/link/MachO/dead_strip.zig
@@ -102,7 +102,7 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void {
};
if (is_gc_root) {
- try roots.putNoClobber(atom_index, {});
+ _ = try roots.getOrPut(atom_index);
log.debug("root(ATOM({d}, %{d}, {?d}))", .{
atom_index,
From 0c169127338ef8af752d1a077e412b5135e300d5 Mon Sep 17 00:00:00 2001
From: Veikka Tuominen
Date: Thu, 16 Mar 2023 17:46:34 +0200
Subject: [PATCH 037/216] std: improve error for formatting a function body
type
Closes #14915
---
lib/std/fmt.zig | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index 8167a2b252..1658f8a502 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -703,10 +703,7 @@ pub fn formatType(
}
try writer.writeAll(" }");
},
- .Fn => {
- if (actual_fmt.len != 0) invalidFmtError(fmt, value);
- return format(writer, "{s}@{x}", .{ @typeName(T), @ptrToInt(value) });
- },
+ .Fn => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"),
.Type => {
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
return formatBuf(@typeName(value), options, writer);
From 5df31f3ef3d2c4640fa2c7fc9b03c83c6a8606ae Mon Sep 17 00:00:00 2001
From: KOUNOIKE Yuusuke
Date: Tue, 21 Mar 2023 01:45:12 +0900
Subject: [PATCH 038/216] add wasm-simd support for suggestVectorSizeForCpu
(#14992)
---
lib/std/simd.zig | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/std/simd.zig b/lib/std/simd.zig
index 71d56daec3..c2e0d9f972 100644
--- a/lib/std/simd.zig
+++ b/lib/std/simd.zig
@@ -43,6 +43,8 @@ pub fn suggestVectorSizeForCpu(comptime T: type, comptime cpu: std.Target.Cpu) ?
// for multiple processing, but I don't know what's optimal here, if using
// the 2048 bits or using just 64 per vector or something in between
if (std.Target.sparc.featureSetHasAny(cpu.features, .{ .vis, .vis2, .vis3 })) break :blk 64;
+ } else if (cpu.arch.isWasm()) {
+ if (std.Target.wasm.featureSetHas(cpu.features, .simd128)) break :blk 128;
}
return null;
};
From 626a75bbc21453237f95c186d1fea790f233bc58 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 19 Mar 2023 16:26:19 -0700
Subject: [PATCH 039/216] std.Build.RunStep: fix control flow with qemu+glibc
logic
---
lib/std/Build/RunStep.zig | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/std/Build/RunStep.zig b/lib/std/Build/RunStep.zig
index feeb64f6ca..36b409d907 100644
--- a/lib/std/Build/RunStep.zig
+++ b/lib/std/Build/RunStep.zig
@@ -594,7 +594,8 @@ fn runCommand(
.qemu => |bin_name| {
if (b.enable_qemu) {
const glibc_dir_arg = if (need_cross_glibc)
- b.glibc_runtimes_dir orelse return
+ b.glibc_runtimes_dir orelse
+ return failForeign(self, "--glibc-runtimes", argv[0], exe)
else
null;
From 773b1c4c5cdf9fde19cbf09d0f81f1bfe27ed7ca Mon Sep 17 00:00:00 2001
From: Veikka Tuominen
Date: Mon, 20 Mar 2023 18:05:52 +0200
Subject: [PATCH 040/216] llvm: fix lowering packed union initiated to zero-bit
value
Closes #14980
---
src/codegen/llvm.zig | 2 ++
test/behavior/union.zig | 20 ++++++++++++++++++++
2 files changed, 22 insertions(+)
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 11fc44747e..dd13087afe 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -3815,6 +3815,8 @@ pub const DeclGen = struct {
const field_ty = union_obj.fields.values()[field_index].ty;
if (union_obj.layout == .Packed) {
+ if (!field_ty.hasRuntimeBits())
+ return llvm_union_ty.constNull();
const non_int_val = try lowerValue(dg, .{ .ty = field_ty, .val = tag_and_val.val });
const ty_bit_size = @intCast(u16, field_ty.bitSize(target));
const small_int_ty = dg.context.intType(ty_bit_size);
diff --git a/test/behavior/union.zig b/test/behavior/union.zig
index 9b49f8bf47..ff3f0b7e54 100644
--- a/test/behavior/union.zig
+++ b/test/behavior/union.zig
@@ -1493,3 +1493,23 @@ test "union reassignment can use previous value" {
a = U{ .b = a.a };
try expect(a.b == 32);
}
+
+test "packed union with zero-bit field" {
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+
+ const S = packed struct {
+ nested: packed union {
+ zero: void,
+ sized: u32,
+ },
+ bar: u32,
+
+ fn doTest(self: @This()) !void {
+ try expect(self.bar == 42);
+ }
+ };
+ try S.doTest(.{ .nested = .{ .zero = {} }, .bar = 42 });
+}
From 9d9815fb9c21c91df41422ff582402fb56029328 Mon Sep 17 00:00:00 2001
From: Veikka Tuominen
Date: Mon, 20 Mar 2023 18:30:33 +0200
Subject: [PATCH 041/216] Value: handle comparisons of runtime_values
Closes #15004
---
src/value.zig | 10 ++++++++++
test/behavior/src.zig | 11 +++++++++++
2 files changed, 21 insertions(+)
diff --git a/src/value.zig b/src/value.zig
index e5283d1270..1b6d2adc1e 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -1113,6 +1113,10 @@ pub const Value = extern union {
.bool_true,
=> return BigIntMutable.init(&space.limbs, 1).toConst(),
+ .runtime_value => {
+ const sub_val = val.castTag(.runtime_value).?.data;
+ return sub_val.toBigIntAdvanced(space, target, opt_sema);
+ },
.int_u64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_u64).?.data).toConst(),
.int_i64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_i64).?.data).toConst(),
.int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(),
@@ -1979,6 +1983,12 @@ pub const Value = extern union {
.variable,
=> .gt,
+ .runtime_value => {
+ // This is needed to correctly handle hashing the value.
+ // Checks in Sema should prevent direct comparisons from reaching here.
+ const val = lhs.castTag(.runtime_value).?.data;
+ return val.orderAgainstZeroAdvanced(opt_sema);
+ },
.int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0),
.int_i64 => std.math.order(lhs.castTag(.int_i64).?.data, 0),
.int_big_positive => lhs.castTag(.int_big_positive).?.asBigInt().orderAgainstScalar(0),
diff --git a/test/behavior/src.zig b/test/behavior/src.zig
index 77e420afcf..e6b84e5d56 100644
--- a/test/behavior/src.zig
+++ b/test/behavior/src.zig
@@ -32,3 +32,14 @@ test "@src used as a comptime parameter" {
const T2 = S.Foo(@src());
try expect(T1 != T2);
}
+
+test "@src in tuple passed to anytype function" {
+ const S = struct {
+ fn Foo(a: anytype) u32 {
+ return a[0].line;
+ }
+ };
+ const l1 = S.Foo(.{@src()});
+ const l2 = S.Foo(.{@src()});
+ try expect(l1 != l2);
+}
From 82133cd992575ab567091eaf2f12fbe5e326b5df Mon Sep 17 00:00:00 2001
From: Veikka Tuominen
Date: Tue, 21 Mar 2023 00:09:00 +0200
Subject: [PATCH 042/216] Sema: improve error message of field access of
wrapped type
Closes #15027
---
src/Sema.zig | 48 ++++++++++++++++++-
.../field_access_of_wrapped_type.zig | 20 ++++++++
2 files changed, 66 insertions(+), 2 deletions(-)
create mode 100644 test/cases/compile_errors/field_access_of_wrapped_type.zig
diff --git a/src/Sema.zig b/src/Sema.zig
index 0afce47e76..6d6a9a13e8 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -2127,6 +2127,50 @@ fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError
return sema.failWithOwnedErrorMsg(msg);
}
+fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, object_ty: Type, field_name: []const u8) CompileError {
+ const inner_ty = if (object_ty.isSinglePointer()) object_ty.childType() else object_ty;
+
+ if (inner_ty.zigTypeTag() == .Optional) opt: {
+ var buf: Type.Payload.ElemType = undefined;
+ const child_ty = inner_ty.optionalChild(&buf);
+ if (!typeSupportsFieldAccess(child_ty, field_name)) break :opt;
+ const msg = msg: {
+ const msg = try sema.errMsg(block, src, "optional type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(block, src, msg, "consider using '.?', 'orelse', or 'if'", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ } else if (inner_ty.zigTypeTag() == .ErrorUnion) err: {
+ const child_ty = inner_ty.errorUnionPayload();
+ if (!typeSupportsFieldAccess(child_ty, field_name)) break :err;
+ const msg = msg: {
+ const msg = try sema.errMsg(block, src, "error union type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(block, src, msg, "consider using 'try', 'catch', or 'if'", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
+ return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
+}
+
+fn typeSupportsFieldAccess(ty: Type, field_name: []const u8) bool {
+ switch (ty.zigTypeTag()) {
+ .Array => return mem.eql(u8, field_name, "len"),
+ .Pointer => {
+ const ptr_info = ty.ptrInfo().data;
+ if (ptr_info.size == .Slice) {
+ return mem.eql(u8, field_name, "ptr") or mem.eql(u8, field_name, "len");
+ } else if (ptr_info.pointee_type.zigTypeTag() == .Array) {
+ return mem.eql(u8, field_name, "len");
+ } else return false;
+ },
+ .Type, .Struct, .Union => return true,
+ else => return false,
+ }
+}
+
/// We don't return a pointer to the new error note because the pointer
/// becomes invalid when you add another one.
fn errNote(
@@ -23321,7 +23365,7 @@ fn fieldVal(
},
else => {},
}
- return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
+ return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name);
}
fn fieldPtr(
@@ -23535,7 +23579,7 @@ fn fieldPtr(
},
else => {},
}
- return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
+ return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name);
}
fn fieldCallBind(
diff --git a/test/cases/compile_errors/field_access_of_wrapped_type.zig b/test/cases/compile_errors/field_access_of_wrapped_type.zig
new file mode 100644
index 0000000000..9d8a7ef17c
--- /dev/null
+++ b/test/cases/compile_errors/field_access_of_wrapped_type.zig
@@ -0,0 +1,20 @@
+const Foo = struct {
+ a: i32,
+};
+export fn f1() void {
+ var foo: ?Foo = undefined;
+ foo.a += 1;
+}
+export fn f2() void {
+ var foo: anyerror!Foo = undefined;
+ foo.a += 1;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :6:8: error: optional type '?tmp.Foo' does not support field access
+// :6:8: note: consider using '.?', 'orelse', or 'if'
+// :10:8: error: error union type 'anyerror!tmp.Foo' does not support field access
+// :10:8: note: consider using 'try', 'catch', or 'if'
From 3a25f6a22e0f339fcaecc87efb0fa4e5f67bd73c Mon Sep 17 00:00:00 2001
From: mlugg
Date: Fri, 17 Mar 2023 12:27:19 +0000
Subject: [PATCH 043/216] Port some stage1 test cases to stage2
There are now very few stage1 cases remaining:
* `cases/compile_errors/stage1/obj/*` currently don't work correctly on
stage2. There are 6 of these, and most of them are probably fairly
simple to fix.
* `cases/compile_errors/async/*` and all remaining `safety/*` depend on
async; see #6025.
Resolves: #14849
---
.../undefined_as_field_type_is_rejected.zig | 4 +-
test/compile_errors.zig | 47 +++++++++++++++++++
2 files changed, 49 insertions(+), 2 deletions(-)
diff --git a/test/cases/compile_errors/undefined_as_field_type_is_rejected.zig b/test/cases/compile_errors/undefined_as_field_type_is_rejected.zig
index b6eb059661..b0abd7139e 100644
--- a/test/cases/compile_errors/undefined_as_field_type_is_rejected.zig
+++ b/test/cases/compile_errors/undefined_as_field_type_is_rejected.zig
@@ -7,7 +7,7 @@ export fn entry1() void {
}
// error
-// backend=stage1
+// backend=stage2
// target=native
//
-// tmp.zig:2:8: error: use of undefined value here causes undefined behavior
+// :2:8: error: use of undefined value here causes undefined behavior
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 2d796b9463..5a60ef2e55 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -136,4 +136,51 @@ pub fn addCases(ctx: *Cases) !void {
\\const dummy = 0;
);
}
+
+ {
+ const case = ctx.obj("wrong same named struct", .{});
+
+ case.addError(
+ \\const a = @import("a.zig");
+ \\const b = @import("b.zig");
+ \\
+ \\export fn entry() void {
+ \\ var a1: a.Foo = undefined;
+ \\ bar(&a1);
+ \\}
+ \\
+ \\fn bar(_: *b.Foo) void {}
+ , &[_][]const u8{
+ ":6:9: error: expected type '*b.Foo', found '*a.Foo'",
+ ":6:9: note: pointer type child 'a.Foo' cannot cast into pointer type child 'b.Foo'",
+ ":1:17: note: struct declared here",
+ ":1:17: note: struct declared here",
+ ":9:11: note: parameter type declared here",
+ });
+
+ case.addSourceFile("a.zig",
+ \\pub const Foo = struct {
+ \\ x: i32,
+ \\};
+ );
+
+ case.addSourceFile("b.zig",
+ \\pub const Foo = struct {
+ \\ z: f64,
+ \\};
+ );
+ }
+
+ {
+ const case = ctx.obj("non-printable invalid character", .{});
+
+ case.addError("\xff\xfe" ++
+ \\export fn foo() bool {
+ \\ return true;
+ \\}
+ , &[_][]const u8{
+ ":1:1: error: expected type expression, found 'invalid bytes'",
+ ":1:1: note: invalid byte: '\\xff'",
+ });
+ }
}
From bc0f246911a35324473f72b770cc5715902cc912 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sun, 19 Mar 2023 19:35:58 -0400
Subject: [PATCH 044/216] tests: add -Dskip-cross-glibc option
It is reasonable to pass -Dskip-non-native when unable to run foreign
binaries, however there is no option for being able to run foreign
static binaries but unable to run foreign dynamic binaries. This can
occur when qemu is installed but not cross glibc.
---
build.zig | 6 ++++++
test/tests.zig | 4 ++++
2 files changed, 10 insertions(+)
diff --git a/build.zig b/build.zig
index 60172eaebd..9926d6e5ec 100644
--- a/build.zig
+++ b/build.zig
@@ -81,6 +81,7 @@ pub fn build(b: *std.Build) !void {
const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release;
const skip_release_safe = b.option(bool, "skip-release-safe", "Main test suite skips release-safe builds") orelse skip_release;
const skip_non_native = b.option(bool, "skip-non-native", "Main test suite skips non-native builds") orelse false;
+ const skip_cross_glibc = b.option(bool, "skip-cross-glibc", "Main test suite skips builds that require cross glibc") orelse false;
const skip_libc = b.option(bool, "skip-libc", "Main test suite skips tests that link libc") orelse false;
const skip_single_threaded = b.option(bool, "skip-single-threaded", "Main test suite skips tests that are single-threaded") orelse false;
const skip_stage1 = b.option(bool, "skip-stage1", "Main test suite skips stage1 compile error tests") orelse false;
@@ -351,6 +352,7 @@ pub fn build(b: *std.Build) !void {
test_cases_options.addOption(bool, "enable_logging", enable_logging);
test_cases_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
test_cases_options.addOption(bool, "skip_non_native", skip_non_native);
+ test_cases_options.addOption(bool, "skip_cross_glibc", skip_cross_glibc);
test_cases_options.addOption(bool, "skip_stage1", skip_stage1);
test_cases_options.addOption(bool, "have_llvm", enable_llvm);
test_cases_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k);
@@ -415,6 +417,7 @@ pub fn build(b: *std.Build) !void {
.optimize_modes = optimization_modes,
.skip_single_threaded = skip_single_threaded,
.skip_non_native = skip_non_native,
+ .skip_cross_glibc = skip_cross_glibc,
.skip_libc = skip_libc,
.skip_stage1 = skip_stage1,
.skip_stage2 = skip_stage2_tests,
@@ -429,6 +432,7 @@ pub fn build(b: *std.Build) !void {
.optimize_modes = optimization_modes,
.skip_single_threaded = true,
.skip_non_native = skip_non_native,
+ .skip_cross_glibc = skip_cross_glibc,
.skip_libc = true,
.skip_stage1 = skip_stage1,
.skip_stage2 = true, // TODO get all these passing
@@ -442,6 +446,7 @@ pub fn build(b: *std.Build) !void {
.optimize_modes = optimization_modes,
.skip_single_threaded = true,
.skip_non_native = skip_non_native,
+ .skip_cross_glibc = skip_cross_glibc,
.skip_libc = true,
.skip_stage1 = skip_stage1,
.skip_stage2 = true, // TODO get all these passing
@@ -473,6 +478,7 @@ pub fn build(b: *std.Build) !void {
.optimize_modes = optimization_modes,
.skip_single_threaded = skip_single_threaded,
.skip_non_native = skip_non_native,
+ .skip_cross_glibc = skip_cross_glibc,
.skip_libc = skip_libc,
.skip_stage1 = skip_stage1,
.skip_stage2 = true, // TODO get all these passing
diff --git a/test/tests.zig b/test/tests.zig
index 3166fbc14a..26e684cd0d 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -910,6 +910,7 @@ const ModuleTestOptions = struct {
optimize_modes: []const OptimizeMode,
skip_single_threaded: bool,
skip_non_native: bool,
+ skip_cross_glibc: bool,
skip_libc: bool,
skip_stage1: bool,
skip_stage2: bool,
@@ -923,6 +924,9 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
if (options.skip_non_native and !test_target.target.isNative())
continue;
+ if (options.skip_cross_glibc and test_target.target.isGnuLibC() and test_target.link_libc)
+ continue;
+
if (options.skip_libc and test_target.link_libc)
continue;
From e70a0b2a6b329a76e9edc4d22c7b923841703a24 Mon Sep 17 00:00:00 2001
From: Veikka Tuominen
Date: Tue, 21 Mar 2023 00:27:33 +0200
Subject: [PATCH 045/216] Value: implement reinterpreting enum field index as
integer
Closes #15019
---
src/value.zig | 5 +++++
test/behavior/union.zig | 20 ++++++++++++++++++++
2 files changed, 25 insertions(+)
diff --git a/src/value.zig b/src/value.zig
index 1b6d2adc1e..e677414c0f 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -1113,6 +1113,10 @@ pub const Value = extern union {
.bool_true,
=> return BigIntMutable.init(&space.limbs, 1).toConst(),
+ .enum_field_index => {
+ const index = val.castTag(.enum_field_index).?.data;
+ return BigIntMutable.init(&space.limbs, index).toConst();
+ },
.runtime_value => {
const sub_val = val.castTag(.runtime_value).?.data;
return sub_val.toBigIntAdvanced(space, target, opt_sema);
@@ -1983,6 +1987,7 @@ pub const Value = extern union {
.variable,
=> .gt,
+ .enum_field_index => return std.math.order(lhs.castTag(.enum_field_index).?.data, 0),
.runtime_value => {
// This is needed to correctly handle hashing the value.
// Checks in Sema should prevent direct comparisons from reaching here.
diff --git a/test/behavior/union.zig b/test/behavior/union.zig
index ff3f0b7e54..010b4a1ffa 100644
--- a/test/behavior/union.zig
+++ b/test/behavior/union.zig
@@ -1513,3 +1513,23 @@ test "packed union with zero-bit field" {
};
try S.doTest(.{ .nested = .{ .zero = {} }, .bar = 42 });
}
+
+test "reinterpreting enum value inside packed union" {
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+
+ const U = packed union {
+ tag: enum { a, b },
+ val: u8,
+
+ fn doTest() !void {
+ var u: @This() = .{ .tag = .a };
+ u.val += 1;
+ try expect(u.tag == .b);
+ }
+ };
+ try U.doTest();
+ comptime try U.doTest();
+}
From dff4bbfd2426ce4943972782d2bcffc89b3fd26d Mon Sep 17 00:00:00 2001
From: Frank Denis <124872+jedisct1@users.noreply.github.com>
Date: Tue, 21 Mar 2023 05:54:10 +0100
Subject: [PATCH 046/216] Remove Gimli and Xoodoo from the standard library
(#14928)
These are great permutations, and there's nothing wrong with them
from a practical security perspective.
However, both were competing in the NIST lightweight crypto
competition.
Gimli didn't pass the 3rd selection round, and is not much used
in the wild besides Zig and libhydrogen. It will never be
standardized and is unlikely to get more traction in the future.
Xoodyak, that Xoodoo is the permutation of, was a finalist.
It has a lot of advantages and *might* be standardized without NIST.
But this is too early to tell, and too risky to commit to it
in a standard library.
For lightweight crypto, Ascon is the one that we know NIST will
standardize and that we can safely rely on from a usage perspective.
Switch to a traditional ChaCha-based CSPRNG, with an Ascon-based one
as an option for constrained systems.
Add a RNG benchmark by the way.
Gimli and Xoodoo served us well. Their code will be maintained,
but outside the standard library.
---
lib/std/crypto.zig | 11 -
lib/std/crypto/ascon.zig | 11 +
lib/std/crypto/benchmark.zig | 2 -
lib/std/crypto/chacha20.zig | 77 ++++-
lib/std/crypto/gimli.zig | 527 -----------------------------------
lib/std/crypto/tlcsprng.zig | 18 +-
lib/std/crypto/xoodoo.zig | 141 ----------
lib/std/rand.zig | 5 +-
lib/std/rand/Ascon.zig | 47 ++--
lib/std/rand/ChaCha.zig | 97 +++++++
lib/std/rand/Gimli.zig | 34 ---
lib/std/rand/Xoodoo.zig | 42 ---
lib/std/rand/benchmark.zig | 217 +++++++++++++++
13 files changed, 443 insertions(+), 786 deletions(-)
delete mode 100644 lib/std/crypto/gimli.zig
delete mode 100644 lib/std/crypto/xoodoo.zig
create mode 100644 lib/std/rand/ChaCha.zig
delete mode 100644 lib/std/rand/Gimli.zig
delete mode 100644 lib/std/rand/Xoodoo.zig
create mode 100644 lib/std/rand/benchmark.zig
diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig
index 9b995480aa..6f0d1d9b6e 100644
--- a/lib/std/crypto.zig
+++ b/lib/std/crypto.zig
@@ -17,8 +17,6 @@ pub const aead = struct {
pub const Aes256Ocb = @import("crypto/aes_ocb.zig").Aes256Ocb;
};
- pub const Gimli = @import("crypto/gimli.zig").Aead;
-
pub const chacha_poly = struct {
pub const ChaCha20Poly1305 = @import("crypto/chacha20.zig").ChaCha20Poly1305;
pub const ChaCha12Poly1305 = @import("crypto/chacha20.zig").ChaCha12Poly1305;
@@ -52,8 +50,6 @@ pub const core = struct {
pub const keccak = @import("crypto/keccak_p.zig");
pub const Ascon = @import("crypto/ascon.zig").State;
- pub const Gimli = @import("crypto/gimli.zig").State;
- pub const Xoodoo = @import("crypto/xoodoo.zig").State;
/// Modes are generic compositions to construct encryption/decryption functions from block ciphers and permutations.
///
@@ -87,7 +83,6 @@ pub const ecc = struct {
pub const hash = struct {
pub const blake2 = @import("crypto/blake2.zig");
pub const Blake3 = @import("crypto/blake3.zig").Blake3;
- pub const Gimli = @import("crypto/gimli.zig").Hash;
pub const Md5 = @import("crypto/md5.zig").Md5;
pub const Sha1 = @import("crypto/sha1.zig").Sha1;
pub const sha2 = @import("crypto/sha2.zig");
@@ -221,8 +216,6 @@ test {
_ = aead.aes_ocb.Aes128Ocb;
_ = aead.aes_ocb.Aes256Ocb;
- _ = aead.Gimli;
-
_ = aead.chacha_poly.ChaCha20Poly1305;
_ = aead.chacha_poly.ChaCha12Poly1305;
_ = aead.chacha_poly.ChaCha8Poly1305;
@@ -239,8 +232,6 @@ test {
_ = core.aes;
_ = core.Ascon;
- _ = core.Gimli;
- _ = core.Xoodoo;
_ = core.modes;
_ = dh.X25519;
@@ -256,7 +247,6 @@ test {
_ = hash.blake2;
_ = hash.Blake3;
- _ = hash.Gimli;
_ = hash.Md5;
_ = hash.Sha1;
_ = hash.sha2;
@@ -334,7 +324,6 @@ test "issue #4532: no index out of bounds" {
hash.blake2.Blake2b256,
hash.blake2.Blake2b384,
hash.blake2.Blake2b512,
- hash.Gimli,
};
inline for (types) |Hasher| {
diff --git a/lib/std/crypto/ascon.zig b/lib/std/crypto/ascon.zig
index 6de003d436..f37d9acea5 100644
--- a/lib/std/crypto/ascon.zig
+++ b/lib/std/crypto/ascon.zig
@@ -168,6 +168,17 @@ pub fn State(comptime endian: builtin.Endian) type {
state.permuteR(12);
}
+ /// Apply a permutation to the state and prevent backtracking.
+ /// The rate is expressed in bytes and must be a multiple of the word size (8).
+ pub inline fn permuteRatchet(state: *Self, comptime rounds: u4, comptime rate: u6) void {
+ const capacity = block_bytes - rate;
+ debug.assert(capacity > 0 and capacity % 8 == 0); // capacity must be a multiple of 64 bits
+ var mask: [capacity / 8]u64 = undefined;
+ inline for (&mask, state.st[state.st.len - mask.len ..]) |*m, x| m.* = x;
+ state.permuteR(rounds);
+ inline for (mask, state.st[state.st.len - mask.len ..]) |m, *x| x.* ^= m;
+ }
+
// Core Ascon permutation.
inline fn round(state: *Self, rk: u64) void {
const x = &state.st;
diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig
index ff098c7804..f512c513e7 100644
--- a/lib/std/crypto/benchmark.zig
+++ b/lib/std/crypto/benchmark.zig
@@ -29,7 +29,6 @@ const hashes = [_]Crypto{
Crypto{ .ty = crypto.hash.sha3.Shake256, .name = "shake-256" },
Crypto{ .ty = crypto.hash.sha3.TurboShake128(null), .name = "turboshake-128" },
Crypto{ .ty = crypto.hash.sha3.TurboShake256(null), .name = "turboshake-256" },
- Crypto{ .ty = crypto.hash.Gimli, .name = "gimli-hash" },
Crypto{ .ty = crypto.hash.blake2.Blake2s256, .name = "blake2s" },
Crypto{ .ty = crypto.hash.blake2.Blake2b512, .name = "blake2b" },
Crypto{ .ty = crypto.hash.Blake3, .name = "blake3" },
@@ -274,7 +273,6 @@ const aeads = [_]Crypto{
Crypto{ .ty = crypto.aead.chacha_poly.XChaCha20Poly1305, .name = "xchacha20Poly1305" },
Crypto{ .ty = crypto.aead.chacha_poly.XChaCha8Poly1305, .name = "xchacha8Poly1305" },
Crypto{ .ty = crypto.aead.salsa_poly.XSalsa20Poly1305, .name = "xsalsa20Poly1305" },
- Crypto{ .ty = crypto.aead.Gimli, .name = "gimli-aead" },
Crypto{ .ty = crypto.aead.aegis.Aegis128L, .name = "aegis-128l" },
Crypto{ .ty = crypto.aead.aegis.Aegis256, .name = "aegis-256" },
Crypto{ .ty = crypto.aead.aes_gcm.Aes128Gcm, .name = "aes128-gcm" },
diff --git a/lib/std/crypto/chacha20.zig b/lib/std/crypto/chacha20.zig
index 883ee51a62..aa0f148be9 100644
--- a/lib/std/crypto/chacha20.zig
+++ b/lib/std/crypto/chacha20.zig
@@ -195,6 +195,26 @@ fn ChaChaVecImpl(comptime rounds_nb: usize) type {
}
}
+ fn chacha20Stream(out: []u8, key: [8]u32, counter: [4]u32) void {
+ var ctx = initContext(key, counter);
+ var x: BlockVec = undefined;
+ var i: usize = 0;
+ while (i + 64 <= out.len) : (i += 64) {
+ chacha20Core(x[0..], ctx);
+ contextFeedback(&x, ctx);
+ hashToBytes(out[i..][0..64], x);
+ ctx[3][0] += 1;
+ }
+ if (i < out.len) {
+ chacha20Core(x[0..], ctx);
+ contextFeedback(&x, ctx);
+
+ var buf: [64]u8 = undefined;
+ hashToBytes(buf[0..], x);
+ mem.copy(u8, out[i..], buf[0 .. out.len - i]);
+ }
+ }
+
fn hchacha20(input: [16]u8, key: [32]u8) [32]u8 {
var c: [4]u32 = undefined;
for (c, 0..) |_, i| {
@@ -336,6 +356,26 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type {
}
}
+ fn chacha20Stream(out: []u8, key: [8]u32, counter: [4]u32) void {
+ var ctx = initContext(key, counter);
+ var x: BlockVec = undefined;
+ var i: usize = 0;
+ while (i + 64 <= out.len) : (i += 64) {
+ chacha20Core(x[0..], ctx);
+ contextFeedback(&x, ctx);
+ hashToBytes(out[i..][0..64], x);
+ ctx[12] += 1;
+ }
+ if (i < out.len) {
+ chacha20Core(x[0..], ctx);
+ contextFeedback(&x, ctx);
+
+ var buf: [64]u8 = undefined;
+ hashToBytes(buf[0..], x);
+ mem.copy(u8, out[i..], buf[0 .. out.len - i]);
+ }
+ }
+
fn hchacha20(input: [16]u8, key: [32]u8) [32]u8 {
var c: [4]u32 = undefined;
for (c, 0..) |_, i| {
@@ -387,6 +427,8 @@ fn ChaChaIETF(comptime rounds_nb: usize) type {
pub const nonce_length = 12;
/// Key length in bytes.
pub const key_length = 32;
+ /// Block length in bytes.
+ pub const block_length = 64;
/// Add the output of the ChaCha20 stream cipher to `in` and stores the result into `out`.
/// WARNING: This function doesn't provide authenticated encryption.
@@ -402,6 +444,18 @@ fn ChaChaIETF(comptime rounds_nb: usize) type {
d[3] = mem.readIntLittle(u32, nonce[8..12]);
ChaChaImpl(rounds_nb).chacha20Xor(out, in, keyToWords(key), d);
}
+
+ /// Write the output of the ChaCha20 stream cipher into `out`.
+ pub fn stream(out: []u8, counter: u32, key: [key_length]u8, nonce: [nonce_length]u8) void {
+ assert(out.len / 64 <= (1 << 32 - 1) - counter);
+
+ var d: [4]u32 = undefined;
+ d[0] = counter;
+ d[1] = mem.readIntLittle(u32, nonce[0..4]);
+ d[2] = mem.readIntLittle(u32, nonce[4..8]);
+ d[3] = mem.readIntLittle(u32, nonce[8..12]);
+ ChaChaImpl(rounds_nb).chacha20Stream(out, keyToWords(key), d);
+ }
};
}
@@ -411,6 +465,8 @@ fn ChaChaWith64BitNonce(comptime rounds_nb: usize) type {
pub const nonce_length = 8;
/// Key length in bytes.
pub const key_length = 32;
+ /// Block length in bytes.
+ pub const block_length = 64;
/// Add the output of the ChaCha20 stream cipher to `in` and stores the result into `out`.
/// WARNING: This function doesn't provide authenticated encryption.
@@ -427,7 +483,6 @@ fn ChaChaWith64BitNonce(comptime rounds_nb: usize) type {
c[2] = mem.readIntLittle(u32, nonce[0..4]);
c[3] = mem.readIntLittle(u32, nonce[4..8]);
- const block_length = (1 << 6);
// The full block size is greater than the address space on a 32bit machine
const big_block = if (@sizeOf(usize) > 4) (block_length << 32) else maxInt(usize);
@@ -448,6 +503,18 @@ fn ChaChaWith64BitNonce(comptime rounds_nb: usize) type {
}
ChaChaImpl(rounds_nb).chacha20Xor(out[cursor..], in[cursor..], k, c);
}
+
+ /// Write the output of the ChaCha20 stream cipher into `out`.
+ pub fn stream(out: []u8, counter: u32, key: [key_length]u8, nonce: [nonce_length]u8) void {
+ assert(out.len / 64 <= (1 << 32 - 1) - counter);
+ const k = keyToWords(key);
+ var c: [4]u32 = undefined;
+ c[0] = @truncate(u32, counter);
+ c[1] = @truncate(u32, counter >> 32);
+ c[2] = mem.readIntLittle(u32, nonce[0..4]);
+ c[3] = mem.readIntLittle(u32, nonce[4..8]);
+ ChaChaImpl(rounds_nb).chacha20Stream(out, k, c);
+ }
};
}
@@ -457,6 +524,8 @@ fn XChaChaIETF(comptime rounds_nb: usize) type {
pub const nonce_length = 24;
/// Key length in bytes.
pub const key_length = 32;
+ /// Block length in bytes.
+ pub const block_length = 64;
/// Add the output of the XChaCha20 stream cipher to `in` and stores the result into `out`.
/// WARNING: This function doesn't provide authenticated encryption.
@@ -465,6 +534,12 @@ fn XChaChaIETF(comptime rounds_nb: usize) type {
const extended = extend(key, nonce, rounds_nb);
ChaChaIETF(rounds_nb).xor(out, in, counter, extended.key, extended.nonce);
}
+
+ /// Write the output of the XChaCha20 stream cipher into `out`.
+ pub fn stream(out: []u8, counter: u32, key: [key_length]u8, nonce: [nonce_length]u8) void {
+ const extended = extend(key, nonce, rounds_nb);
+ ChaChaIETF(rounds_nb).xor(out, counter, extended.key, extended.nonce);
+ }
};
}
diff --git a/lib/std/crypto/gimli.zig b/lib/std/crypto/gimli.zig
deleted file mode 100644
index 0189f4c359..0000000000
--- a/lib/std/crypto/gimli.zig
+++ /dev/null
@@ -1,527 +0,0 @@
-//! Gimli is a 384-bit permutation designed to achieve high security with high
-//! performance across a broad range of platforms, including 64-bit Intel/AMD
-//! server CPUs, 64-bit and 32-bit ARM smartphone CPUs, 32-bit ARM
-//! microcontrollers, 8-bit AVR microcontrollers, FPGAs, ASICs without
-//! side-channel protection, and ASICs with side-channel protection.
-//!
-//! https://gimli.cr.yp.to/
-//! https://csrc.nist.gov/CSRC/media/Projects/Lightweight-Cryptography/documents/round-1/spec-doc/gimli-spec.pdf
-
-const std = @import("../std.zig");
-const builtin = @import("builtin");
-const mem = std.mem;
-const math = std.math;
-const debug = std.debug;
-const assert = std.debug.assert;
-const testing = std.testing;
-const htest = @import("test.zig");
-const AuthenticationError = std.crypto.errors.AuthenticationError;
-
-pub const State = struct {
- pub const BLOCKBYTES = 48;
- pub const RATE = 16;
-
- data: [BLOCKBYTES / 4]u32 align(16),
-
- const Self = @This();
-
- pub fn init(initial_state: [State.BLOCKBYTES]u8) Self {
- var data: [BLOCKBYTES / 4]u32 = undefined;
- var i: usize = 0;
- while (i < State.BLOCKBYTES) : (i += 4) {
- data[i / 4] = mem.readIntNative(u32, initial_state[i..][0..4]);
- }
- return Self{ .data = data };
- }
-
- /// TODO follow the span() convention instead of having this and `toSliceConst`
- pub fn toSlice(self: *Self) *[BLOCKBYTES]u8 {
- return mem.asBytes(&self.data);
- }
-
- /// TODO follow the span() convention instead of having this and `toSlice`
- pub fn toSliceConst(self: *const Self) *const [BLOCKBYTES]u8 {
- return mem.asBytes(&self.data);
- }
-
- inline fn endianSwap(self: *Self) void {
- for (&self.data) |*w| {
- w.* = mem.littleToNative(u32, w.*);
- }
- }
-
- fn permute_unrolled(self: *Self) void {
- self.endianSwap();
- const state = &self.data;
- comptime var round = @as(u32, 24);
- inline while (round > 0) : (round -= 1) {
- var column = @as(usize, 0);
- while (column < 4) : (column += 1) {
- const x = math.rotl(u32, state[column], 24);
- const y = math.rotl(u32, state[4 + column], 9);
- const z = state[8 + column];
- state[8 + column] = ((x ^ (z << 1)) ^ ((y & z) << 2));
- state[4 + column] = ((y ^ x) ^ ((x | z) << 1));
- state[column] = ((z ^ y) ^ ((x & y) << 3));
- }
- switch (round & 3) {
- 0 => {
- mem.swap(u32, &state[0], &state[1]);
- mem.swap(u32, &state[2], &state[3]);
- state[0] ^= round | 0x9e377900;
- },
- 2 => {
- mem.swap(u32, &state[0], &state[2]);
- mem.swap(u32, &state[1], &state[3]);
- },
- else => {},
- }
- }
- self.endianSwap();
- }
-
- fn permute_small(self: *Self) void {
- self.endianSwap();
- const state = &self.data;
- var round = @as(u32, 24);
- while (round > 0) : (round -= 1) {
- var column = @as(usize, 0);
- while (column < 4) : (column += 1) {
- const x = math.rotl(u32, state[column], 24);
- const y = math.rotl(u32, state[4 + column], 9);
- const z = state[8 + column];
- state[8 + column] = ((x ^ (z << 1)) ^ ((y & z) << 2));
- state[4 + column] = ((y ^ x) ^ ((x | z) << 1));
- state[column] = ((z ^ y) ^ ((x & y) << 3));
- }
- switch (round & 3) {
- 0 => {
- mem.swap(u32, &state[0], &state[1]);
- mem.swap(u32, &state[2], &state[3]);
- state[0] ^= round | 0x9e377900;
- },
- 2 => {
- mem.swap(u32, &state[0], &state[2]);
- mem.swap(u32, &state[1], &state[3]);
- },
- else => {},
- }
- }
- self.endianSwap();
- }
-
- const Lane = @Vector(4, u32);
-
- inline fn shift(x: Lane, comptime n: comptime_int) Lane {
- return x << @splat(4, @as(u5, n));
- }
-
- fn permute_vectorized(self: *Self) void {
- self.endianSwap();
- const state = &self.data;
- var x = Lane{ state[0], state[1], state[2], state[3] };
- var y = Lane{ state[4], state[5], state[6], state[7] };
- var z = Lane{ state[8], state[9], state[10], state[11] };
- var round = @as(u32, 24);
- while (round > 0) : (round -= 1) {
- x = math.rotl(Lane, x, 24);
- y = math.rotl(Lane, y, 9);
- const newz = x ^ shift(z, 1) ^ shift(y & z, 2);
- const newy = y ^ x ^ shift(x | z, 1);
- const newx = z ^ y ^ shift(x & y, 3);
- x = newx;
- y = newy;
- z = newz;
- switch (round & 3) {
- 0 => {
- x = @shuffle(u32, x, undefined, [_]i32{ 1, 0, 3, 2 });
- x[0] ^= round | 0x9e377900;
- },
- 2 => {
- x = @shuffle(u32, x, undefined, [_]i32{ 2, 3, 0, 1 });
- },
- else => {},
- }
- }
- comptime var i: usize = 0;
- inline while (i < 4) : (i += 1) {
- state[0 + i] = x[i];
- state[4 + i] = y[i];
- state[8 + i] = z[i];
- }
- self.endianSwap();
- }
-
- pub const permute = if (builtin.cpu.arch == .x86_64) impl: {
- break :impl permute_vectorized;
- } else if (builtin.mode == .ReleaseSmall) impl: {
- break :impl permute_small;
- } else impl: {
- break :impl permute_unrolled;
- };
-
- pub fn squeeze(self: *Self, out: []u8) void {
- var i = @as(usize, 0);
- while (i + RATE <= out.len) : (i += RATE) {
- self.permute();
- mem.copy(u8, out[i..], self.toSliceConst()[0..RATE]);
- }
- const leftover = out.len - i;
- if (leftover != 0) {
- self.permute();
- mem.copy(u8, out[i..], self.toSliceConst()[0..leftover]);
- }
- }
-};
-
-test "permute" {
- // test vector from gimli-20170627
- const tv_input = [3][4]u32{
- [4]u32{ 0x00000000, 0x9e3779ba, 0x3c6ef37a, 0xdaa66d46 },
- [4]u32{ 0x78dde724, 0x1715611a, 0xb54cdb2e, 0x53845566 },
- [4]u32{ 0xf1bbcfc8, 0x8ff34a5a, 0x2e2ac522, 0xcc624026 },
- };
- var input: [48]u8 = undefined;
- var i: usize = 0;
- while (i < 12) : (i += 1) {
- mem.writeIntLittle(u32, input[i * 4 ..][0..4], tv_input[i / 4][i % 4]);
- }
-
- var state = State.init(input);
- state.permute();
-
- const tv_output = [3][4]u32{
- [4]u32{ 0xba11c85a, 0x91bad119, 0x380ce880, 0xd24c2c68 },
- [4]u32{ 0x3eceffea, 0x277a921c, 0x4f73a0bd, 0xda5a9cd8 },
- [4]u32{ 0x84b673f0, 0x34e52ff7, 0x9e2bef49, 0xf41bb8d6 },
- };
- var expected_output: [48]u8 = undefined;
- i = 0;
- while (i < 12) : (i += 1) {
- mem.writeIntLittle(u32, expected_output[i * 4 ..][0..4], tv_output[i / 4][i % 4]);
- }
- try testing.expectEqualSlices(u8, state.toSliceConst(), expected_output[0..]);
-}
-
-pub const Hash = struct {
- state: State,
- buf_off: usize,
-
- pub const block_length = State.RATE;
- pub const digest_length = 32;
- pub const Options = struct {};
-
- const Self = @This();
-
- pub fn init(options: Options) Self {
- _ = options;
- return Self{
- .state = State{ .data = [_]u32{0} ** (State.BLOCKBYTES / 4) },
- .buf_off = 0,
- };
- }
-
- /// Also known as 'absorb'
- pub fn update(self: *Self, data: []const u8) void {
- const buf = self.state.toSlice();
- var in = data;
- while (in.len > 0) {
- const left = State.RATE - self.buf_off;
- const ps = math.min(in.len, left);
- for (buf[self.buf_off .. self.buf_off + ps], 0..) |*p, i| {
- p.* ^= in[i];
- }
- self.buf_off += ps;
- in = in[ps..];
- if (self.buf_off == State.RATE) {
- self.state.permute();
- self.buf_off = 0;
- }
- }
- }
-
- /// Finish the current hashing operation, writing the hash to `out`
- ///
- /// From 4.9 "Application to hashing"
- /// By default, Gimli-Hash provides a fixed-length output of 32 bytes
- /// (the concatenation of two 16-byte blocks). However, Gimli-Hash can
- /// be used as an “extendable one-way function” (XOF).
- pub fn final(self: *Self, out: []u8) void {
- const buf = self.state.toSlice();
-
- // XOR 1 into the next byte of the state
- buf[self.buf_off] ^= 1;
- // XOR 1 into the last byte of the state, position 47.
- buf[buf.len - 1] ^= 1;
-
- self.state.squeeze(out);
- }
-
- pub const Error = error{};
- pub const Writer = std.io.Writer(*Self, Error, write);
-
- fn write(self: *Self, bytes: []const u8) Error!usize {
- self.update(bytes);
- return bytes.len;
- }
-
- pub fn writer(self: *Self) Writer {
- return .{ .context = self };
- }
-};
-
-pub fn hash(out: []u8, in: []const u8, options: Hash.Options) void {
- var st = Hash.init(options);
- st.update(in);
- st.final(out);
-}
-
-test "hash" {
- // a test vector (30) from NIST KAT submission.
- var msg: [58 / 2]u8 = undefined;
- _ = try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C");
- var md: [32]u8 = undefined;
- hash(&md, &msg, .{});
- try htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", &md);
-}
-
-test "hash test vector 17" {
- var msg: [32 / 2]u8 = undefined;
- _ = try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F");
- var md: [32]u8 = undefined;
- hash(&md, &msg, .{});
- try htest.assertEqual("404C130AF1B9023A7908200919F690FFBB756D5176E056FFDE320016A37C7282", &md);
-}
-
-test "hash test vector 33" {
- var msg: [32]u8 = undefined;
- _ = try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
- var md: [32]u8 = undefined;
- hash(&md, &msg, .{});
- try htest.assertEqual("A8F4FA28708BDA7EFB4C1914CA4AFA9E475B82D588D36504F87DBB0ED9AB3C4B", &md);
-}
-
-pub const Aead = struct {
- pub const tag_length = State.RATE;
- pub const nonce_length = 16;
- pub const key_length = 32;
-
- /// ad: Associated Data
- /// npub: public nonce
- /// k: private key
- fn init(ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) State {
- var state = State{
- .data = undefined,
- };
- const buf = state.toSlice();
-
- // Gimli-Cipher initializes a 48-byte Gimli state to a 16-byte nonce
- // followed by a 32-byte key.
- assert(npub.len + k.len == State.BLOCKBYTES);
- std.mem.copy(u8, buf[0..npub.len], &npub);
- std.mem.copy(u8, buf[npub.len .. npub.len + k.len], &k);
-
- // It then applies the Gimli permutation.
- state.permute();
-
- {
- // Gimli-Cipher then handles each block of associated data, including
- // exactly one final non-full block, in the same way as Gimli-Hash.
- var data = ad;
- while (data.len >= State.RATE) : (data = data[State.RATE..]) {
- for (buf[0..State.RATE], 0..) |*p, i| {
- p.* ^= data[i];
- }
- state.permute();
- }
- for (buf[0..data.len], 0..) |*p, i| {
- p.* ^= data[i];
- }
-
- // XOR 1 into the next byte of the state
- buf[data.len] ^= 1;
- // XOR 1 into the last byte of the state, position 47.
- buf[buf.len - 1] ^= 1;
-
- state.permute();
- }
-
- return state;
- }
-
- /// c: ciphertext: output buffer should be of size m.len
- /// tag: authentication tag: output MAC
- /// m: message
- /// ad: Associated Data
- /// npub: public nonce
- /// k: private key
- pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) void {
- assert(c.len == m.len);
-
- var state = Aead.init(ad, npub, k);
- const buf = state.toSlice();
-
- // Gimli-Cipher then handles each block of plaintext, including
- // exactly one final non-full block, in the same way as Gimli-Hash.
- // Whenever a plaintext byte is XORed into a state byte, the new state
- // byte is output as ciphertext.
- var in = m;
- var out = c;
- while (in.len >= State.RATE) : ({
- in = in[State.RATE..];
- out = out[State.RATE..];
- }) {
- for (in[0..State.RATE], 0..) |v, i| {
- buf[i] ^= v;
- }
- mem.copy(u8, out[0..State.RATE], buf[0..State.RATE]);
- state.permute();
- }
- for (in[0..], 0..) |v, i| {
- buf[i] ^= v;
- out[i] = buf[i];
- }
-
- // XOR 1 into the next byte of the state
- buf[in.len] ^= 1;
- // XOR 1 into the last byte of the state, position 47.
- buf[buf.len - 1] ^= 1;
-
- state.permute();
-
- // After the final non-full block of plaintext, the first 16 bytes
- // of the state are output as an authentication tag.
- std.mem.copy(u8, tag, buf[0..State.RATE]);
- }
-
- /// m: message: output buffer should be of size c.len
- /// c: ciphertext
- /// tag: authentication tag
- /// ad: Associated Data
- /// npub: public nonce
- /// k: private key
- /// NOTE: the check of the authentication tag is currently not done in constant time
- pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
- assert(c.len == m.len);
-
- var state = Aead.init(ad, npub, k);
- const buf = state.toSlice();
-
- var in = c;
- var out = m;
- while (in.len >= State.RATE) : ({
- in = in[State.RATE..];
- out = out[State.RATE..];
- }) {
- const d = in[0..State.RATE].*;
- for (d, 0..) |v, i| {
- out[i] = buf[i] ^ v;
- }
- mem.copy(u8, buf[0..State.RATE], d[0..State.RATE]);
- state.permute();
- }
- for (buf[0..in.len], 0..) |*p, i| {
- const d = in[i];
- out[i] = p.* ^ d;
- p.* = d;
- }
-
- // XOR 1 into the next byte of the state
- buf[in.len] ^= 1;
- // XOR 1 into the last byte of the state, position 47.
- buf[buf.len - 1] ^= 1;
-
- state.permute();
-
- // After the final non-full block of plaintext, the first 16 bytes
- // of the state are the authentication tag.
- // TODO: use a constant-time equality check here, see https://github.com/ziglang/zig/issues/1776
- if (!mem.eql(u8, buf[0..State.RATE], &tag)) {
- @memset(m.ptr, undefined, m.len);
- return error.AuthenticationFailed;
- }
- }
-};
-
-test "cipher" {
- var key: [32]u8 = undefined;
- _ = try std.fmt.hexToBytes(&key, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
- var nonce: [16]u8 = undefined;
- _ = try std.fmt.hexToBytes(&nonce, "000102030405060708090A0B0C0D0E0F");
- { // test vector (1) from NIST KAT submission.
- const ad: [0]u8 = undefined;
- const pt: [0]u8 = undefined;
-
- var ct: [pt.len]u8 = undefined;
- var tag: [16]u8 = undefined;
- Aead.encrypt(&ct, &tag, &pt, &ad, nonce, key);
- try htest.assertEqual("", &ct);
- try htest.assertEqual("14DA9BB7120BF58B985A8E00FDEBA15B", &tag);
-
- var pt2: [pt.len]u8 = undefined;
- try Aead.decrypt(&pt2, &ct, tag, &ad, nonce, key);
- try testing.expectEqualSlices(u8, &pt, &pt2);
- }
- { // test vector (34) from NIST KAT submission.
- const ad: [0]u8 = undefined;
- var pt: [2 / 2]u8 = undefined;
- _ = try std.fmt.hexToBytes(&pt, "00");
-
- var ct: [pt.len]u8 = undefined;
- var tag: [16]u8 = undefined;
- Aead.encrypt(&ct, &tag, &pt, &ad, nonce, key);
- try htest.assertEqual("7F", &ct);
- try htest.assertEqual("80492C317B1CD58A1EDC3A0D3E9876FC", &tag);
-
- var pt2: [pt.len]u8 = undefined;
- try Aead.decrypt(&pt2, &ct, tag, &ad, nonce, key);
- try testing.expectEqualSlices(u8, &pt, &pt2);
- }
- { // test vector (106) from NIST KAT submission.
- var ad: [12 / 2]u8 = undefined;
- _ = try std.fmt.hexToBytes(&ad, "000102030405");
- var pt: [6 / 2]u8 = undefined;
- _ = try std.fmt.hexToBytes(&pt, "000102");
-
- var ct: [pt.len]u8 = undefined;
- var tag: [16]u8 = undefined;
- Aead.encrypt(&ct, &tag, &pt, &ad, nonce, key);
- try htest.assertEqual("484D35", &ct);
- try htest.assertEqual("030BBEA23B61C00CED60A923BDCF9147", &tag);
-
- var pt2: [pt.len]u8 = undefined;
- try Aead.decrypt(&pt2, &ct, tag, &ad, nonce, key);
- try testing.expectEqualSlices(u8, &pt, &pt2);
- }
- { // test vector (790) from NIST KAT submission.
- var ad: [60 / 2]u8 = undefined;
- _ = try std.fmt.hexToBytes(&ad, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D");
- var pt: [46 / 2]u8 = undefined;
- _ = try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F10111213141516");
-
- var ct: [pt.len]u8 = undefined;
- var tag: [16]u8 = undefined;
- Aead.encrypt(&ct, &tag, &pt, &ad, nonce, key);
- try htest.assertEqual("6815B4A0ECDAD01596EAD87D9E690697475D234C6A13D1", &ct);
- try htest.assertEqual("DFE23F1642508290D68245279558B2FB", &tag);
-
- var pt2: [pt.len]u8 = undefined;
- try Aead.decrypt(&pt2, &ct, tag, &ad, nonce, key);
- try testing.expectEqualSlices(u8, &pt, &pt2);
- }
- { // test vector (1057) from NIST KAT submission.
- const ad: [0]u8 = undefined;
- var pt: [64 / 2]u8 = undefined;
- _ = try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
-
- var ct: [pt.len]u8 = undefined;
- var tag: [16]u8 = undefined;
- Aead.encrypt(&ct, &tag, &pt, &ad, nonce, key);
- try htest.assertEqual("7F8A2CF4F52AA4D6B2E74105C30A2777B9D0C8AEFDD555DE35861BD3011F652F", &ct);
- try htest.assertEqual("7256456FA935AC34BBF55AE135F33257", &tag);
-
- var pt2: [pt.len]u8 = undefined;
- try Aead.decrypt(&pt2, &ct, tag, &ad, nonce, key);
- try testing.expectEqualSlices(u8, &pt, &pt2);
- }
-}
diff --git a/lib/std/crypto/tlcsprng.zig b/lib/std/crypto/tlcsprng.zig
index 5a09e20f07..ac706e5f6a 100644
--- a/lib/std/crypto/tlcsprng.zig
+++ b/lib/std/crypto/tlcsprng.zig
@@ -41,9 +41,11 @@ const maybe_have_wipe_on_fork = builtin.os.isAtLeast(.linux, .{
}) orelse true;
const is_haiku = builtin.os.tag == .haiku;
+const Rng = std.rand.DefaultCsprng;
+
const Context = struct {
init_state: enum(u8) { uninitialized = 0, initialized, failed },
- gimli: std.crypto.core.Gimli,
+ rng: Rng,
};
var install_atfork_handler = std.once(struct {
@@ -93,7 +95,7 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void {
const S = struct {
threadlocal var buf: Context align(mem.page_size) = .{
.init_state = .uninitialized,
- .gimli = undefined,
+ .rng = undefined,
};
};
wipe_mem = mem.asBytes(&S.buf);
@@ -156,12 +158,7 @@ fn childAtForkHandler() callconv(.C) void {
fn fillWithCsprng(buffer: []u8) void {
const ctx = @ptrCast(*Context, wipe_mem.ptr);
- if (buffer.len != 0) {
- ctx.gimli.squeeze(buffer);
- } else {
- ctx.gimli.permute();
- }
- mem.set(u8, ctx.gimli.toSlice()[0..std.crypto.core.Gimli.RATE], 0);
+ return ctx.rng.fill(buffer);
}
pub fn defaultRandomSeed(buffer: []u8) void {
@@ -169,7 +166,7 @@ pub fn defaultRandomSeed(buffer: []u8) void {
}
fn initAndFill(buffer: []u8) void {
- var seed: [std.crypto.core.Gimli.BLOCKBYTES]u8 = undefined;
+ var seed: [Rng.secret_seed_length]u8 = undefined;
// Because we panic on getrandom() failing, we provide the opportunity
// to override the default seed function. This also makes
// `std.crypto.random` available on freestanding targets, provided that
@@ -177,7 +174,8 @@ fn initAndFill(buffer: []u8) void {
std.options.cryptoRandomSeed(&seed);
const ctx = @ptrCast(*Context, wipe_mem.ptr);
- ctx.gimli = std.crypto.core.Gimli.init(seed);
+ ctx.rng = Rng.init(seed);
+ std.crypto.utils.secureZero(u8, &seed);
// This is at the end so that accidental recursive dependencies result
// in stack overflows instead of invalid random data.
diff --git a/lib/std/crypto/xoodoo.zig b/lib/std/crypto/xoodoo.zig
deleted file mode 100644
index ea3554a635..0000000000
--- a/lib/std/crypto/xoodoo.zig
+++ /dev/null
@@ -1,141 +0,0 @@
-//! Xoodoo is a 384-bit permutation designed to achieve high security with high
-//! performance across a broad range of platforms, including 64-bit Intel/AMD
-//! server CPUs, 64-bit and 32-bit ARM smartphone CPUs, 32-bit ARM
-//! microcontrollers, 8-bit AVR microcontrollers, FPGAs, ASICs without
-//! side-channel protection, and ASICs with side-channel protection.
-//!
-//! Xoodoo is the core function of Xoodyak, a finalist of the NIST lightweight cryptography competition.
-//! https://csrc.nist.gov/CSRC/media/Projects/Lightweight-Cryptography/documents/round-1/spec-doc/Xoodyak-spec.pdf
-//!
-//! It is not meant to be used directly, but as a building block for symmetric cryptography.
-
-const std = @import("../std.zig");
-const builtin = @import("builtin");
-const mem = std.mem;
-const math = std.math;
-const testing = std.testing;
-
-/// A Xoodoo state.
-pub const State = struct {
- /// Number of bytes in the state.
- pub const block_bytes = 48;
-
- const rcs = [12]u32{ 0x058, 0x038, 0x3c0, 0x0d0, 0x120, 0x014, 0x060, 0x02c, 0x380, 0x0f0, 0x1a0, 0x012 };
- const Lane = @Vector(4, u32);
- st: [3]Lane,
-
- /// Initialize a state from a slice of bytes.
- pub fn init(initial_state: [block_bytes]u8) State {
- var state = State{ .st = undefined };
- mem.copy(u8, state.asBytes(), &initial_state);
- state.endianSwap();
- return state;
- }
-
- // A representation of the state as 32-bit words.
- fn asWords(self: *State) *[12]u32 {
- return @ptrCast(*[12]u32, &self.st);
- }
-
- /// A representation of the state as bytes. The byte order is architecture-dependent.
- pub fn asBytes(self: *State) *[block_bytes]u8 {
- return mem.asBytes(&self.st);
- }
-
- /// Byte-swap words storing the bytes of a given range if the architecture is not little-endian.
- pub fn endianSwapPartial(self: *State, from: usize, to: usize) void {
- for (self.asWords()[from / 4 .. (to + 3) / 4]) |*w| {
- w.* = mem.littleToNative(u32, w.*);
- }
- }
-
- /// Byte-swap the entire state if the architecture is not little-endian.
- pub fn endianSwap(self: *State) void {
- for (self.asWords()) |*w| {
- w.* = mem.littleToNative(u32, w.*);
- }
- }
-
- /// XOR a byte into the state at a given offset.
- pub fn addByte(self: *State, byte: u8, offset: usize) void {
- self.endianSwapPartial(offset, offset);
- self.asBytes()[offset] ^= byte;
- self.endianSwapPartial(offset, offset);
- }
-
- /// XOR bytes into the beginning of the state.
- pub fn addBytes(self: *State, bytes: []const u8) void {
- self.endianSwap();
- for (self.asBytes()[0..bytes.len], 0..) |*byte, i| {
- byte.* ^= bytes[i];
- }
- self.endianSwap();
- }
-
- /// Extract the first bytes of the state.
- pub fn extract(self: *State, out: []u8) void {
- self.endianSwap();
- mem.copy(u8, out, self.asBytes()[0..out.len]);
- self.endianSwap();
- }
-
- /// Set the words storing the bytes of a given range to zero.
- pub fn clear(self: *State, from: usize, to: usize) void {
- mem.set(u32, self.asWords()[from / 4 .. (to + 3) / 4], 0);
- }
-
- /// Apply the Xoodoo permutation.
- pub fn permute(self: *State) void {
- const rot8x32 = comptime if (builtin.target.cpu.arch.endian() == .Big)
- [_]i32{ 9, 10, 11, 8, 13, 14, 15, 12, 1, 2, 3, 0, 5, 6, 7, 4 }
- else
- [_]i32{ 11, 8, 9, 10, 15, 12, 13, 14, 3, 0, 1, 2, 7, 4, 5, 6 };
-
- var a = self.st[0];
- var b = self.st[1];
- var c = self.st[2];
- inline for (rcs) |rc| {
- var p = @shuffle(u32, a ^ b ^ c, undefined, [_]i32{ 3, 0, 1, 2 });
- var e = math.rotl(Lane, p, 5);
- p = math.rotl(Lane, p, 14);
- e ^= p;
- a ^= e;
- b ^= e;
- c ^= e;
- b = @shuffle(u32, b, undefined, [_]i32{ 3, 0, 1, 2 });
- c = math.rotl(Lane, c, 11);
- a[0] ^= rc;
- a ^= ~b & c;
- b ^= ~c & a;
- c ^= ~a & b;
- b = math.rotl(Lane, b, 1);
- c = @bitCast(Lane, @shuffle(u8, @bitCast(@Vector(16, u8), c), undefined, rot8x32));
- }
- self.st[0] = a;
- self.st[1] = b;
- self.st[2] = c;
- }
-};
-
-test "xoodoo" {
- const bytes = [_]u8{0x01} ** State.block_bytes;
- var st = State.init(bytes);
- var out: [State.block_bytes]u8 = undefined;
- st.permute();
- st.extract(&out);
- const expected1 = [_]u8{ 51, 240, 163, 117, 43, 238, 62, 200, 114, 52, 79, 41, 48, 108, 150, 181, 24, 5, 252, 185, 235, 179, 28, 3, 116, 170, 36, 15, 232, 35, 116, 61, 110, 4, 109, 227, 91, 205, 0, 180, 179, 146, 112, 235, 96, 212, 206, 205 };
- try testing.expectEqualSlices(u8, &expected1, &out);
- st.clear(0, 10);
- st.extract(&out);
- const expected2 = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 108, 150, 181, 24, 5, 252, 185, 235, 179, 28, 3, 116, 170, 36, 15, 232, 35, 116, 61, 110, 4, 109, 227, 91, 205, 0, 180, 179, 146, 112, 235, 96, 212, 206, 205 };
- try testing.expectEqualSlices(u8, &expected2, &out);
- st.addByte(1, 5);
- st.addByte(2, 5);
- st.extract(&out);
- const expected3 = [_]u8{ 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 48, 108, 150, 181, 24, 5, 252, 185, 235, 179, 28, 3, 116, 170, 36, 15, 232, 35, 116, 61, 110, 4, 109, 227, 91, 205, 0, 180, 179, 146, 112, 235, 96, 212, 206, 205 };
- try testing.expectEqualSlices(u8, &expected3, &out);
- st.addBytes(&bytes);
- st.extract(&out);
- const expected4 = [_]u8{ 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 49, 109, 151, 180, 25, 4, 253, 184, 234, 178, 29, 2, 117, 171, 37, 14, 233, 34, 117, 60, 111, 5, 108, 226, 90, 204, 1, 181, 178, 147, 113, 234, 97, 213, 207, 204 };
- try testing.expectEqualSlices(u8, &expected4, &out);
-}
diff --git a/lib/std/rand.zig b/lib/std/rand.zig
index 9722a47682..4f9cb0db56 100644
--- a/lib/std/rand.zig
+++ b/lib/std/rand.zig
@@ -18,11 +18,12 @@ const maxInt = std.math.maxInt;
pub const DefaultPrng = Xoshiro256;
/// Cryptographically secure random numbers.
-pub const DefaultCsprng = Ascon;
+pub const DefaultCsprng = ChaCha;
pub const Ascon = @import("rand/Ascon.zig");
+pub const ChaCha = @import("rand/ChaCha.zig");
+
pub const Isaac64 = @import("rand/Isaac64.zig");
-pub const Xoodoo = @import("rand/Xoodoo.zig");
pub const Pcg = @import("rand/Pcg.zig");
pub const Xoroshiro128 = @import("rand/Xoroshiro128.zig");
pub const Xoshiro256 = @import("rand/Xoshiro256.zig");
diff --git a/lib/std/rand/Ascon.zig b/lib/std/rand/Ascon.zig
index b6e8ce4899..3600e02905 100644
--- a/lib/std/rand/Ascon.zig
+++ b/lib/std/rand/Ascon.zig
@@ -1,4 +1,12 @@
-//! CSPRNG based on the Ascon XOFa construction
+//! CSPRNG based on the Reverie construction, a permutation-based PRNG
+//! with forward security, instantiated with the Ascon(128,12,8) permutation.
+//!
+//! Compared to ChaCha, this PRNG is has a much smaller state, and can be
+//! a better choice for constrained environments.
+//!
+//! References:
+//! - A Robust and Sponge-Like PRNG with Improved Efficiency https://eprint.iacr.org/2016/886.pdf
+//! - Ascon https://ascon.iaik.tugraz.at/files/asconv12-nist.pdf
const std = @import("std");
const min = std.math.min;
@@ -6,30 +14,38 @@ const mem = std.mem;
const Random = std.rand.Random;
const Self = @This();
-state: std.crypto.core.Ascon(.Little),
+const Ascon = std.crypto.core.Ascon(.Little);
-const rate = 8;
+state: Ascon,
+
+const rate = 16;
pub const secret_seed_length = 32;
/// The seed must be uniform, secret and `secret_seed_length` bytes long.
pub fn init(secret_seed: [secret_seed_length]u8) Self {
- var state = std.crypto.core.Ascon(.Little).initXofA();
- var i: usize = 0;
- while (i + rate <= secret_seed.len) : (i += rate) {
- state.addBytes(secret_seed[i..][0..rate]);
- state.permuteR(8);
- }
- const left = secret_seed.len - i;
- if (left > 0) state.addBytes(secret_seed[i..]);
- state.addByte(0x80, left);
- state.permute();
- return Self{ .state = state };
+ var self = Self{ .state = Ascon.initXof() };
+ self.addEntropy(&secret_seed);
+ return self;
}
+/// Inserts entropy to refresh the internal state.
+pub fn addEntropy(self: *Self, bytes: []const u8) void {
+ comptime std.debug.assert(secret_seed_length % rate == 0);
+ var i: usize = 0;
+ while (i + rate < bytes.len) : (i += rate) {
+ self.state.addBytes(bytes[i..][0..rate]);
+ self.state.permuteR(8);
+ }
+ if (i != bytes.len) self.state.addBytes(bytes[i..]);
+ self.state.permute();
+}
+
+/// Returns a `std.rand.Random` structure backed by the current RNG.
pub fn random(self: *Self) Random {
return Random.init(self, fill);
}
+/// Fills the buffer with random bytes.
pub fn fill(self: *Self, buf: []u8) void {
var i: usize = 0;
while (true) {
@@ -40,6 +56,5 @@ pub fn fill(self: *Self, buf: []u8) void {
self.state.permuteR(8);
i += n;
}
- self.state.clear(0, rate);
- self.state.permuteR(8);
+ self.state.permuteRatchet(6, rate);
}
diff --git a/lib/std/rand/ChaCha.zig b/lib/std/rand/ChaCha.zig
new file mode 100644
index 0000000000..0992aeb97e
--- /dev/null
+++ b/lib/std/rand/ChaCha.zig
@@ -0,0 +1,97 @@
+//! CSPRNG based on the ChaCha8 stream cipher, with forward security.
+//!
+//! References:
+//! - Fast-key-erasure random-number generators https://blog.cr.yp.to/20170723-random.html
+
+const std = @import("std");
+const mem = std.mem;
+const Random = std.rand.Random;
+const Self = @This();
+
+const Cipher = std.crypto.stream.chacha.ChaCha8IETF;
+
+const State = [2 * Cipher.block_length]u8;
+
+state: State,
+offset: usize,
+
+const nonce = [_]u8{0} ** Cipher.nonce_length;
+
+pub const secret_seed_length = Cipher.key_length;
+
+/// The seed must be uniform, secret and `secret_seed_length` bytes long.
+pub fn init(secret_seed: [secret_seed_length]u8) Self {
+ var self = Self{ .state = undefined, .offset = 0 };
+ Cipher.stream(&self.state, 0, secret_seed, nonce);
+ return self;
+}
+
+/// Inserts entropy to refresh the internal state.
+pub fn addEntropy(self: *Self, bytes: []const u8) void {
+ var i: usize = 0;
+ while (i + Cipher.key_length <= bytes.len) : (i += Cipher.key_length) {
+ Cipher.xor(
+ self.state[0..Cipher.key_length],
+ self.state[0..Cipher.key_length],
+ 0,
+ bytes[i..][0..Cipher.key_length].*,
+ nonce,
+ );
+ }
+ if (i < bytes.len) {
+ var k = [_]u8{0} ** Cipher.key_length;
+ mem.copy(u8, k[0..], bytes[i..]);
+ Cipher.xor(
+ self.state[0..Cipher.key_length],
+ self.state[0..Cipher.key_length],
+ 0,
+ k,
+ nonce,
+ );
+ }
+ self.refill();
+}
+
+/// Returns a `std.rand.Random` structure backed by the current RNG.
+pub fn random(self: *Self) Random {
+ return Random.init(self, fill);
+}
+
+// Refills the buffer with random bytes, overwriting the previous key.
+fn refill(self: *Self) void {
+ Cipher.stream(&self.state, 0, self.state[0..Cipher.key_length].*, nonce);
+ self.offset = 0;
+}
+
+/// Fills the buffer with random bytes.
+pub fn fill(self: *Self, buf_: []u8) void {
+ const bytes = self.state[Cipher.key_length..];
+ var buf = buf_;
+
+ const avail = bytes.len - self.offset;
+ if (avail > 0) {
+ // Bytes from the current block
+ const n = @min(avail, buf.len);
+ mem.copy(u8, buf[0..n], bytes[self.offset..][0..n]);
+ mem.set(u8, bytes[self.offset..][0..n], 0);
+ buf = buf[n..];
+ self.offset += n;
+ }
+ if (buf.len == 0) return;
+
+ self.refill();
+
+ // Full blocks
+ while (buf.len >= bytes.len) {
+ mem.copy(u8, buf[0..bytes.len], bytes);
+ buf = buf[bytes.len..];
+ self.refill();
+ }
+
+ // Remaining bytes
+ if (buf.len > 0) {
+ mem.copy(u8, buf, bytes[0..buf.len]);
+ mem.set(u8, bytes[0..buf.len], 0);
+ self.offset = buf.len;
+ }
+}
diff --git a/lib/std/rand/Gimli.zig b/lib/std/rand/Gimli.zig
deleted file mode 100644
index 7b7720503e..0000000000
--- a/lib/std/rand/Gimli.zig
+++ /dev/null
@@ -1,34 +0,0 @@
-//! CSPRNG
-
-const std = @import("std");
-const Random = std.rand.Random;
-const mem = std.mem;
-const Gimli = @This();
-
-state: std.crypto.core.Gimli,
-
-pub const secret_seed_length = 32;
-
-/// The seed must be uniform, secret and `secret_seed_length` bytes long.
-pub fn init(secret_seed: [secret_seed_length]u8) Gimli {
- var initial_state: [std.crypto.core.Gimli.BLOCKBYTES]u8 = undefined;
- mem.copy(u8, initial_state[0..secret_seed_length], &secret_seed);
- mem.set(u8, initial_state[secret_seed_length..], 0);
- var self = Gimli{
- .state = std.crypto.core.Gimli.init(initial_state),
- };
- return self;
-}
-
-pub fn random(self: *Gimli) Random {
- return Random.init(self, fill);
-}
-
-pub fn fill(self: *Gimli, buf: []u8) void {
- if (buf.len != 0) {
- self.state.squeeze(buf);
- } else {
- self.state.permute();
- }
- mem.set(u8, self.state.toSlice()[0..std.crypto.core.Gimli.RATE], 0);
-}
diff --git a/lib/std/rand/Xoodoo.zig b/lib/std/rand/Xoodoo.zig
deleted file mode 100644
index 3e16f2a864..0000000000
--- a/lib/std/rand/Xoodoo.zig
+++ /dev/null
@@ -1,42 +0,0 @@
-//! CSPRNG
-
-const std = @import("std");
-const Random = std.rand.Random;
-const min = std.math.min;
-const mem = std.mem;
-const Xoodoo = @This();
-
-const State = std.crypto.core.Xoodoo;
-
-state: State,
-
-const rate = 16;
-pub const secret_seed_length = 32;
-
-/// The seed must be uniform, secret and `secret_seed_length` bytes long.
-pub fn init(secret_seed: [secret_seed_length]u8) Xoodoo {
- var initial_state: [State.block_bytes]u8 = undefined;
- mem.copy(u8, initial_state[0..secret_seed_length], &secret_seed);
- mem.set(u8, initial_state[secret_seed_length..], 0);
- var state = State.init(initial_state);
- state.permute();
- return Xoodoo{ .state = state };
-}
-
-pub fn random(self: *Xoodoo) Random {
- return Random.init(self, fill);
-}
-
-pub fn fill(self: *Xoodoo, buf: []u8) void {
- var i: usize = 0;
- while (true) {
- const left = buf.len - i;
- const n = min(left, rate);
- self.state.extract(buf[i..][0..n]);
- if (left == 0) break;
- self.state.permute();
- i += n;
- }
- self.state.clear(0, rate);
- self.state.permute();
-}
diff --git a/lib/std/rand/benchmark.zig b/lib/std/rand/benchmark.zig
new file mode 100644
index 0000000000..668b664c27
--- /dev/null
+++ b/lib/std/rand/benchmark.zig
@@ -0,0 +1,217 @@
+// zig run -O ReleaseFast --zig-lib-dir ../.. benchmark.zig
+
+const std = @import("std");
+const builtin = @import("builtin");
+const time = std.time;
+const Timer = time.Timer;
+const rand = std.rand;
+
+const KiB = 1024;
+const MiB = 1024 * KiB;
+const GiB = 1024 * MiB;
+
+const Rng = struct {
+ ty: type,
+ name: []const u8,
+ init_u8s: ?[]const u8 = null,
+ init_u64: ?u64 = null,
+};
+
+const prngs = [_]Rng{
+ Rng{
+ .ty = rand.Isaac64,
+ .name = "isaac64",
+ .init_u64 = 0,
+ },
+ Rng{
+ .ty = rand.Pcg,
+ .name = "pcg",
+ .init_u64 = 0,
+ },
+ Rng{
+ .ty = rand.RomuTrio,
+ .name = "romutrio",
+ .init_u64 = 0,
+ },
+ Rng{
+ .ty = std.rand.Sfc64,
+ .name = "sfc64",
+ .init_u64 = 0,
+ },
+ Rng{
+ .ty = std.rand.Xoroshiro128,
+ .name = "xoroshiro128",
+ .init_u64 = 0,
+ },
+ Rng{
+ .ty = std.rand.Xoshiro256,
+ .name = "xoshiro256",
+ .init_u64 = 0,
+ },
+};
+
+const csprngs = [_]Rng{
+ Rng{
+ .ty = rand.Ascon,
+ .name = "ascon",
+ .init_u8s = &[_]u8{0} ** 32,
+ },
+ Rng{
+ .ty = rand.ChaCha,
+ .name = "chacha",
+ .init_u8s = &[_]u8{0} ** 32,
+ },
+};
+
+const Result = struct {
+ throughput: u64,
+};
+
+const long_block_size: usize = 8 * 8192;
+const short_block_size: usize = 8;
+
+pub fn benchmark(comptime H: anytype, bytes: usize, comptime block_size: usize) !Result {
+ var rng = blk: {
+ if (H.init_u8s) |init| {
+ break :blk H.ty.init(init[0..].*);
+ }
+ if (H.init_u64) |init| {
+ break :blk H.ty.init(init);
+ }
+ break :blk H.ty.init();
+ };
+
+ var block: [block_size]u8 = undefined;
+
+ var offset: usize = 0;
+ var timer = try Timer.start();
+ const start = timer.lap();
+ while (offset < bytes) : (offset += block.len) {
+ rng.fill(block[0..]);
+ }
+ const end = timer.read();
+
+ const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
+ const throughput = @floatToInt(u64, @intToFloat(f64, bytes) / elapsed_s);
+
+ std.debug.assert(rng.random().int(u64) != 0);
+
+ return Result{
+ .throughput = throughput,
+ };
+}
+
+fn usage() void {
+ std.debug.print(
+ \\throughput_test [options]
+ \\
+ \\Options:
+ \\ --filter [test-name]
+ \\ --count [int]
+ \\ --prngs-only
+ \\ --csprngs-only
+ \\ --short-only
+ \\ --long-only
+ \\ --help
+ \\
+ , .{});
+}
+
+fn mode(comptime x: comptime_int) comptime_int {
+ return if (builtin.mode == .Debug) x / 64 else x;
+}
+
+pub fn main() !void {
+ const stdout = std.io.getStdOut().writer();
+
+ var buffer: [1024]u8 = undefined;
+ var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]);
+ const args = try std.process.argsAlloc(fixed.allocator());
+
+ var filter: ?[]u8 = "";
+ var count: usize = mode(128 * MiB);
+ var bench_prngs = true;
+ var bench_csprngs = true;
+ var bench_long = true;
+ var bench_short = true;
+
+ var i: usize = 1;
+ while (i < args.len) : (i += 1) {
+ if (std.mem.eql(u8, args[i], "--mode")) {
+ try stdout.print("{}\n", .{builtin.mode});
+ return;
+ } else if (std.mem.eql(u8, args[i], "--filter")) {
+ i += 1;
+ if (i == args.len) {
+ usage();
+ std.os.exit(1);
+ }
+
+ filter = args[i];
+ } else if (std.mem.eql(u8, args[i], "--count")) {
+ i += 1;
+ if (i == args.len) {
+ usage();
+ std.os.exit(1);
+ }
+
+ const c = try std.fmt.parseUnsigned(usize, args[i], 10);
+ count = c * MiB;
+ } else if (std.mem.eql(u8, args[i], "--csprngs-only")) {
+ bench_prngs = false;
+ } else if (std.mem.eql(u8, args[i], "--prngs-only")) {
+ bench_csprngs = false;
+ } else if (std.mem.eql(u8, args[i], "--short-only")) {
+ bench_long = false;
+ } else if (std.mem.eql(u8, args[i], "--long-only")) {
+ bench_short = false;
+ } else if (std.mem.eql(u8, args[i], "--help")) {
+ usage();
+ return;
+ } else {
+ usage();
+ std.os.exit(1);
+ }
+ }
+
+ if (bench_prngs) {
+ if (bench_long) {
+ inline for (prngs) |R| {
+ if (filter == null or std.mem.indexOf(u8, R.name, filter.?) != null) {
+ try stdout.print("{s} (long outputs)\n", .{R.name});
+ const result_long = try benchmark(R, count, long_block_size);
+ try stdout.print(" {:5} MiB/s\n", .{result_long.throughput / (1 * MiB)});
+ }
+ }
+ }
+ if (bench_short) {
+ inline for (prngs) |R| {
+ if (filter == null or std.mem.indexOf(u8, R.name, filter.?) != null) {
+ try stdout.print("{s} (short outputs)\n", .{R.name});
+ const result_short = try benchmark(R, count, short_block_size);
+ try stdout.print(" {:5} MiB/s\n", .{result_short.throughput / (1 * MiB)});
+ }
+ }
+ }
+ }
+ if (bench_csprngs) {
+ if (bench_long) {
+ inline for (csprngs) |R| {
+ if (filter == null or std.mem.indexOf(u8, R.name, filter.?) != null) {
+ try stdout.print("{s} (cryptographic, long outputs)\n", .{R.name});
+ const result_long = try benchmark(R, count, long_block_size);
+ try stdout.print(" {:5} MiB/s\n", .{result_long.throughput / (1 * MiB)});
+ }
+ }
+ }
+ if (bench_short) {
+ inline for (csprngs) |R| {
+ if (filter == null or std.mem.indexOf(u8, R.name, filter.?) != null) {
+ try stdout.print("{s} (cryptographic, short outputs)\n", .{R.name});
+ const result_short = try benchmark(R, count, short_block_size);
+ try stdout.print(" {:5} MiB/s\n", .{result_short.throughput / (1 * MiB)});
+ }
+ }
+ }
+ }
+}
From 29e6aedc95766f960d7dbc92c862a82bf40faafd Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Fri, 17 Mar 2023 20:07:08 -0400
Subject: [PATCH 047/216] x86_64: implement min and max as commutative binary
ops
---
src/arch/x86_64/CodeGen.zig | 194 +++++++++++++++++++-----------------
src/arch/x86_64/Emit.zig | 28 +++++-
src/arch/x86_64/Mir.zig | 24 +++--
src/arch/x86_64/bits.zig | 7 +-
4 files changed, 146 insertions(+), 107 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 5dfce901f7..4e4fe8823f 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -402,8 +402,8 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
_ = try self.addInst(.{
.tag = .setcc,
- .ops = .r_c,
- .data = .{ .r_c = .{
+ .ops = .r_cc,
+ .data = .{ .r_cc = .{
.r1 = reg,
.cc = cc,
} },
@@ -413,8 +413,8 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
_ = try self.addInst(.{
.tag = .cmovcc,
- .ops = .rr_c,
- .data = .{ .rr_c = .{
+ .ops = .rr_cc,
+ .data = .{ .rr_cc = .{
.r1 = reg1,
.r2 = reg2,
.cc = cc,
@@ -422,6 +422,26 @@ fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bi
});
}
+fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condition) !void {
+ _ = try self.addInst(.{
+ .tag = .cmovcc,
+ .ops = switch (m) {
+ .sib => .rm_sib_cc,
+ .rip => .rm_rip_cc,
+ else => unreachable,
+ },
+ .data = .{ .rx_cc = .{
+ .r1 = reg,
+ .cc = cc,
+ .payload = switch (m) {
+ .sib => try self.addExtra(Mir.MemorySib.encode(m)),
+ .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+ else => unreachable,
+ },
+ } },
+ });
+}
+
fn asmJmpReloc(self: *Self, target: Mir.Inst.Index) !Mir.Inst.Index {
return self.addInst(.{
.tag = .jmp_reloc,
@@ -793,18 +813,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
switch (air_tags[inst]) {
// zig fmt: off
- .add => try self.airBinOp(inst, .add),
- .addwrap => try self.airBinOp(inst, .addwrap),
- .sub => try self.airBinOp(inst, .sub),
- .subwrap => try self.airBinOp(inst, .subwrap),
- .bool_and => try self.airBinOp(inst, .bool_and),
- .bool_or => try self.airBinOp(inst, .bool_or),
- .bit_and => try self.airBinOp(inst, .bit_and),
- .bit_or => try self.airBinOp(inst, .bit_or),
- .xor => try self.airBinOp(inst, .xor),
+ .add,
+ .addwrap,
+ .sub,
+ .subwrap,
+ .bool_and,
+ .bool_or,
+ .bit_and,
+ .bit_or,
+ .xor,
+ .min,
+ .max,
+ => |tag| try self.airBinOp(inst, tag),
- .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
- .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
+ .ptr_add, .ptr_sub => |tag| try self.airPtrArithmetic(inst, tag),
.shr, .shr_exact => try self.airShlShrBinOp(inst),
.shl, .shl_exact => try self.airShlShrBinOp(inst),
@@ -818,8 +840,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.sub_sat => try self.airSubSat(inst),
.mul_sat => try self.airMulSat(inst),
.shl_sat => try self.airShlSat(inst),
- .min => try self.airMin(inst),
- .max => try self.airMax(inst),
.slice => try self.airSlice(inst),
.sqrt,
@@ -1466,61 +1486,6 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
-fn airMin(self: *Self, inst: Air.Inst.Index) !void {
- const bin_op = self.air.instructions.items(.data)[inst].bin_op;
- if (self.liveness.isUnused(inst)) {
- return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
- }
-
- const ty = self.air.typeOfIndex(inst);
- if (ty.zigTypeTag() != .Int) {
- return self.fail("TODO implement min for type {}", .{ty.fmtDebug()});
- }
- const signedness = ty.intInfo(self.target.*).signedness;
- const result: MCValue = result: {
- // TODO improve by checking if any operand can be reused.
- // TODO audit register allocation
- const lhs = try self.resolveInst(bin_op.lhs);
- const lhs_lock: ?RegisterLock = switch (lhs) {
- .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
- else => null,
- };
- defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
-
- const lhs_reg = try self.copyToTmpRegister(ty, lhs);
- const lhs_reg_lock = self.register_manager.lockRegAssumeUnused(lhs_reg);
- defer self.register_manager.unlockReg(lhs_reg_lock);
-
- const rhs_mcv = try self.limitImmediateType(bin_op.rhs, i32);
- const rhs_lock: ?RegisterLock = switch (rhs_mcv) {
- .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
- else => null,
- };
- defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
-
- try self.genBinOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv);
-
- const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv);
- const cc: Condition = switch (signedness) {
- .unsigned => .b,
- .signed => .l,
- };
- try self.asmCmovccRegisterRegister(dst_mcv.register, lhs_reg, cc);
-
- break :result dst_mcv;
- };
- return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
-}
-
-fn airMax(self: *Self, inst: Air.Inst.Index) !void {
- const bin_op = self.air.instructions.items(.data)[inst].bin_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement max for {}", .{self.target.cpu.arch});
- return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
-}
-
fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
@@ -1545,11 +1510,10 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
- if (self.liveness.isUnused(inst)) {
- return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
- }
-
- const result = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
+ const result = if (self.liveness.isUnused(inst))
+ .dead
+ else
+ try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
@@ -1557,11 +1521,10 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
- if (self.liveness.isUnused(inst)) {
- return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
- }
-
- const result = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
+ const result = if (self.liveness.isUnused(inst))
+ .dead
+ else
+ try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
@@ -3486,10 +3449,10 @@ fn genBinOp(
const lhs_ty = self.air.typeOf(lhs_air);
const rhs_ty = self.air.typeOf(rhs_air);
if (lhs_ty.zigTypeTag() == .Vector) {
- return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});
+ return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});
}
if (lhs_ty.abiSize(self.target.*) > 8) {
- return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});
+ return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});
}
const is_commutative: bool = switch (tag) {
@@ -3500,6 +3463,8 @@ fn genBinOp(
.bool_and,
.bit_and,
.xor,
+ .min,
+ .max,
=> true,
else => false,
@@ -3520,10 +3485,10 @@ fn genBinOp(
var flipped: bool = false;
const dst_mcv: MCValue = blk: {
if (maybe_inst) |inst| {
- if (self.reuseOperand(inst, lhs_air, 0, lhs) and lhs.isRegister()) {
+ if (lhs.isRegister() and self.reuseOperand(inst, lhs_air, 0, lhs)) {
break :blk lhs;
}
- if (is_commutative and self.reuseOperand(inst, rhs_air, 1, rhs) and rhs.isRegister()) {
+ if (rhs.isRegister() and is_commutative and self.reuseOperand(inst, rhs_air, 1, rhs)) {
flipped = true;
break :blk rhs;
}
@@ -3580,6 +3545,58 @@ fn genBinOp(
.xor => try self.genBinOpMir(.xor, lhs_ty, dst_mcv, src_mcv),
+ .min,
+ .max,
+ => {
+ if (!lhs_ty.isAbiInt() or !rhs_ty.isAbiInt()) {
+ return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) });
+ }
+
+ const mat_src_mcv = switch (src_mcv) {
+ .immediate => MCValue{ .register = try self.copyToTmpRegister(rhs_ty, src_mcv) },
+ else => src_mcv,
+ };
+ const mat_mcv_lock = switch (mat_src_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ else => null,
+ };
+ defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock);
+
+ try self.genBinOpMir(.cmp, lhs_ty, dst_mcv, mat_src_mcv);
+
+ const int_info = lhs_ty.intInfo(self.target.*);
+ const cc: Condition = switch (int_info.signedness) {
+ .unsigned => switch (tag) {
+ .min => .a,
+ .max => .b,
+ else => unreachable,
+ },
+ .signed => switch (tag) {
+ .min => .g,
+ .max => .l,
+ else => unreachable,
+ },
+ };
+
+ const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
+ switch (dst_mcv) {
+ .register => |dst_reg| switch (mat_src_mcv) {
+ .register => |src_reg| try self.asmCmovccRegisterRegister(
+ registerAlias(dst_reg, abi_size),
+ registerAlias(src_reg, abi_size),
+ cc,
+ ),
+ .stack_offset => |off| try self.asmCmovccRegisterMemory(
+ registerAlias(dst_reg, abi_size),
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
+ cc,
+ ),
+ else => unreachable,
+ },
+ else => unreachable,
+ }
+ },
+
else => unreachable,
}
return dst_mcv;
@@ -3660,13 +3677,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
Immediate.s(small),
);
} else {
- const tmp_reg = try self.register_manager.allocReg(null, gp);
- const tmp_alias = registerAlias(tmp_reg, abi_size);
- try self.asmRegisterImmediate(.mov, tmp_alias, Immediate.u(imm));
try self.asmRegisterRegister(
mir_tag,
registerAlias(dst_reg, abi_size),
- tmp_alias,
+ registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),
);
}
},
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index 32699d35cb..4e2c1db9af 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -374,23 +374,41 @@ fn mnemonicFromConditionCode(comptime basename: []const u8, cc: bits.Condition)
fn mirCmovcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
const ops = emit.mir.instructions.items(.ops)[inst];
switch (ops) {
- .rr_c => {
- const data = emit.mir.instructions.items(.data)[inst].rr_c;
+ .rr_cc => {
+ const data = emit.mir.instructions.items(.data)[inst].rr_cc;
const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
return emit.encode(mnemonic, .{
.op1 = .{ .reg = data.r1 },
.op2 = .{ .reg = data.r2 },
});
},
- else => unreachable, // TODO
+ .rm_sib_cc => {
+ const data = emit.mir.instructions.items(.data)[inst].rx_cc;
+ const extra = emit.mir.extraData(Mir.MemorySib, data.payload).data;
+ const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
+ return emit.encode(mnemonic, .{
+ .op1 = .{ .reg = data.r1 },
+ .op2 = .{ .mem = Mir.MemorySib.decode(extra) },
+ });
+ },
+ .rm_rip_cc => {
+ const data = emit.mir.instructions.items(.data)[inst].rx_cc;
+ const extra = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
+ const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
+ return emit.encode(mnemonic, .{
+ .op1 = .{ .reg = data.r1 },
+ .op2 = .{ .mem = Mir.MemoryRip.decode(extra) },
+ });
+ },
+ else => unreachable,
}
}
fn mirSetcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
const ops = emit.mir.instructions.items(.ops)[inst];
switch (ops) {
- .r_c => {
- const data = emit.mir.instructions.items(.data)[inst].r_c;
+ .r_cc => {
+ const data = emit.mir.instructions.items(.data)[inst].r_cc;
const mnemonic = mnemonicFromConditionCode("set", data.cc);
return emit.encode(mnemonic, .{
.op1 = .{ .reg = data.r1 },
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index 3951108e3a..ed0606e87a 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -186,10 +186,10 @@ pub const Inst = struct {
rri_u,
/// Register with condition code (CC).
/// Uses `r_c` payload.
- r_c,
+ r_cc,
/// Register, register with condition code (CC).
/// Uses `rr_c` payload.
- rr_c,
+ rr_cc,
/// Register, immediate (sign-extended) operands.
/// Uses `ri` payload.
ri_s,
@@ -214,6 +214,12 @@ pub const Inst = struct {
/// Register, memory (RIP) operands.
/// Uses `rx` payload.
rm_rip,
+ /// Register, memory (SIB) operands with condition code (CC).
+ /// Uses `rx_cc` payload.
+ rm_sib_cc,
+ /// Register, memory (RIP) operands with condition code (CC).
+ /// Uses `rx_cc` payload.
+ rm_rip_cc,
/// Single memory (SIB) operand.
/// Uses `payload` with extra data of type `MemorySib`.
m_sib,
@@ -250,10 +256,6 @@ pub const Inst = struct {
/// References another Mir instruction directly with condition code (CC).
/// Uses `inst_cc` payload.
inst_cc,
- /// Uses `payload` payload with data of type `MemoryConditionCode`.
- m_cc,
- /// Uses `rx` payload with extra data of type `MemoryConditionCode`.
- rm_cc,
/// Uses `reloc` payload.
reloc,
/// Linker relocation - GOT indirection.
@@ -296,12 +298,12 @@ pub const Inst = struct {
imm: u32,
},
/// Register with condition code (CC).
- r_c: struct {
+ r_cc: struct {
r1: Register,
cc: bits.Condition,
},
/// Register, register with condition code (CC).
- rr_c: struct {
+ rr_cc: struct {
r1: Register,
r2: Register,
cc: bits.Condition,
@@ -316,6 +318,12 @@ pub const Inst = struct {
r1: Register,
payload: u32,
},
+ /// Register with condition code (CC), followed by custom payload found in extra.
+ rx_cc: struct {
+ r1: Register,
+ cc: bits.Condition,
+ payload: u32,
+ },
/// Custom payload followed by an immediate.
xi: struct {
payload: u32,
diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig
index 043e589af4..72d7b159cf 100644
--- a/src/arch/x86_64/bits.zig
+++ b/src/arch/x86_64/bits.zig
@@ -97,8 +97,7 @@ pub const Condition = enum(u5) {
};
}
- /// Returns the condition which is true iff the given condition is
- /// false (if such a condition exists)
+ /// Returns the condition which is true iff the given condition is false
pub fn negate(cond: Condition) Condition {
return switch (cond) {
.a => .na,
@@ -127,8 +126,8 @@ pub const Condition = enum(u5) {
.nz => .z,
.o => .no,
.p => .np,
- .pe => unreachable,
- .po => unreachable,
+ .pe => .po,
+ .po => .pe,
.s => .ns,
.z => .nz,
};
From 30e1daa7463c766e23f57e6a89e4e0ffd4918be5 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Fri, 17 Mar 2023 22:07:32 -0400
Subject: [PATCH 048/216] x86_64: implement basic float ops
---
src/arch/x86_64/CodeGen.zig | 174 ++++++++++++++++--------------
src/arch/x86_64/Emit.zig | 10 ++
src/arch/x86_64/Encoding.zig | 8 ++
src/arch/x86_64/Mir.zig | 24 ++++-
src/arch/x86_64/encodings.zig | 20 ++++
test/behavior/maximum_minimum.zig | 2 -
6 files changed, 155 insertions(+), 83 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 4e4fe8823f..d18f99923e 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -1530,21 +1530,23 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void
fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const result = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
- if (self.liveness.isUnused(inst)) {
- return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
- }
+ const tag = self.air.instructions.items(.tag)[inst];
+ const ty = self.air.typeOfIndex(inst);
- const tag = self.air.instructions.items(.tag)[inst];
- const ty = self.air.typeOfIndex(inst);
+ if (ty.zigTypeTag() == .Float) {
+ break :result try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
+ }
- try self.spillRegisters(2, .{ .rax, .rdx });
+ try self.spillRegisters(2, .{ .rax, .rdx });
- const lhs = try self.resolveInst(bin_op.lhs);
- const rhs = try self.resolveInst(bin_op.rhs);
-
- const result = try self.genMulDivBinOp(tag, inst, ty, lhs, rhs);
+ const lhs = try self.resolveInst(bin_op.lhs);
+ const rhs = try self.resolveInst(bin_op.rhs);
+ break :result try self.genMulDivBinOp(tag, inst, ty, lhs, rhs);
+ };
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
@@ -3288,10 +3290,10 @@ fn genMulDivBinOp(
rhs: MCValue,
) !MCValue {
if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) {
- return self.fail("TODO implement genBinOp for {}", .{ty.fmtDebug()});
+ return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
}
if (ty.abiSize(self.target.*) > 8) {
- return self.fail("TODO implement genBinOp for {}", .{ty.fmtDebug()});
+ return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
}
if (tag == .div_float) {
return self.fail("TODO implement genMulDivBinOp for div_float", .{});
@@ -3516,11 +3518,31 @@ fn genBinOp(
switch (tag) {
.add,
.addwrap,
- => try self.genBinOpMir(.add, lhs_ty, dst_mcv, src_mcv),
+ => try self.genBinOpMir(switch (lhs_ty.tag()) {
+ else => .add,
+ .f32 => .addss,
+ .f64 => .addsd,
+ }, lhs_ty, dst_mcv, src_mcv),
.sub,
.subwrap,
- => try self.genBinOpMir(.sub, lhs_ty, dst_mcv, src_mcv),
+ => try self.genBinOpMir(switch (lhs_ty.tag()) {
+ else => .sub,
+ .f32 => .subss,
+ .f64 => .subsd,
+ }, lhs_ty, dst_mcv, src_mcv),
+
+ .mul => try self.genBinOpMir(switch (lhs_ty.tag()) {
+ .f32 => .mulss,
+ .f64 => .mulsd,
+ else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
+ }, lhs_ty, dst_mcv, src_mcv),
+
+ .div_float => try self.genBinOpMir(switch (lhs_ty.tag()) {
+ .f32 => .divss,
+ .f64 => .divsd,
+ else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
+ }, lhs_ty, dst_mcv, src_mcv),
.ptr_add,
.ptr_sub,
@@ -3547,54 +3569,66 @@ fn genBinOp(
.min,
.max,
- => {
- if (!lhs_ty.isAbiInt() or !rhs_ty.isAbiInt()) {
- return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) });
- }
+ => switch (lhs_ty.zigTypeTag()) {
+ .Int => {
+ const mat_src_mcv = switch (src_mcv) {
+ .immediate => MCValue{ .register = try self.copyToTmpRegister(rhs_ty, src_mcv) },
+ else => src_mcv,
+ };
+ const mat_mcv_lock = switch (mat_src_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ else => null,
+ };
+ defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock);
- const mat_src_mcv = switch (src_mcv) {
- .immediate => MCValue{ .register = try self.copyToTmpRegister(rhs_ty, src_mcv) },
- else => src_mcv,
- };
- const mat_mcv_lock = switch (mat_src_mcv) {
- .register => |reg| self.register_manager.lockReg(reg),
- else => null,
- };
- defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock);
+ try self.genBinOpMir(.cmp, lhs_ty, dst_mcv, mat_src_mcv);
- try self.genBinOpMir(.cmp, lhs_ty, dst_mcv, mat_src_mcv);
+ const int_info = lhs_ty.intInfo(self.target.*);
+ const cc: Condition = switch (int_info.signedness) {
+ .unsigned => switch (tag) {
+ .min => .a,
+ .max => .b,
+ else => unreachable,
+ },
+ .signed => switch (tag) {
+ .min => .g,
+ .max => .l,
+ else => unreachable,
+ },
+ };
- const int_info = lhs_ty.intInfo(self.target.*);
- const cc: Condition = switch (int_info.signedness) {
- .unsigned => switch (tag) {
- .min => .a,
- .max => .b,
+ const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
+ switch (dst_mcv) {
+ .register => |dst_reg| switch (mat_src_mcv) {
+ .register => |src_reg| try self.asmCmovccRegisterRegister(
+ registerAlias(dst_reg, abi_size),
+ registerAlias(src_reg, abi_size),
+ cc,
+ ),
+ .stack_offset => |off| try self.asmCmovccRegisterMemory(
+ registerAlias(dst_reg, abi_size),
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
+ cc,
+ ),
+ else => unreachable,
+ },
+ else => unreachable,
+ }
+ },
+ .Float => try self.genBinOpMir(switch (lhs_ty.tag()) {
+ .f32 => switch (tag) {
+ .min => .minss,
+ .max => .maxss,
else => unreachable,
},
- .signed => switch (tag) {
- .min => .g,
- .max => .l,
+ .f64 => switch (tag) {
+ .min => .minsd,
+ .max => .maxsd,
else => unreachable,
},
- };
-
- const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
- switch (dst_mcv) {
- .register => |dst_reg| switch (mat_src_mcv) {
- .register => |src_reg| try self.asmCmovccRegisterRegister(
- registerAlias(dst_reg, abi_size),
- registerAlias(src_reg, abi_size),
- cc,
- ),
- .stack_offset => |off| try self.asmCmovccRegisterMemory(
- registerAlias(dst_reg, abi_size),
- Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
- cc,
- ),
- else => unreachable,
- },
- else => unreachable,
- }
+ else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
+ }, lhs_ty, dst_mcv, src_mcv),
+ else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
},
else => unreachable,
@@ -3626,29 +3660,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
.register => |src_reg| switch (dst_ty.zigTypeTag()) {
.Float => {
if (intrinsicsAllowed(self.target.*, dst_ty)) {
- const actual_tag: Mir.Inst.Tag = switch (dst_ty.tag()) {
- .f32 => switch (mir_tag) {
- .add => .addss,
- .cmp => .ucomiss,
- else => return self.fail(
- "TODO genBinOpMir for f32 register-register with MIR tag {}",
- .{mir_tag},
- ),
- },
- .f64 => switch (mir_tag) {
- .add => .addsd,
- .cmp => .ucomisd,
- else => return self.fail(
- "TODO genBinOpMir for f64 register-register with MIR tag {}",
- .{mir_tag},
- ),
- },
- else => return self.fail(
- "TODO genBinOpMir for float register-register and type {}",
- .{dst_ty.fmtDebug()},
- ),
- };
- return self.asmRegisterRegister(actual_tag, dst_reg.to128(), src_reg.to128());
+ return self.asmRegisterRegister(mir_tag, dst_reg.to128(), src_reg.to128());
}
return self.fail("TODO genBinOpMir for float register-register and no intrinsics", .{});
@@ -4307,7 +4319,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
};
defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
- try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv);
+ try self.genBinOpMir(switch (ty.tag()) {
+ else => .cmp,
+ .f32 => .ucomiss,
+ .f64 => .ucomisd,
+ }, ty, dst_mcv, src_mcv);
break :result switch (signedness) {
.signed => MCValue{ .eflags = Condition.fromCompareOperatorSigned(op) },
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index 4e2c1db9af..e9d09a4ef6 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -110,11 +110,21 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.addss,
.cmpss,
+ .divss,
+ .maxss,
+ .minss,
.movss,
+ .mulss,
+ .subss,
.ucomiss,
.addsd,
.cmpsd,
+ .divsd,
+ .maxsd,
+ .minsd,
.movsd,
+ .mulsd,
+ .subsd,
.ucomisd,
=> try emit.mirEncodeGeneric(tag, inst),
diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig
index a51f954aed..d0ede962cb 100644
--- a/src/arch/x86_64/Encoding.zig
+++ b/src/arch/x86_64/Encoding.zig
@@ -342,12 +342,20 @@ pub const Mnemonic = enum {
// SSE
addss,
cmpss,
+ divss,
+ maxss, minss,
movss,
+ mulss,
+ subss,
ucomiss,
// SSE2
addsd,
cmpsd,
+ divsd,
+ maxsd, minsd,
movq, movsd,
+ mulsd,
+ subsd,
ucomisd,
// zig fmt: on
};
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index ed0606e87a..6f3bf6c745 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -109,20 +109,40 @@ pub const Inst = struct {
/// Logical exclusive-or
xor,
- /// Add single precision floating point
+ /// Add single precision floating point values
addss,
/// Compare scalar single-precision floating-point values
cmpss,
+ /// Divide scalar single-precision floating-point values
+ divss,
+ /// Return maximum single-precision floating-point value
+ maxss,
+ /// Return minimum single-precision floating-point value
+ minss,
/// Move scalar single-precision floating-point value
movss,
+ /// Multiply scalar single-precision floating-point values
+ mulss,
+ /// Subtract scalar single-precision floating-point values
+ subss,
/// Unordered compare scalar single-precision floating-point values
ucomiss,
- /// Add double precision floating point
+ /// Add double precision floating point values
addsd,
/// Compare scalar double-precision floating-point values
cmpsd,
+ /// Divide scalar double-precision floating-point values
+ divsd,
+ /// Return maximum double-precision floating-point value
+ maxsd,
+ /// Return minimum double-precision floating-point value
+ minsd,
/// Move scalar double-precision floating-point value
movsd,
+ /// Multiply scalar double-precision floating-point values
+ mulsd,
+ /// Subtract scalar double-precision floating-point values
+ subsd,
/// Unordered compare scalar double-precision floating-point values
ucomisd,
diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig
index b008eb9f3e..dc7b51521d 100644
--- a/src/arch/x86_64/encodings.zig
+++ b/src/arch/x86_64/encodings.zig
@@ -599,9 +599,19 @@ pub const table = &[_]Entry{
.{ .cmpss, .rmi, .xmm, .xmm_m32, .imm8, .none, 3, 0xf3, 0x0f, 0xc2, 0, .sse },
+ .{ .divss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5e, 0, .sse },
+
+ .{ .maxss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5f, 0, .sse },
+
+ .{ .minss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5d, 0, .sse },
+
.{ .movss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x10, 0, .sse },
.{ .movss, .mr, .xmm_m32, .xmm, .none, .none, 3, 0xf3, 0x0f, 0x11, 0, .sse },
+ .{ .mulss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x59, 0, .sse },
+
+ .{ .subss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5c, 0, .sse },
+
.{ .ucomiss, .rm, .xmm, .xmm_m32, .none, .none, 2, 0x0f, 0x2e, 0x00, 0, .sse },
// SSE2
@@ -609,9 +619,19 @@ pub const table = &[_]Entry{
.{ .cmpsd, .rmi, .xmm, .xmm_m64, .imm8, .none, 3, 0xf2, 0x0f, 0xc2, 0, .sse2 },
+ .{ .divsd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf2, 0x0f, 0x5e, 0, .sse2 },
+
+ .{ .maxsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x5f, 0, .sse2 },
+
+ .{ .minsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x5d, 0, .sse2 },
+
.{ .movq, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf3, 0x0f, 0x7e, 0, .sse2 },
.{ .movq, .mr, .xmm_m64, .xmm, .none, .none, 3, 0x66, 0x0f, 0xd6, 0, .sse2 },
+ .{ .mulsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x59, 0, .sse2 },
+
+ .{ .subsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x5c, 0, .sse2 },
+
.{ .movsd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf2, 0x0f, 0x10, 0, .sse2 },
.{ .movsd, .mr, .xmm_m64, .xmm, .none, .none, 3, 0xf2, 0x0f, 0x11, 0, .sse2 },
diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig
index 34a7d0976a..d538e2db65 100644
--- a/test/behavior/maximum_minimum.zig
+++ b/test/behavior/maximum_minimum.zig
@@ -5,7 +5,6 @@ const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
test "@max" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -52,7 +51,6 @@ test "@max on vectors" {
}
test "@min" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
From b6eebb709fdb8aff62105f60b275527c306b97b8 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 18 Mar 2023 00:02:07 -0400
Subject: [PATCH 049/216] x86_64: fix OBO
These loops were skipping over the top stack entry, and there's already
a function that does this correctly.
---
src/arch/x86_64/CodeGen.zig | 21 +++------------------
1 file changed, 3 insertions(+), 18 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index d18f99923e..de9031f48c 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -5006,14 +5006,8 @@ fn canonicaliseBranches(self: *Self, parent_branch: *Branch, canon_branch: *Bran
if (target_value == .dead)
continue;
// The instruction is only overridden in the else branch.
- var i: usize = self.branch_stack.items.len - 1;
- while (true) {
- i -= 1; // If this overflows, the question is: why wasn't the instruction marked dead?
- if (self.branch_stack.items[i].inst_table.get(target_key)) |mcv| {
- assert(mcv != .dead);
- break :blk mcv;
- }
- }
+ // If integer overflows occurs, the question is: why wasn't the instruction marked dead?
+ break :blk self.getResolvedInstValue(target_key).?;
};
log.debug("consolidating target_entry {d} {}=>{}", .{ target_key, target_value, canon_mcv });
// TODO make sure the destination stack offset / register does not already have something
@@ -5030,16 +5024,7 @@ fn canonicaliseBranches(self: *Self, parent_branch: *Branch, canon_branch: *Bran
log.debug("canon_value = {}", .{canon_value});
if (canon_value == .dead)
continue;
- const parent_mcv = blk: {
- var i: usize = self.branch_stack.items.len - 1;
- while (true) {
- i -= 1;
- if (self.branch_stack.items[i].inst_table.get(canon_key)) |mcv| {
- assert(mcv != .dead);
- break :blk mcv;
- }
- }
- };
+ const parent_mcv = self.getResolvedInstValue(canon_key).?;
log.debug("consolidating canon_entry {d} {}=>{}", .{ canon_key, parent_mcv, canon_value });
// TODO make sure the destination stack offset / register does not already have something
// going on there.
From c865c8fb2a910e73e38192a8bd484935bae8f6fc Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 18 Mar 2023 01:37:13 -0400
Subject: [PATCH 050/216] x86_64: implement float division intrinsics
---
src/arch/x86_64/CodeGen.zig | 27 +-
src/arch/x86_64/Emit.zig | 2 +
src/arch/x86_64/Encoding.zig | 23 +-
src/arch/x86_64/Mir.zig | 4 +
src/arch/x86_64/encodings.zig | 1134 +++++++++++++++++----------------
5 files changed, 614 insertions(+), 576 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index de9031f48c..04e8a7ebe3 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -3538,12 +3538,37 @@ fn genBinOp(
else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
}, lhs_ty, dst_mcv, src_mcv),
- .div_float => try self.genBinOpMir(switch (lhs_ty.tag()) {
+ .div_float,
+ .div_exact,
+ => try self.genBinOpMir(switch (lhs_ty.tag()) {
.f32 => .divss,
.f64 => .divsd,
else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
}, lhs_ty, dst_mcv, src_mcv),
+ .div_trunc,
+ .div_floor,
+ => {
+ try self.genBinOpMir(switch (lhs_ty.tag()) {
+ .f32 => .divss,
+ .f64 => .divsd,
+ else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
+ }, lhs_ty, dst_mcv, src_mcv);
+ if (Target.x86.featureSetHas(self.target.cpu.features, .sse4_1)) {
+ const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
+ const dst_alias = registerAlias(dst_mcv.register, abi_size);
+ try self.asmRegisterRegisterImmediate(switch (lhs_ty.tag()) {
+ .f32 => .roundss,
+ .f64 => .roundsd,
+ else => unreachable,
+ }, dst_alias, dst_alias, Immediate.u(switch (tag) {
+ .div_trunc => 0b1_0_11,
+ .div_floor => 0b1_0_01,
+ else => unreachable,
+ }));
+ } else return self.fail("TODO implement round without sse4_1", .{});
+ },
+
.ptr_add,
.ptr_sub,
=> {
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index e9d09a4ef6..95c5c41170 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -115,6 +115,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.minss,
.movss,
.mulss,
+ .roundss,
.subss,
.ucomiss,
.addsd,
@@ -124,6 +125,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.minsd,
.movsd,
.mulsd,
+ .roundsd,
.subsd,
.ucomisd,
=> try emit.mirEncodeGeneric(tag, inst),
diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig
index d0ede962cb..275c001bd7 100644
--- a/src/arch/x86_64/Encoding.zig
+++ b/src/arch/x86_64/Encoding.zig
@@ -19,8 +19,8 @@ op1: Op,
op2: Op,
op3: Op,
op4: Op,
-opc_len: u2,
-opc: [3]u8,
+opc_len: u3,
+opc: [7]u8,
modrm_ext: u3,
mode: Mode,
@@ -69,18 +69,19 @@ pub fn findByMnemonic(mnemonic: Mnemonic, args: struct {
var candidates: [10]Encoding = undefined;
var count: usize = 0;
for (table) |entry| {
- const enc = Encoding{
+ var enc = Encoding{
.mnemonic = entry[0],
.op_en = entry[1],
.op1 = entry[2],
.op2 = entry[3],
.op3 = entry[4],
.op4 = entry[5],
- .opc_len = entry[6],
- .opc = .{ entry[7], entry[8], entry[9] },
- .modrm_ext = entry[10],
- .mode = entry[11],
+ .opc_len = @intCast(u3, entry[6].len),
+ .opc = undefined,
+ .modrm_ext = entry[7],
+ .mode = entry[8],
};
+ std.mem.copy(u8, &enc.opc, entry[6]);
if (enc.mnemonic == mnemonic and
input_op1.isSubset(enc.op1, enc.mode) and
input_op2.isSubset(enc.op2, enc.mode) and
@@ -184,7 +185,7 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {
if (match) {
if (prefixes.rex.w) {
switch (enc.mode) {
- .fpu, .sse, .sse2, .none => {},
+ .fpu, .sse, .sse2, .sse4_1, .none => {},
.long, .rex => return enc,
}
} else if (prefixes.rex.present and !prefixes.rex.isSet()) {
@@ -357,6 +358,9 @@ pub const Mnemonic = enum {
mulsd,
subsd,
ucomisd,
+ // SSE4.1
+ roundss,
+ roundsd,
// zig fmt: on
};
@@ -550,7 +554,7 @@ pub const Op = enum {
else => {
if (op.isRegister() and target.isRegister()) {
switch (mode) {
- .sse, .sse2 => return op.isFloatingPointRegister() and target.isFloatingPointRegister(),
+ .sse, .sse2, .sse4_1 => return op.isFloatingPointRegister() and target.isFloatingPointRegister(),
else => switch (target) {
.cl, .al, .ax, .eax, .rax => return op == target,
else => return op.bitSize() == target.bitSize(),
@@ -592,4 +596,5 @@ pub const Mode = enum {
long,
sse,
sse2,
+ sse4_1,
};
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index 6f3bf6c745..ed10bed9b6 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -123,6 +123,8 @@ pub const Inst = struct {
movss,
/// Multiply scalar single-precision floating-point values
mulss,
+ /// Round scalar single-precision floating-point values
+ roundss,
/// Subtract scalar single-precision floating-point values
subss,
/// Unordered compare scalar single-precision floating-point values
@@ -141,6 +143,8 @@ pub const Inst = struct {
movsd,
/// Multiply scalar double-precision floating-point values
mulsd,
+ /// Round scalar double-precision floating-point values
+ roundsd,
/// Subtract scalar double-precision floating-point values
subsd,
/// Unordered compare scalar double-precision floating-point values
diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig
index dc7b51521d..57b330b9ce 100644
--- a/src/arch/x86_64/encodings.zig
+++ b/src/arch/x86_64/encodings.zig
@@ -4,638 +4,640 @@ const OpEn = Encoding.OpEn;
const Op = Encoding.Op;
const Mode = Encoding.Mode;
-const opcode_len = u2;
const modrm_ext = u3;
-const Entry = struct { Mnemonic, OpEn, Op, Op, Op, Op, opcode_len, u8, u8, u8, modrm_ext, Mode };
+const Entry = struct { Mnemonic, OpEn, Op, Op, Op, Op, []const u8, modrm_ext, Mode };
// TODO move this into a .zon file when Zig is capable of importing .zon files
// zig fmt: off
pub const table = &[_]Entry{
// General-purpose
- .{ .adc, .zi, .al, .imm8, .none, .none, 1, 0x14, 0x00, 0x00, 0, .none },
- .{ .adc, .zi, .ax, .imm16, .none, .none, 1, 0x15, 0x00, 0x00, 0, .none },
- .{ .adc, .zi, .eax, .imm32, .none, .none, 1, 0x15, 0x00, 0x00, 0, .none },
- .{ .adc, .zi, .rax, .imm32s, .none, .none, 1, 0x15, 0x00, 0x00, 0, .long },
- .{ .adc, .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 2, .none },
- .{ .adc, .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 2, .rex },
- .{ .adc, .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 2, .none },
- .{ .adc, .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 2, .none },
- .{ .adc, .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 2, .long },
- .{ .adc, .mi, .rm16, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 2, .none },
- .{ .adc, .mi, .rm32, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 2, .none },
- .{ .adc, .mi, .rm64, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 2, .long },
- .{ .adc, .mr, .rm8, .r8, .none, .none, 1, 0x10, 0x00, 0x00, 0, .none },
- .{ .adc, .mr, .rm8, .r8, .none, .none, 1, 0x10, 0x00, 0x00, 0, .rex },
- .{ .adc, .mr, .rm16, .r16, .none, .none, 1, 0x11, 0x00, 0x00, 0, .none },
- .{ .adc, .mr, .rm32, .r32, .none, .none, 1, 0x11, 0x00, 0x00, 0, .none },
- .{ .adc, .mr, .rm64, .r64, .none, .none, 1, 0x11, 0x00, 0x00, 0, .long },
- .{ .adc, .rm, .r8, .rm8, .none, .none, 1, 0x12, 0x00, 0x00, 0, .none },
- .{ .adc, .rm, .r8, .rm8, .none, .none, 1, 0x12, 0x00, 0x00, 0, .rex },
- .{ .adc, .rm, .r16, .rm16, .none, .none, 1, 0x13, 0x00, 0x00, 0, .none },
- .{ .adc, .rm, .r32, .rm32, .none, .none, 1, 0x13, 0x00, 0x00, 0, .none },
- .{ .adc, .rm, .r64, .rm64, .none, .none, 1, 0x13, 0x00, 0x00, 0, .long },
+ .{ .adc, .zi, .al, .imm8, .none, .none, &.{ 0x14 }, 0, .none },
+ .{ .adc, .zi, .ax, .imm16, .none, .none, &.{ 0x15 }, 0, .none },
+ .{ .adc, .zi, .eax, .imm32, .none, .none, &.{ 0x15 }, 0, .none },
+ .{ .adc, .zi, .rax, .imm32s, .none, .none, &.{ 0x15 }, 0, .long },
+ .{ .adc, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 2, .none },
+ .{ .adc, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 2, .rex },
+ .{ .adc, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 2, .none },
+ .{ .adc, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 2, .none },
+ .{ .adc, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 2, .long },
+ .{ .adc, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 2, .none },
+ .{ .adc, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 2, .none },
+ .{ .adc, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 2, .long },
+ .{ .adc, .mr, .rm8, .r8, .none, .none, &.{ 0x10 }, 0, .none },
+ .{ .adc, .mr, .rm8, .r8, .none, .none, &.{ 0x10 }, 0, .rex },
+ .{ .adc, .mr, .rm16, .r16, .none, .none, &.{ 0x11 }, 0, .none },
+ .{ .adc, .mr, .rm32, .r32, .none, .none, &.{ 0x11 }, 0, .none },
+ .{ .adc, .mr, .rm64, .r64, .none, .none, &.{ 0x11 }, 0, .long },
+ .{ .adc, .rm, .r8, .rm8, .none, .none, &.{ 0x12 }, 0, .none },
+ .{ .adc, .rm, .r8, .rm8, .none, .none, &.{ 0x12 }, 0, .rex },
+ .{ .adc, .rm, .r16, .rm16, .none, .none, &.{ 0x13 }, 0, .none },
+ .{ .adc, .rm, .r32, .rm32, .none, .none, &.{ 0x13 }, 0, .none },
+ .{ .adc, .rm, .r64, .rm64, .none, .none, &.{ 0x13 }, 0, .long },
- .{ .add, .zi, .al, .imm8, .none, .none, 1, 0x04, 0x00, 0x00, 0, .none },
- .{ .add, .zi, .ax, .imm16, .none, .none, 1, 0x05, 0x00, 0x00, 0, .none },
- .{ .add, .zi, .eax, .imm32, .none, .none, 1, 0x05, 0x00, 0x00, 0, .none },
- .{ .add, .zi, .rax, .imm32s, .none, .none, 1, 0x05, 0x00, 0x00, 0, .long },
- .{ .add, .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 0, .none },
- .{ .add, .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 0, .rex },
- .{ .add, .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 0, .none },
- .{ .add, .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 0, .none },
- .{ .add, .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 0, .long },
- .{ .add, .mi, .rm16, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 0, .none },
- .{ .add, .mi, .rm32, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 0, .none },
- .{ .add, .mi, .rm64, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 0, .long },
- .{ .add, .mr, .rm8, .r8, .none, .none, 1, 0x00, 0x00, 0x00, 0, .none },
- .{ .add, .mr, .rm8, .r8, .none, .none, 1, 0x00, 0x00, 0x00, 0, .rex },
- .{ .add, .mr, .rm16, .r16, .none, .none, 1, 0x01, 0x00, 0x00, 0, .none },
- .{ .add, .mr, .rm32, .r32, .none, .none, 1, 0x01, 0x00, 0x00, 0, .none },
- .{ .add, .mr, .rm64, .r64, .none, .none, 1, 0x01, 0x00, 0x00, 0, .long },
- .{ .add, .rm, .r8, .rm8, .none, .none, 1, 0x02, 0x00, 0x00, 0, .none },
- .{ .add, .rm, .r8, .rm8, .none, .none, 1, 0x02, 0x00, 0x00, 0, .rex },
- .{ .add, .rm, .r16, .rm16, .none, .none, 1, 0x03, 0x00, 0x00, 0, .none },
- .{ .add, .rm, .r32, .rm32, .none, .none, 1, 0x03, 0x00, 0x00, 0, .none },
- .{ .add, .rm, .r64, .rm64, .none, .none, 1, 0x03, 0x00, 0x00, 0, .long },
+ .{ .add, .zi, .al, .imm8, .none, .none, &.{ 0x04 }, 0, .none },
+ .{ .add, .zi, .ax, .imm16, .none, .none, &.{ 0x05 }, 0, .none },
+ .{ .add, .zi, .eax, .imm32, .none, .none, &.{ 0x05 }, 0, .none },
+ .{ .add, .zi, .rax, .imm32s, .none, .none, &.{ 0x05 }, 0, .long },
+ .{ .add, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 0, .none },
+ .{ .add, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 0, .rex },
+ .{ .add, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 0, .none },
+ .{ .add, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 0, .none },
+ .{ .add, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 0, .long },
+ .{ .add, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 0, .none },
+ .{ .add, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 0, .none },
+ .{ .add, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 0, .long },
+ .{ .add, .mr, .rm8, .r8, .none, .none, &.{ 0x00 }, 0, .none },
+ .{ .add, .mr, .rm8, .r8, .none, .none, &.{ 0x00 }, 0, .rex },
+ .{ .add, .mr, .rm16, .r16, .none, .none, &.{ 0x01 }, 0, .none },
+ .{ .add, .mr, .rm32, .r32, .none, .none, &.{ 0x01 }, 0, .none },
+ .{ .add, .mr, .rm64, .r64, .none, .none, &.{ 0x01 }, 0, .long },
+ .{ .add, .rm, .r8, .rm8, .none, .none, &.{ 0x02 }, 0, .none },
+ .{ .add, .rm, .r8, .rm8, .none, .none, &.{ 0x02 }, 0, .rex },
+ .{ .add, .rm, .r16, .rm16, .none, .none, &.{ 0x03 }, 0, .none },
+ .{ .add, .rm, .r32, .rm32, .none, .none, &.{ 0x03 }, 0, .none },
+ .{ .add, .rm, .r64, .rm64, .none, .none, &.{ 0x03 }, 0, .long },
- .{ .@"and", .zi, .al, .imm8, .none, .none, 1, 0x24, 0x00, 0x00, 0, .none },
- .{ .@"and", .zi, .ax, .imm16, .none, .none, 1, 0x25, 0x00, 0x00, 0, .none },
- .{ .@"and", .zi, .eax, .imm32, .none, .none, 1, 0x25, 0x00, 0x00, 0, .none },
- .{ .@"and", .zi, .rax, .imm32s, .none, .none, 1, 0x25, 0x00, 0x00, 0, .long },
- .{ .@"and", .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 4, .none },
- .{ .@"and", .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 4, .rex },
- .{ .@"and", .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 4, .none },
- .{ .@"and", .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 4, .none },
- .{ .@"and", .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 4, .long },
- .{ .@"and", .mi, .rm16, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 4, .none },
- .{ .@"and", .mi, .rm32, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 4, .none },
- .{ .@"and", .mi, .rm64, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 4, .long },
- .{ .@"and", .mr, .rm8, .r8, .none, .none, 1, 0x20, 0x00, 0x00, 0, .none },
- .{ .@"and", .mr, .rm8, .r8, .none, .none, 1, 0x20, 0x00, 0x00, 0, .rex },
- .{ .@"and", .mr, .rm16, .r16, .none, .none, 1, 0x21, 0x00, 0x00, 0, .none },
- .{ .@"and", .mr, .rm32, .r32, .none, .none, 1, 0x21, 0x00, 0x00, 0, .none },
- .{ .@"and", .mr, .rm64, .r64, .none, .none, 1, 0x21, 0x00, 0x00, 0, .long },
- .{ .@"and", .rm, .r8, .rm8, .none, .none, 1, 0x22, 0x00, 0x00, 0, .none },
- .{ .@"and", .rm, .r8, .rm8, .none, .none, 1, 0x22, 0x00, 0x00, 0, .rex },
- .{ .@"and", .rm, .r16, .rm16, .none, .none, 1, 0x23, 0x00, 0x00, 0, .none },
- .{ .@"and", .rm, .r32, .rm32, .none, .none, 1, 0x23, 0x00, 0x00, 0, .none },
- .{ .@"and", .rm, .r64, .rm64, .none, .none, 1, 0x23, 0x00, 0x00, 0, .long },
+ .{ .@"and", .zi, .al, .imm8, .none, .none, &.{ 0x24 }, 0, .none },
+ .{ .@"and", .zi, .ax, .imm16, .none, .none, &.{ 0x25 }, 0, .none },
+ .{ .@"and", .zi, .eax, .imm32, .none, .none, &.{ 0x25 }, 0, .none },
+ .{ .@"and", .zi, .rax, .imm32s, .none, .none, &.{ 0x25 }, 0, .long },
+ .{ .@"and", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 4, .none },
+ .{ .@"and", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 4, .rex },
+ .{ .@"and", .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 4, .none },
+ .{ .@"and", .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 4, .none },
+ .{ .@"and", .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 4, .long },
+ .{ .@"and", .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 4, .none },
+ .{ .@"and", .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 4, .none },
+ .{ .@"and", .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 4, .long },
+ .{ .@"and", .mr, .rm8, .r8, .none, .none, &.{ 0x20 }, 0, .none },
+ .{ .@"and", .mr, .rm8, .r8, .none, .none, &.{ 0x20 }, 0, .rex },
+ .{ .@"and", .mr, .rm16, .r16, .none, .none, &.{ 0x21 }, 0, .none },
+ .{ .@"and", .mr, .rm32, .r32, .none, .none, &.{ 0x21 }, 0, .none },
+ .{ .@"and", .mr, .rm64, .r64, .none, .none, &.{ 0x21 }, 0, .long },
+ .{ .@"and", .rm, .r8, .rm8, .none, .none, &.{ 0x22 }, 0, .none },
+ .{ .@"and", .rm, .r8, .rm8, .none, .none, &.{ 0x22 }, 0, .rex },
+ .{ .@"and", .rm, .r16, .rm16, .none, .none, &.{ 0x23 }, 0, .none },
+ .{ .@"and", .rm, .r32, .rm32, .none, .none, &.{ 0x23 }, 0, .none },
+ .{ .@"and", .rm, .r64, .rm64, .none, .none, &.{ 0x23 }, 0, .long },
// This is M encoding according to Intel, but D makes more sense here.
- .{ .call, .d, .rel32, .none, .none, .none, 1, 0xe8, 0x00, 0x00, 0, .none },
- .{ .call, .m, .rm64, .none, .none, .none, 1, 0xff, 0x00, 0x00, 2, .none },
+ .{ .call, .d, .rel32, .none, .none, .none, &.{ 0xe8 }, 0, .none },
+ .{ .call, .m, .rm64, .none, .none, .none, &.{ 0xff }, 2, .none },
- .{ .cbw, .np, .o16, .none, .none, .none, 1, 0x98, 0x00, 0x00, 0, .none },
- .{ .cwde, .np, .o32, .none, .none, .none, 1, 0x98, 0x00, 0x00, 0, .none },
- .{ .cdqe, .np, .o64, .none, .none, .none, 1, 0x98, 0x00, 0x00, 0, .long },
+ .{ .cbw, .np, .o16, .none, .none, .none, &.{ 0x98 }, 0, .none },
+ .{ .cwde, .np, .o32, .none, .none, .none, &.{ 0x98 }, 0, .none },
+ .{ .cdqe, .np, .o64, .none, .none, .none, &.{ 0x98 }, 0, .long },
- .{ .cwd, .np, .o16, .none, .none, .none, 1, 0x99, 0x00, 0x00, 0, .none },
- .{ .cdq, .np, .o32, .none, .none, .none, 1, 0x99, 0x00, 0x00, 0, .none },
- .{ .cqo, .np, .o64, .none, .none, .none, 1, 0x99, 0x00, 0x00, 0, .long },
+ .{ .cwd, .np, .o16, .none, .none, .none, &.{ 0x99 }, 0, .none },
+ .{ .cdq, .np, .o32, .none, .none, .none, &.{ 0x99 }, 0, .none },
+ .{ .cqo, .np, .o64, .none, .none, .none, &.{ 0x99 }, 0, .long },
- .{ .cmova, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x47, 0x00, 0, .none },
- .{ .cmova, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x47, 0x00, 0, .none },
- .{ .cmova, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x47, 0x00, 0, .long },
- .{ .cmovae, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .none },
- .{ .cmovae, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .none },
- .{ .cmovae, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .long },
- .{ .cmovb, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .none },
- .{ .cmovb, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .none },
- .{ .cmovb, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .long },
- .{ .cmovbe, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x46, 0x00, 0, .none },
- .{ .cmovbe, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x46, 0x00, 0, .none },
- .{ .cmovbe, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x46, 0x00, 0, .long },
- .{ .cmovc, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .none },
- .{ .cmovc, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .none },
- .{ .cmovc, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .long },
- .{ .cmove, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x44, 0x00, 0, .none },
- .{ .cmove, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x44, 0x00, 0, .none },
- .{ .cmove, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x44, 0x00, 0, .long },
- .{ .cmovg, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4f, 0x00, 0, .none },
- .{ .cmovg, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4f, 0x00, 0, .none },
- .{ .cmovg, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4f, 0x00, 0, .long },
- .{ .cmovge, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4d, 0x00, 0, .none },
- .{ .cmovge, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4d, 0x00, 0, .none },
- .{ .cmovge, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4d, 0x00, 0, .long },
- .{ .cmovl, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4c, 0x00, 0, .none },
- .{ .cmovl, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4c, 0x00, 0, .none },
- .{ .cmovl, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4c, 0x00, 0, .long },
- .{ .cmovle, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4e, 0x00, 0, .none },
- .{ .cmovle, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4e, 0x00, 0, .none },
- .{ .cmovle, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4e, 0x00, 0, .long },
- .{ .cmovna, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x46, 0x00, 0, .none },
- .{ .cmovna, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x46, 0x00, 0, .none },
- .{ .cmovna, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x46, 0x00, 0, .long },
- .{ .cmovnae, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .none },
- .{ .cmovnae, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .none },
- .{ .cmovnae, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x42, 0x00, 0, .long },
- .{ .cmovnb, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .none },
- .{ .cmovnb, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .none },
- .{ .cmovnb, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .long },
- .{ .cmovnbe, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x47, 0x00, 0, .none },
- .{ .cmovnbe, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x47, 0x00, 0, .none },
- .{ .cmovnbe, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x47, 0x00, 0, .long },
- .{ .cmovnc, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .none },
- .{ .cmovnc, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .none },
- .{ .cmovnc, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x43, 0x00, 0, .long },
- .{ .cmovne, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x45, 0x00, 0, .none },
- .{ .cmovne, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x45, 0x00, 0, .none },
- .{ .cmovne, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x45, 0x00, 0, .long },
- .{ .cmovng, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4e, 0x00, 0, .none },
- .{ .cmovng, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4e, 0x00, 0, .none },
- .{ .cmovng, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4e, 0x00, 0, .long },
- .{ .cmovnge, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4c, 0x00, 0, .none },
- .{ .cmovnge, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4c, 0x00, 0, .none },
- .{ .cmovnge, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4c, 0x00, 0, .long },
- .{ .cmovnl, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4d, 0x00, 0, .none },
- .{ .cmovnl, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4d, 0x00, 0, .none },
- .{ .cmovnl, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4d, 0x00, 0, .long },
- .{ .cmovnle, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4f, 0x00, 0, .none },
- .{ .cmovnle, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4f, 0x00, 0, .none },
- .{ .cmovnle, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4f, 0x00, 0, .long },
- .{ .cmovno, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x41, 0x00, 0, .none },
- .{ .cmovno, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x41, 0x00, 0, .none },
- .{ .cmovno, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x41, 0x00, 0, .long },
- .{ .cmovnp, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4b, 0x00, 0, .none },
- .{ .cmovnp, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4b, 0x00, 0, .none },
- .{ .cmovnp, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4b, 0x00, 0, .long },
- .{ .cmovns, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x49, 0x00, 0, .none },
- .{ .cmovns, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x49, 0x00, 0, .none },
- .{ .cmovns, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x49, 0x00, 0, .long },
- .{ .cmovnz, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x45, 0x00, 0, .none },
- .{ .cmovnz, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x45, 0x00, 0, .none },
- .{ .cmovnz, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x45, 0x00, 0, .long },
- .{ .cmovo, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x40, 0x00, 0, .none },
- .{ .cmovo, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x40, 0x00, 0, .none },
- .{ .cmovo, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x40, 0x00, 0, .long },
- .{ .cmovp, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4a, 0x00, 0, .none },
- .{ .cmovp, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4a, 0x00, 0, .none },
- .{ .cmovp, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4a, 0x00, 0, .long },
- .{ .cmovpe, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4a, 0x00, 0, .none },
- .{ .cmovpe, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4a, 0x00, 0, .none },
- .{ .cmovpe, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4a, 0x00, 0, .long },
- .{ .cmovpo, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x4b, 0x00, 0, .none },
- .{ .cmovpo, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x4b, 0x00, 0, .none },
- .{ .cmovpo, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x4b, 0x00, 0, .long },
- .{ .cmovs, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x48, 0x00, 0, .none },
- .{ .cmovs, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x48, 0x00, 0, .none },
- .{ .cmovs, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x48, 0x00, 0, .long },
- .{ .cmovz, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0x44, 0x00, 0, .none },
- .{ .cmovz, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0x44, 0x00, 0, .none },
- .{ .cmovz, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0x44, 0x00, 0, .long },
+ .{ .cmova, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x47 }, 0, .none },
+ .{ .cmova, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x47 }, 0, .none },
+ .{ .cmova, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x47 }, 0, .long },
+ .{ .cmovae, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },
+ .{ .cmovae, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },
+ .{ .cmovae, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x43 }, 0, .long },
+ .{ .cmovb, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },
+ .{ .cmovb, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },
+ .{ .cmovb, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x42 }, 0, .long },
+ .{ .cmovbe, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x46 }, 0, .none },
+ .{ .cmovbe, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x46 }, 0, .none },
+ .{ .cmovbe, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x46 }, 0, .long },
+ .{ .cmovc, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },
+ .{ .cmovc, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },
+ .{ .cmovc, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x42 }, 0, .long },
+ .{ .cmove, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x44 }, 0, .none },
+ .{ .cmove, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x44 }, 0, .none },
+ .{ .cmove, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x44 }, 0, .long },
+ .{ .cmovg, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4f }, 0, .none },
+ .{ .cmovg, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4f }, 0, .none },
+ .{ .cmovg, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4f }, 0, .long },
+ .{ .cmovge, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4d }, 0, .none },
+ .{ .cmovge, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4d }, 0, .none },
+ .{ .cmovge, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4d }, 0, .long },
+ .{ .cmovl, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4c }, 0, .none },
+ .{ .cmovl, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4c }, 0, .none },
+ .{ .cmovl, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4c }, 0, .long },
+ .{ .cmovle, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4e }, 0, .none },
+ .{ .cmovle, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4e }, 0, .none },
+ .{ .cmovle, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4e }, 0, .long },
+ .{ .cmovna, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x46 }, 0, .none },
+ .{ .cmovna, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x46 }, 0, .none },
+ .{ .cmovna, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x46 }, 0, .long },
+ .{ .cmovnae, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },
+ .{ .cmovnae, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x42 }, 0, .none },
+ .{ .cmovnae, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x42 }, 0, .long },
+ .{ .cmovnb, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },
+ .{ .cmovnb, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },
+ .{ .cmovnb, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x43 }, 0, .long },
+ .{ .cmovnbe, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x47 }, 0, .none },
+ .{ .cmovnbe, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x47 }, 0, .none },
+ .{ .cmovnbe, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x47 }, 0, .long },
+ .{ .cmovnc, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },
+ .{ .cmovnc, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x43 }, 0, .none },
+ .{ .cmovnc, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x43 }, 0, .long },
+ .{ .cmovne, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x45 }, 0, .none },
+ .{ .cmovne, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x45 }, 0, .none },
+ .{ .cmovne, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x45 }, 0, .long },
+ .{ .cmovng, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4e }, 0, .none },
+ .{ .cmovng, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4e }, 0, .none },
+ .{ .cmovng, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4e }, 0, .long },
+ .{ .cmovnge, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4c }, 0, .none },
+ .{ .cmovnge, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4c }, 0, .none },
+ .{ .cmovnge, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4c }, 0, .long },
+ .{ .cmovnl, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4d }, 0, .none },
+ .{ .cmovnl, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4d }, 0, .none },
+ .{ .cmovnl, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4d }, 0, .long },
+ .{ .cmovnle, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4f }, 0, .none },
+ .{ .cmovnle, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4f }, 0, .none },
+ .{ .cmovnle, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4f }, 0, .long },
+ .{ .cmovno, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x41 }, 0, .none },
+ .{ .cmovno, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x41 }, 0, .none },
+ .{ .cmovno, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x41 }, 0, .long },
+ .{ .cmovnp, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4b }, 0, .none },
+ .{ .cmovnp, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4b }, 0, .none },
+ .{ .cmovnp, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4b }, 0, .long },
+ .{ .cmovns, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x49 }, 0, .none },
+ .{ .cmovns, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x49 }, 0, .none },
+ .{ .cmovns, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x49 }, 0, .long },
+ .{ .cmovnz, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x45 }, 0, .none },
+ .{ .cmovnz, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x45 }, 0, .none },
+ .{ .cmovnz, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x45 }, 0, .long },
+ .{ .cmovo, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x40 }, 0, .none },
+ .{ .cmovo, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x40 }, 0, .none },
+ .{ .cmovo, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x40 }, 0, .long },
+ .{ .cmovp, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4a }, 0, .none },
+ .{ .cmovp, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4a }, 0, .none },
+ .{ .cmovp, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4a }, 0, .long },
+ .{ .cmovpe, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4a }, 0, .none },
+ .{ .cmovpe, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4a }, 0, .none },
+ .{ .cmovpe, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4a }, 0, .long },
+ .{ .cmovpo, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x4b }, 0, .none },
+ .{ .cmovpo, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x4b }, 0, .none },
+ .{ .cmovpo, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x4b }, 0, .long },
+ .{ .cmovs, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x48 }, 0, .none },
+ .{ .cmovs, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x48 }, 0, .none },
+ .{ .cmovs, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x48 }, 0, .long },
+ .{ .cmovz, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0x44 }, 0, .none },
+ .{ .cmovz, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0x44 }, 0, .none },
+ .{ .cmovz, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0x44 }, 0, .long },
- .{ .cmp, .zi, .al, .imm8, .none, .none, 1, 0x3c, 0x00, 0x00, 0, .none },
- .{ .cmp, .zi, .ax, .imm16, .none, .none, 1, 0x3d, 0x00, 0x00, 0, .none },
- .{ .cmp, .zi, .eax, .imm32, .none, .none, 1, 0x3d, 0x00, 0x00, 0, .none },
- .{ .cmp, .zi, .rax, .imm32s, .none, .none, 1, 0x3d, 0x00, 0x00, 0, .long },
- .{ .cmp, .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 7, .none },
- .{ .cmp, .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 7, .rex },
- .{ .cmp, .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 7, .none },
- .{ .cmp, .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 7, .none },
- .{ .cmp, .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 7, .long },
- .{ .cmp, .mi, .rm16, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 7, .none },
- .{ .cmp, .mi, .rm32, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 7, .none },
- .{ .cmp, .mi, .rm64, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 7, .long },
- .{ .cmp, .mr, .rm8, .r8, .none, .none, 1, 0x38, 0x00, 0x00, 0, .none },
- .{ .cmp, .mr, .rm8, .r8, .none, .none, 1, 0x38, 0x00, 0x00, 0, .rex },
- .{ .cmp, .mr, .rm16, .r16, .none, .none, 1, 0x39, 0x00, 0x00, 0, .none },
- .{ .cmp, .mr, .rm32, .r32, .none, .none, 1, 0x39, 0x00, 0x00, 0, .none },
- .{ .cmp, .mr, .rm64, .r64, .none, .none, 1, 0x39, 0x00, 0x00, 0, .long },
- .{ .cmp, .rm, .r8, .rm8, .none, .none, 1, 0x3a, 0x00, 0x00, 0, .none },
- .{ .cmp, .rm, .r8, .rm8, .none, .none, 1, 0x3a, 0x00, 0x00, 0, .rex },
- .{ .cmp, .rm, .r16, .rm16, .none, .none, 1, 0x3b, 0x00, 0x00, 0, .none },
- .{ .cmp, .rm, .r32, .rm32, .none, .none, 1, 0x3b, 0x00, 0x00, 0, .none },
- .{ .cmp, .rm, .r64, .rm64, .none, .none, 1, 0x3b, 0x00, 0x00, 0, .long },
+ .{ .cmp, .zi, .al, .imm8, .none, .none, &.{ 0x3c }, 0, .none },
+ .{ .cmp, .zi, .ax, .imm16, .none, .none, &.{ 0x3d }, 0, .none },
+ .{ .cmp, .zi, .eax, .imm32, .none, .none, &.{ 0x3d }, 0, .none },
+ .{ .cmp, .zi, .rax, .imm32s, .none, .none, &.{ 0x3d }, 0, .long },
+ .{ .cmp, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 7, .none },
+ .{ .cmp, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 7, .rex },
+ .{ .cmp, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 7, .none },
+ .{ .cmp, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 7, .none },
+ .{ .cmp, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 7, .long },
+ .{ .cmp, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 7, .none },
+ .{ .cmp, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 7, .none },
+ .{ .cmp, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 7, .long },
+ .{ .cmp, .mr, .rm8, .r8, .none, .none, &.{ 0x38 }, 0, .none },
+ .{ .cmp, .mr, .rm8, .r8, .none, .none, &.{ 0x38 }, 0, .rex },
+ .{ .cmp, .mr, .rm16, .r16, .none, .none, &.{ 0x39 }, 0, .none },
+ .{ .cmp, .mr, .rm32, .r32, .none, .none, &.{ 0x39 }, 0, .none },
+ .{ .cmp, .mr, .rm64, .r64, .none, .none, &.{ 0x39 }, 0, .long },
+ .{ .cmp, .rm, .r8, .rm8, .none, .none, &.{ 0x3a }, 0, .none },
+ .{ .cmp, .rm, .r8, .rm8, .none, .none, &.{ 0x3a }, 0, .rex },
+ .{ .cmp, .rm, .r16, .rm16, .none, .none, &.{ 0x3b }, 0, .none },
+ .{ .cmp, .rm, .r32, .rm32, .none, .none, &.{ 0x3b }, 0, .none },
+ .{ .cmp, .rm, .r64, .rm64, .none, .none, &.{ 0x3b }, 0, .long },
- .{ .div, .m, .rm8, .none, .none, .none, 1, 0xf6, 0x00, 0x00, 6, .none },
- .{ .div, .m, .rm8, .none, .none, .none, 1, 0xf6, 0x00, 0x00, 6, .rex },
- .{ .div, .m, .rm16, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 6, .none },
- .{ .div, .m, .rm32, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 6, .none },
- .{ .div, .m, .rm64, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 6, .long },
+ .{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .none },
+ .{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .rex },
+ .{ .div, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 6, .none },
+ .{ .div, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 6, .none },
+ .{ .div, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 6, .long },
- .{ .fisttp, .m, .m16, .none, .none, .none, 1, 0xdf, 0x00, 0x00, 1, .fpu },
- .{ .fisttp, .m, .m32, .none, .none, .none, 1, 0xdb, 0x00, 0x00, 1, .fpu },
- .{ .fisttp, .m, .m64, .none, .none, .none, 1, 0xdd, 0x00, 0x00, 1, .fpu },
+ .{ .fisttp, .m, .m16, .none, .none, .none, &.{ 0xdf }, 1, .fpu },
+ .{ .fisttp, .m, .m32, .none, .none, .none, &.{ 0xdb }, 1, .fpu },
+ .{ .fisttp, .m, .m64, .none, .none, .none, &.{ 0xdd }, 1, .fpu },
- .{ .fld, .m, .m32, .none, .none, .none, 1, 0xd9, 0x00, 0x00, 0, .fpu },
- .{ .fld, .m, .m64, .none, .none, .none, 1, 0xdd, 0x00, 0x00, 0, .fpu },
- .{ .fld, .m, .m80, .none, .none, .none, 1, 0xdb, 0x00, 0x00, 5, .fpu },
+ .{ .fld, .m, .m32, .none, .none, .none, &.{ 0xd9 }, 0, .fpu },
+ .{ .fld, .m, .m64, .none, .none, .none, &.{ 0xdd }, 0, .fpu },
+ .{ .fld, .m, .m80, .none, .none, .none, &.{ 0xdb }, 5, .fpu },
- .{ .idiv, .m, .rm8, .none, .none, .none, 1, 0xf6, 0x00, 0x00, 7, .none },
- .{ .idiv, .m, .rm8, .none, .none, .none, 1, 0xf6, 0x00, 0x00, 7, .rex },
- .{ .idiv, .m, .rm16, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 7, .none },
- .{ .idiv, .m, .rm32, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 7, .none },
- .{ .idiv, .m, .rm64, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 7, .long },
+ .{ .idiv, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 7, .none },
+ .{ .idiv, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 7, .rex },
+ .{ .idiv, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 7, .none },
+ .{ .idiv, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 7, .none },
+ .{ .idiv, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 7, .long },
- .{ .imul, .m, .rm8, .none, .none, .none, 1, 0xf6, 0x00, 0x00, 5, .none },
- .{ .imul, .m, .rm8, .none, .none, .none, 1, 0xf6, 0x00, 0x00, 5, .rex },
- .{ .imul, .m, .rm16, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 5, .none },
- .{ .imul, .m, .rm32, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 5, .none },
- .{ .imul, .m, .rm64, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 5, .long },
- .{ .imul, .rm, .r16, .rm16, .none, .none, 2, 0x0f, 0xaf, 0x00, 0, .none },
- .{ .imul, .rm, .r32, .rm32, .none, .none, 2, 0x0f, 0xaf, 0x00, 0, .none },
- .{ .imul, .rm, .r64, .rm64, .none, .none, 2, 0x0f, 0xaf, 0x00, 0, .long },
- .{ .imul, .rmi, .r16, .rm16, .imm8s, .none, 1, 0x6b, 0x00, 0x00, 0, .none },
- .{ .imul, .rmi, .r32, .rm32, .imm8s, .none, 1, 0x6b, 0x00, 0x00, 0, .none },
- .{ .imul, .rmi, .r64, .rm64, .imm8s, .none, 1, 0x6b, 0x00, 0x00, 0, .long },
- .{ .imul, .rmi, .r16, .rm16, .imm16, .none, 1, 0x69, 0x00, 0x00, 0, .none },
- .{ .imul, .rmi, .r32, .rm32, .imm32, .none, 1, 0x69, 0x00, 0x00, 0, .none },
- .{ .imul, .rmi, .r64, .rm64, .imm32, .none, 1, 0x69, 0x00, 0x00, 0, .long },
+ .{ .imul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 5, .none },
+ .{ .imul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 5, .rex },
+ .{ .imul, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 5, .none },
+ .{ .imul, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 5, .none },
+ .{ .imul, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 5, .long },
+ .{ .imul, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0xaf }, 0, .none },
+ .{ .imul, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xaf }, 0, .none },
+ .{ .imul, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xaf }, 0, .long },
+ .{ .imul, .rmi, .r16, .rm16, .imm8s, .none, &.{ 0x6b }, 0, .none },
+ .{ .imul, .rmi, .r32, .rm32, .imm8s, .none, &.{ 0x6b }, 0, .none },
+ .{ .imul, .rmi, .r64, .rm64, .imm8s, .none, &.{ 0x6b }, 0, .long },
+ .{ .imul, .rmi, .r16, .rm16, .imm16, .none, &.{ 0x69 }, 0, .none },
+ .{ .imul, .rmi, .r32, .rm32, .imm32, .none, &.{ 0x69 }, 0, .none },
+ .{ .imul, .rmi, .r64, .rm64, .imm32, .none, &.{ 0x69 }, 0, .long },
- .{ .int3, .np, .none, .none, .none, .none, 1, 0xcc, 0x00, 0x00, 0, .none },
+ .{ .int3, .np, .none, .none, .none, .none, &.{ 0xcc }, 0, .none },
- .{ .ja, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x87, 0x00, 0, .none },
- .{ .jae, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x83, 0x00, 0, .none },
- .{ .jb, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x82, 0x00, 0, .none },
- .{ .jbe, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x86, 0x00, 0, .none },
- .{ .jc, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x82, 0x00, 0, .none },
- .{ .jrcxz, .d, .rel32, .none, .none, .none, 1, 0xe3, 0x00, 0x00, 0, .none },
- .{ .je, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x84, 0x00, 0, .none },
- .{ .jg, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8f, 0x00, 0, .none },
- .{ .jge, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8d, 0x00, 0, .none },
- .{ .jl, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8c, 0x00, 0, .none },
- .{ .jle, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8e, 0x00, 0, .none },
- .{ .jna, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x86, 0x00, 0, .none },
- .{ .jnae, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x82, 0x00, 0, .none },
- .{ .jnb, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x83, 0x00, 0, .none },
- .{ .jnbe, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x87, 0x00, 0, .none },
- .{ .jnc, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x83, 0x00, 0, .none },
- .{ .jne, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x85, 0x00, 0, .none },
- .{ .jng, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8e, 0x00, 0, .none },
- .{ .jnge, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8c, 0x00, 0, .none },
- .{ .jnl, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8d, 0x00, 0, .none },
- .{ .jnle, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8f, 0x00, 0, .none },
- .{ .jno, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x81, 0x00, 0, .none },
- .{ .jnp, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8b, 0x00, 0, .none },
- .{ .jns, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x89, 0x00, 0, .none },
- .{ .jnz, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x85, 0x00, 0, .none },
- .{ .jo, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x80, 0x00, 0, .none },
- .{ .jp, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8a, 0x00, 0, .none },
- .{ .jpe, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8a, 0x00, 0, .none },
- .{ .jpo, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x8b, 0x00, 0, .none },
- .{ .js, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x88, 0x00, 0, .none },
- .{ .jz, .d, .rel32, .none, .none, .none, 2, 0x0f, 0x84, 0x00, 0, .none },
+ .{ .ja, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x87 }, 0, .none },
+ .{ .jae, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x83 }, 0, .none },
+ .{ .jb, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x82 }, 0, .none },
+ .{ .jbe, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x86 }, 0, .none },
+ .{ .jc, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x82 }, 0, .none },
+ .{ .jrcxz, .d, .rel32, .none, .none, .none, &.{ 0xe3 }, 0, .none },
+ .{ .je, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x84 }, 0, .none },
+ .{ .jg, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8f }, 0, .none },
+ .{ .jge, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8d }, 0, .none },
+ .{ .jl, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8c }, 0, .none },
+ .{ .jle, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8e }, 0, .none },
+ .{ .jna, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x86 }, 0, .none },
+ .{ .jnae, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x82 }, 0, .none },
+ .{ .jnb, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x83 }, 0, .none },
+ .{ .jnbe, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x87 }, 0, .none },
+ .{ .jnc, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x83 }, 0, .none },
+ .{ .jne, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x85 }, 0, .none },
+ .{ .jng, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8e }, 0, .none },
+ .{ .jnge, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8c }, 0, .none },
+ .{ .jnl, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8d }, 0, .none },
+ .{ .jnle, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8f }, 0, .none },
+ .{ .jno, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x81 }, 0, .none },
+ .{ .jnp, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8b }, 0, .none },
+ .{ .jns, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x89 }, 0, .none },
+ .{ .jnz, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x85 }, 0, .none },
+ .{ .jo, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x80 }, 0, .none },
+ .{ .jp, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8a }, 0, .none },
+ .{ .jpe, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8a }, 0, .none },
+ .{ .jpo, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x8b }, 0, .none },
+ .{ .js, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x88 }, 0, .none },
+ .{ .jz, .d, .rel32, .none, .none, .none, &.{ 0x0f, 0x84 }, 0, .none },
- .{ .jmp, .d, .rel32, .none, .none, .none, 1, 0xe9, 0x00, 0x00, 0, .none },
- .{ .jmp, .m, .rm64, .none, .none, .none, 1, 0xff, 0x00, 0x00, 4, .none },
+ .{ .jmp, .d, .rel32, .none, .none, .none, &.{ 0xe9 }, 0, .none },
+ .{ .jmp, .m, .rm64, .none, .none, .none, &.{ 0xff }, 4, .none },
- .{ .lea, .rm, .r16, .m, .none, .none, 1, 0x8d, 0x00, 0x00, 0, .none },
- .{ .lea, .rm, .r32, .m, .none, .none, 1, 0x8d, 0x00, 0x00, 0, .none },
- .{ .lea, .rm, .r64, .m, .none, .none, 1, 0x8d, 0x00, 0x00, 0, .long },
+ .{ .lea, .rm, .r16, .m, .none, .none, &.{ 0x8d }, 0, .none },
+ .{ .lea, .rm, .r32, .m, .none, .none, &.{ 0x8d }, 0, .none },
+ .{ .lea, .rm, .r64, .m, .none, .none, &.{ 0x8d }, 0, .long },
- .{ .mov, .mr, .rm8, .r8, .none, .none, 1, 0x88, 0x00, 0x00, 0, .none },
- .{ .mov, .mr, .rm8, .r8, .none, .none, 1, 0x88, 0x00, 0x00, 0, .rex },
- .{ .mov, .mr, .rm16, .r16, .none, .none, 1, 0x89, 0x00, 0x00, 0, .none },
- .{ .mov, .mr, .rm32, .r32, .none, .none, 1, 0x89, 0x00, 0x00, 0, .none },
- .{ .mov, .mr, .rm64, .r64, .none, .none, 1, 0x89, 0x00, 0x00, 0, .long },
- .{ .mov, .rm, .r8, .rm8, .none, .none, 1, 0x8a, 0x00, 0x00, 0, .none },
- .{ .mov, .rm, .r8, .rm8, .none, .none, 1, 0x8a, 0x00, 0x00, 0, .rex },
- .{ .mov, .rm, .r16, .rm16, .none, .none, 1, 0x8b, 0x00, 0x00, 0, .none },
- .{ .mov, .rm, .r32, .rm32, .none, .none, 1, 0x8b, 0x00, 0x00, 0, .none },
- .{ .mov, .rm, .r64, .rm64, .none, .none, 1, 0x8b, 0x00, 0x00, 0, .long },
- .{ .mov, .mr, .rm16, .sreg, .none, .none, 1, 0x8c, 0x00, 0x00, 0, .none },
- .{ .mov, .mr, .rm64, .sreg, .none, .none, 1, 0x8c, 0x00, 0x00, 0, .long },
- .{ .mov, .rm, .sreg, .rm16, .none, .none, 1, 0x8e, 0x00, 0x00, 0, .none },
- .{ .mov, .rm, .sreg, .rm64, .none, .none, 1, 0x8e, 0x00, 0x00, 0, .long },
- .{ .mov, .fd, .al, .moffs, .none, .none, 1, 0xa0, 0x00, 0x00, 0, .none },
- .{ .mov, .fd, .ax, .moffs, .none, .none, 1, 0xa1, 0x00, 0x00, 0, .none },
- .{ .mov, .fd, .eax, .moffs, .none, .none, 1, 0xa1, 0x00, 0x00, 0, .none },
- .{ .mov, .fd, .rax, .moffs, .none, .none, 1, 0xa1, 0x00, 0x00, 0, .long },
- .{ .mov, .td, .moffs, .al, .none, .none, 1, 0xa2, 0x00, 0x00, 0, .none },
- .{ .mov, .td, .moffs, .ax, .none, .none, 1, 0xa3, 0x00, 0x00, 0, .none },
- .{ .mov, .td, .moffs, .eax, .none, .none, 1, 0xa3, 0x00, 0x00, 0, .none },
- .{ .mov, .td, .moffs, .rax, .none, .none, 1, 0xa3, 0x00, 0x00, 0, .long },
- .{ .mov, .oi, .r8, .imm8, .none, .none, 1, 0xb0, 0x00, 0x00, 0, .none },
- .{ .mov, .oi, .r8, .imm8, .none, .none, 1, 0xb0, 0x00, 0x00, 0, .rex },
- .{ .mov, .oi, .r16, .imm16, .none, .none, 1, 0xb8, 0x00, 0x00, 0, .none },
- .{ .mov, .oi, .r32, .imm32, .none, .none, 1, 0xb8, 0x00, 0x00, 0, .none },
- .{ .mov, .oi, .r64, .imm64, .none, .none, 1, 0xb8, 0x00, 0x00, 0, .long },
- .{ .mov, .mi, .rm8, .imm8, .none, .none, 1, 0xc6, 0x00, 0x00, 0, .none },
- .{ .mov, .mi, .rm8, .imm8, .none, .none, 1, 0xc6, 0x00, 0x00, 0, .rex },
- .{ .mov, .mi, .rm16, .imm16, .none, .none, 1, 0xc7, 0x00, 0x00, 0, .none },
- .{ .mov, .mi, .rm32, .imm32, .none, .none, 1, 0xc7, 0x00, 0x00, 0, .none },
- .{ .mov, .mi, .rm64, .imm32s, .none, .none, 1, 0xc7, 0x00, 0x00, 0, .long },
+ .{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .none },
+ .{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .rex },
+ .{ .mov, .mr, .rm16, .r16, .none, .none, &.{ 0x89 }, 0, .none },
+ .{ .mov, .mr, .rm32, .r32, .none, .none, &.{ 0x89 }, 0, .none },
+ .{ .mov, .mr, .rm64, .r64, .none, .none, &.{ 0x89 }, 0, .long },
+ .{ .mov, .rm, .r8, .rm8, .none, .none, &.{ 0x8a }, 0, .none },
+ .{ .mov, .rm, .r8, .rm8, .none, .none, &.{ 0x8a }, 0, .rex },
+ .{ .mov, .rm, .r16, .rm16, .none, .none, &.{ 0x8b }, 0, .none },
+ .{ .mov, .rm, .r32, .rm32, .none, .none, &.{ 0x8b }, 0, .none },
+ .{ .mov, .rm, .r64, .rm64, .none, .none, &.{ 0x8b }, 0, .long },
+ .{ .mov, .mr, .rm16, .sreg, .none, .none, &.{ 0x8c }, 0, .none },
+ .{ .mov, .mr, .rm64, .sreg, .none, .none, &.{ 0x8c }, 0, .long },
+ .{ .mov, .rm, .sreg, .rm16, .none, .none, &.{ 0x8e }, 0, .none },
+ .{ .mov, .rm, .sreg, .rm64, .none, .none, &.{ 0x8e }, 0, .long },
+ .{ .mov, .fd, .al, .moffs, .none, .none, &.{ 0xa0 }, 0, .none },
+ .{ .mov, .fd, .ax, .moffs, .none, .none, &.{ 0xa1 }, 0, .none },
+ .{ .mov, .fd, .eax, .moffs, .none, .none, &.{ 0xa1 }, 0, .none },
+ .{ .mov, .fd, .rax, .moffs, .none, .none, &.{ 0xa1 }, 0, .long },
+ .{ .mov, .td, .moffs, .al, .none, .none, &.{ 0xa2 }, 0, .none },
+ .{ .mov, .td, .moffs, .ax, .none, .none, &.{ 0xa3 }, 0, .none },
+ .{ .mov, .td, .moffs, .eax, .none, .none, &.{ 0xa3 }, 0, .none },
+ .{ .mov, .td, .moffs, .rax, .none, .none, &.{ 0xa3 }, 0, .long },
+ .{ .mov, .oi, .r8, .imm8, .none, .none, &.{ 0xb0 }, 0, .none },
+ .{ .mov, .oi, .r8, .imm8, .none, .none, &.{ 0xb0 }, 0, .rex },
+ .{ .mov, .oi, .r16, .imm16, .none, .none, &.{ 0xb8 }, 0, .none },
+ .{ .mov, .oi, .r32, .imm32, .none, .none, &.{ 0xb8 }, 0, .none },
+ .{ .mov, .oi, .r64, .imm64, .none, .none, &.{ 0xb8 }, 0, .long },
+ .{ .mov, .mi, .rm8, .imm8, .none, .none, &.{ 0xc6 }, 0, .none },
+ .{ .mov, .mi, .rm8, .imm8, .none, .none, &.{ 0xc6 }, 0, .rex },
+ .{ .mov, .mi, .rm16, .imm16, .none, .none, &.{ 0xc7 }, 0, .none },
+ .{ .mov, .mi, .rm32, .imm32, .none, .none, &.{ 0xc7 }, 0, .none },
+ .{ .mov, .mi, .rm64, .imm32s, .none, .none, &.{ 0xc7 }, 0, .long },
- .{ .movsx, .rm, .r16, .rm8, .none, .none, 2, 0x0f, 0xbe, 0x00, 0, .none },
- .{ .movsx, .rm, .r16, .rm8, .none, .none, 2, 0x0f, 0xbe, 0x00, 0, .rex },
- .{ .movsx, .rm, .r32, .rm8, .none, .none, 2, 0x0f, 0xbe, 0x00, 0, .none },
- .{ .movsx, .rm, .r32, .rm8, .none, .none, 2, 0x0f, 0xbe, 0x00, 0, .rex },
- .{ .movsx, .rm, .r64, .rm8, .none, .none, 2, 0x0f, 0xbe, 0x00, 0, .long },
- .{ .movsx, .rm, .r32, .rm16, .none, .none, 2, 0x0f, 0xbf, 0x00, 0, .none },
- .{ .movsx, .rm, .r64, .rm16, .none, .none, 2, 0x0f, 0xbf, 0x00, 0, .long },
+ .{ .movsx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .none },
+ .{ .movsx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .rex },
+ .{ .movsx, .rm, .r32, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .none },
+ .{ .movsx, .rm, .r32, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .rex },
+ .{ .movsx, .rm, .r64, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .long },
+ .{ .movsx, .rm, .r32, .rm16, .none, .none, &.{ 0x0f, 0xbf }, 0, .none },
+ .{ .movsx, .rm, .r64, .rm16, .none, .none, &.{ 0x0f, 0xbf }, 0, .long },
// This instruction is discouraged.
- .{ .movsxd, .rm, .r32, .rm32, .none, .none, 1, 0x63, 0x00, 0x00, 0, .none },
- .{ .movsxd, .rm, .r64, .rm32, .none, .none, 1, 0x63, 0x00, 0x00, 0, .long },
+ .{ .movsxd, .rm, .r32, .rm32, .none, .none, &.{ 0x63 }, 0, .none },
+ .{ .movsxd, .rm, .r64, .rm32, .none, .none, &.{ 0x63 }, 0, .long },
- .{ .movzx, .rm, .r16, .rm8, .none, .none, 2, 0x0f, 0xb6, 0x00, 0, .none },
- .{ .movzx, .rm, .r32, .rm8, .none, .none, 2, 0x0f, 0xb6, 0x00, 0, .none },
- .{ .movzx, .rm, .r64, .rm8, .none, .none, 2, 0x0f, 0xb6, 0x00, 0, .long },
- .{ .movzx, .rm, .r32, .rm16, .none, .none, 2, 0x0f, 0xb7, 0x00, 0, .none },
- .{ .movzx, .rm, .r64, .rm16, .none, .none, 2, 0x0f, 0xb7, 0x00, 0, .long },
+ .{ .movzx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xb6 }, 0, .none },
+ .{ .movzx, .rm, .r32, .rm8, .none, .none, &.{ 0x0f, 0xb6 }, 0, .none },
+ .{ .movzx, .rm, .r64, .rm8, .none, .none, &.{ 0x0f, 0xb6 }, 0, .long },
+ .{ .movzx, .rm, .r32, .rm16, .none, .none, &.{ 0x0f, 0xb7 }, 0, .none },
+ .{ .movzx, .rm, .r64, .rm16, .none, .none, &.{ 0x0f, 0xb7 }, 0, .long },
- .{ .mul, .m, .rm8, .none, .none, .none, 1, 0xf6, 0x00, 0x00, 4, .none },
- .{ .mul, .m, .rm8, .none, .none, .none, 1, 0xf6, 0x00, 0x00, 4, .rex },
- .{ .mul, .m, .rm16, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 4, .none },
- .{ .mul, .m, .rm32, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 4, .none },
- .{ .mul, .m, .rm64, .none, .none, .none, 1, 0xf7, 0x00, 0x00, 4, .long },
+ .{ .mul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 4, .none },
+ .{ .mul, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 4, .rex },
+ .{ .mul, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 4, .none },
+ .{ .mul, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 4, .none },
+ .{ .mul, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 4, .long },
- .{ .nop, .np, .none, .none, .none, .none, 1, 0x90, 0x00, 0x00, 0, .none },
+ .{ .nop, .np, .none, .none, .none, .none, &.{ 0x90 }, 0, .none },
- .{ .@"or", .zi, .al, .imm8, .none, .none, 1, 0x0c, 0x00, 0x00, 0, .none },
- .{ .@"or", .zi, .ax, .imm16, .none, .none, 1, 0x0d, 0x00, 0x00, 0, .none },
- .{ .@"or", .zi, .eax, .imm32, .none, .none, 1, 0x0d, 0x00, 0x00, 0, .none },
- .{ .@"or", .zi, .rax, .imm32s, .none, .none, 1, 0x0d, 0x00, 0x00, 0, .long },
- .{ .@"or", .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 1, .none },
- .{ .@"or", .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 1, .rex },
- .{ .@"or", .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 1, .none },
- .{ .@"or", .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 1, .none },
- .{ .@"or", .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 1, .long },
- .{ .@"or", .mi, .rm16, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 1, .none },
- .{ .@"or", .mi, .rm32, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 1, .none },
- .{ .@"or", .mi, .rm64, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 1, .long },
- .{ .@"or", .mr, .rm8, .r8, .none, .none, 1, 0x08, 0x00, 0x00, 0, .none },
- .{ .@"or", .mr, .rm8, .r8, .none, .none, 1, 0x08, 0x00, 0x00, 0, .rex },
- .{ .@"or", .mr, .rm16, .r16, .none, .none, 1, 0x09, 0x00, 0x00, 0, .none },
- .{ .@"or", .mr, .rm32, .r32, .none, .none, 1, 0x09, 0x00, 0x00, 0, .none },
- .{ .@"or", .mr, .rm64, .r64, .none, .none, 1, 0x09, 0x00, 0x00, 0, .long },
- .{ .@"or", .rm, .r8, .rm8, .none, .none, 1, 0x0a, 0x00, 0x00, 0, .none },
- .{ .@"or", .rm, .r8, .rm8, .none, .none, 1, 0x0a, 0x00, 0x00, 0, .rex },
- .{ .@"or", .rm, .r16, .rm16, .none, .none, 1, 0x0b, 0x00, 0x00, 0, .none },
- .{ .@"or", .rm, .r32, .rm32, .none, .none, 1, 0x0b, 0x00, 0x00, 0, .none },
- .{ .@"or", .rm, .r64, .rm64, .none, .none, 1, 0x0b, 0x00, 0x00, 0, .long },
+ .{ .@"or", .zi, .al, .imm8, .none, .none, &.{ 0x0c }, 0, .none },
+ .{ .@"or", .zi, .ax, .imm16, .none, .none, &.{ 0x0d }, 0, .none },
+ .{ .@"or", .zi, .eax, .imm32, .none, .none, &.{ 0x0d }, 0, .none },
+ .{ .@"or", .zi, .rax, .imm32s, .none, .none, &.{ 0x0d }, 0, .long },
+ .{ .@"or", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 1, .none },
+ .{ .@"or", .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 1, .rex },
+ .{ .@"or", .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 1, .none },
+ .{ .@"or", .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 1, .none },
+ .{ .@"or", .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 1, .long },
+ .{ .@"or", .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 1, .none },
+ .{ .@"or", .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 1, .none },
+ .{ .@"or", .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 1, .long },
+ .{ .@"or", .mr, .rm8, .r8, .none, .none, &.{ 0x08 }, 0, .none },
+ .{ .@"or", .mr, .rm8, .r8, .none, .none, &.{ 0x08 }, 0, .rex },
+ .{ .@"or", .mr, .rm16, .r16, .none, .none, &.{ 0x09 }, 0, .none },
+ .{ .@"or", .mr, .rm32, .r32, .none, .none, &.{ 0x09 }, 0, .none },
+ .{ .@"or", .mr, .rm64, .r64, .none, .none, &.{ 0x09 }, 0, .long },
+ .{ .@"or", .rm, .r8, .rm8, .none, .none, &.{ 0x0a }, 0, .none },
+ .{ .@"or", .rm, .r8, .rm8, .none, .none, &.{ 0x0a }, 0, .rex },
+ .{ .@"or", .rm, .r16, .rm16, .none, .none, &.{ 0x0b }, 0, .none },
+ .{ .@"or", .rm, .r32, .rm32, .none, .none, &.{ 0x0b }, 0, .none },
+ .{ .@"or", .rm, .r64, .rm64, .none, .none, &.{ 0x0b }, 0, .long },
- .{ .pop, .o, .r16, .none, .none, .none, 1, 0x58, 0x00, 0x00, 0, .none },
- .{ .pop, .o, .r64, .none, .none, .none, 1, 0x58, 0x00, 0x00, 0, .none },
- .{ .pop, .m, .rm16, .none, .none, .none, 1, 0x8f, 0x00, 0x00, 0, .none },
- .{ .pop, .m, .rm64, .none, .none, .none, 1, 0x8f, 0x00, 0x00, 0, .none },
+ .{ .pop, .o, .r16, .none, .none, .none, &.{ 0x58 }, 0, .none },
+ .{ .pop, .o, .r64, .none, .none, .none, &.{ 0x58 }, 0, .none },
+ .{ .pop, .m, .rm16, .none, .none, .none, &.{ 0x8f }, 0, .none },
+ .{ .pop, .m, .rm64, .none, .none, .none, &.{ 0x8f }, 0, .none },
- .{ .push, .o, .r16, .none, .none, .none, 1, 0x50, 0x00, 0x00, 0, .none },
- .{ .push, .o, .r64, .none, .none, .none, 1, 0x50, 0x00, 0x00, 0, .none },
- .{ .push, .m, .rm16, .none, .none, .none, 1, 0xff, 0x00, 0x00, 6, .none },
- .{ .push, .m, .rm64, .none, .none, .none, 1, 0xff, 0x00, 0x00, 6, .none },
- .{ .push, .i, .imm8, .none, .none, .none, 1, 0x6a, 0x00, 0x00, 0, .none },
- .{ .push, .i, .imm16, .none, .none, .none, 1, 0x68, 0x00, 0x00, 0, .none },
- .{ .push, .i, .imm32, .none, .none, .none, 1, 0x68, 0x00, 0x00, 0, .none },
+ .{ .push, .o, .r16, .none, .none, .none, &.{ 0x50 }, 0, .none },
+ .{ .push, .o, .r64, .none, .none, .none, &.{ 0x50 }, 0, .none },
+ .{ .push, .m, .rm16, .none, .none, .none, &.{ 0xff }, 6, .none },
+ .{ .push, .m, .rm64, .none, .none, .none, &.{ 0xff }, 6, .none },
+ .{ .push, .i, .imm8, .none, .none, .none, &.{ 0x6a }, 0, .none },
+ .{ .push, .i, .imm16, .none, .none, .none, &.{ 0x68 }, 0, .none },
+ .{ .push, .i, .imm32, .none, .none, .none, &.{ 0x68 }, 0, .none },
- .{ .ret, .np, .none, .none, .none, .none, 1, 0xc3, 0x00, 0x00, 0, .none },
+ .{ .ret, .np, .none, .none, .none, .none, &.{ 0xc3 }, 0, .none },
- .{ .sal, .m1, .rm8, .unity, .none, .none, 1, 0xd0, 0x00, 0x00, 4, .none },
- .{ .sal, .m1, .rm8, .unity, .none, .none, 1, 0xd0, 0x00, 0x00, 4, .rex },
- .{ .sal, .m1, .rm16, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 4, .none },
- .{ .sal, .m1, .rm32, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 4, .none },
- .{ .sal, .m1, .rm64, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 4, .long },
- .{ .sal, .mc, .rm8, .cl, .none, .none, 1, 0xd2, 0x00, 0x00, 4, .none },
- .{ .sal, .mc, .rm8, .cl, .none, .none, 1, 0xd2, 0x00, 0x00, 4, .rex },
- .{ .sal, .mc, .rm16, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 4, .none },
- .{ .sal, .mc, .rm32, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 4, .none },
- .{ .sal, .mc, .rm64, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 4, .long },
- .{ .sal, .mi, .rm8, .imm8, .none, .none, 1, 0xc0, 0x00, 0x00, 4, .none },
- .{ .sal, .mi, .rm8, .imm8, .none, .none, 1, 0xc0, 0x00, 0x00, 4, .rex },
- .{ .sal, .mi, .rm16, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 4, .none },
- .{ .sal, .mi, .rm32, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 4, .none },
- .{ .sal, .mi, .rm64, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 4, .long },
+ .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none },
+ .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex },
+ .{ .sal, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none },
+ .{ .sal, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 4, .none },
+ .{ .sal, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 4, .long },
+ .{ .sal, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .none },
+ .{ .sal, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .rex },
+ .{ .sal, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 4, .none },
+ .{ .sal, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 4, .none },
+ .{ .sal, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 4, .long },
+ .{ .sal, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .none },
+ .{ .sal, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .rex },
+ .{ .sal, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },
+ .{ .sal, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },
+ .{ .sal, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 4, .long },
- .{ .sar, .m1, .rm8, .unity, .none, .none, 1, 0xd0, 0x00, 0x00, 7, .none },
- .{ .sar, .m1, .rm8, .unity, .none, .none, 1, 0xd0, 0x00, 0x00, 7, .rex },
- .{ .sar, .m1, .rm16, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 7, .none },
- .{ .sar, .m1, .rm32, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 7, .none },
- .{ .sar, .m1, .rm64, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 7, .long },
- .{ .sar, .mc, .rm8, .cl, .none, .none, 1, 0xd2, 0x00, 0x00, 7, .none },
- .{ .sar, .mc, .rm8, .cl, .none, .none, 1, 0xd2, 0x00, 0x00, 7, .rex },
- .{ .sar, .mc, .rm16, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 7, .none },
- .{ .sar, .mc, .rm32, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 7, .none },
- .{ .sar, .mc, .rm64, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 7, .long },
- .{ .sar, .mi, .rm8, .imm8, .none, .none, 1, 0xc0, 0x00, 0x00, 7, .none },
- .{ .sar, .mi, .rm8, .imm8, .none, .none, 1, 0xc0, 0x00, 0x00, 7, .rex },
- .{ .sar, .mi, .rm16, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 7, .none },
- .{ .sar, .mi, .rm32, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 7, .none },
- .{ .sar, .mi, .rm64, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 7, .long },
+ .{ .sar, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 7, .none },
+ .{ .sar, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 7, .rex },
+ .{ .sar, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 7, .none },
+ .{ .sar, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 7, .none },
+ .{ .sar, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 7, .long },
+ .{ .sar, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 7, .none },
+ .{ .sar, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 7, .rex },
+ .{ .sar, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 7, .none },
+ .{ .sar, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 7, .none },
+ .{ .sar, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 7, .long },
+ .{ .sar, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 7, .none },
+ .{ .sar, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 7, .rex },
+ .{ .sar, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 7, .none },
+ .{ .sar, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 7, .none },
+ .{ .sar, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 7, .long },
- .{ .sbb, .zi, .al, .imm8, .none, .none, 1, 0x1c, 0x00, 0x00, 0, .none },
- .{ .sbb, .zi, .ax, .imm16, .none, .none, 1, 0x1d, 0x00, 0x00, 0, .none },
- .{ .sbb, .zi, .eax, .imm32, .none, .none, 1, 0x1d, 0x00, 0x00, 0, .none },
- .{ .sbb, .zi, .rax, .imm32s, .none, .none, 1, 0x1d, 0x00, 0x00, 0, .long },
- .{ .sbb, .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 3, .none },
- .{ .sbb, .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 3, .rex },
- .{ .sbb, .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 3, .none },
- .{ .sbb, .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 3, .none },
- .{ .sbb, .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 3, .long },
- .{ .sbb, .mi, .rm16, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 3, .none },
- .{ .sbb, .mi, .rm32, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 3, .none },
- .{ .sbb, .mi, .rm64, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 3, .long },
- .{ .sbb, .mr, .rm8, .r8, .none, .none, 1, 0x18, 0x00, 0x00, 0, .none },
- .{ .sbb, .mr, .rm8, .r8, .none, .none, 1, 0x18, 0x00, 0x00, 0, .rex },
- .{ .sbb, .mr, .rm16, .r16, .none, .none, 1, 0x19, 0x00, 0x00, 0, .none },
- .{ .sbb, .mr, .rm32, .r32, .none, .none, 1, 0x19, 0x00, 0x00, 0, .none },
- .{ .sbb, .mr, .rm64, .r64, .none, .none, 1, 0x19, 0x00, 0x00, 0, .long },
- .{ .sbb, .rm, .r8, .rm8, .none, .none, 1, 0x1a, 0x00, 0x00, 0, .none },
- .{ .sbb, .rm, .r8, .rm8, .none, .none, 1, 0x1a, 0x00, 0x00, 0, .rex },
- .{ .sbb, .rm, .r16, .rm16, .none, .none, 1, 0x1b, 0x00, 0x00, 0, .none },
- .{ .sbb, .rm, .r32, .rm32, .none, .none, 1, 0x1b, 0x00, 0x00, 0, .none },
- .{ .sbb, .rm, .r64, .rm64, .none, .none, 1, 0x1b, 0x00, 0x00, 0, .long },
+ .{ .sbb, .zi, .al, .imm8, .none, .none, &.{ 0x1c }, 0, .none },
+ .{ .sbb, .zi, .ax, .imm16, .none, .none, &.{ 0x1d }, 0, .none },
+ .{ .sbb, .zi, .eax, .imm32, .none, .none, &.{ 0x1d }, 0, .none },
+ .{ .sbb, .zi, .rax, .imm32s, .none, .none, &.{ 0x1d }, 0, .long },
+ .{ .sbb, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 3, .none },
+ .{ .sbb, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 3, .rex },
+ .{ .sbb, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 3, .none },
+ .{ .sbb, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 3, .none },
+ .{ .sbb, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 3, .long },
+ .{ .sbb, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 3, .none },
+ .{ .sbb, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 3, .none },
+ .{ .sbb, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 3, .long },
+ .{ .sbb, .mr, .rm8, .r8, .none, .none, &.{ 0x18 }, 0, .none },
+ .{ .sbb, .mr, .rm8, .r8, .none, .none, &.{ 0x18 }, 0, .rex },
+ .{ .sbb, .mr, .rm16, .r16, .none, .none, &.{ 0x19 }, 0, .none },
+ .{ .sbb, .mr, .rm32, .r32, .none, .none, &.{ 0x19 }, 0, .none },
+ .{ .sbb, .mr, .rm64, .r64, .none, .none, &.{ 0x19 }, 0, .long },
+ .{ .sbb, .rm, .r8, .rm8, .none, .none, &.{ 0x1a }, 0, .none },
+ .{ .sbb, .rm, .r8, .rm8, .none, .none, &.{ 0x1a }, 0, .rex },
+ .{ .sbb, .rm, .r16, .rm16, .none, .none, &.{ 0x1b }, 0, .none },
+ .{ .sbb, .rm, .r32, .rm32, .none, .none, &.{ 0x1b }, 0, .none },
+ .{ .sbb, .rm, .r64, .rm64, .none, .none, &.{ 0x1b }, 0, .long },
- .{ .seta, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x97, 0x00, 0, .none },
- .{ .seta, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x97, 0x00, 0, .rex },
- .{ .setae, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x93, 0x00, 0, .none },
- .{ .setae, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x93, 0x00, 0, .rex },
- .{ .setb, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x92, 0x00, 0, .none },
- .{ .setb, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x92, 0x00, 0, .rex },
- .{ .setbe, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x96, 0x00, 0, .none },
- .{ .setbe, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x96, 0x00, 0, .rex },
- .{ .setc, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x92, 0x00, 0, .none },
- .{ .setc, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x92, 0x00, 0, .rex },
- .{ .sete, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x94, 0x00, 0, .none },
- .{ .sete, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x94, 0x00, 0, .rex },
- .{ .setg, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9f, 0x00, 0, .none },
- .{ .setg, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9f, 0x00, 0, .rex },
- .{ .setge, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9d, 0x00, 0, .none },
- .{ .setge, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9d, 0x00, 0, .rex },
- .{ .setl, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9c, 0x00, 0, .none },
- .{ .setl, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9c, 0x00, 0, .rex },
- .{ .setle, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9e, 0x00, 0, .none },
- .{ .setle, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9e, 0x00, 0, .rex },
- .{ .setna, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x96, 0x00, 0, .none },
- .{ .setna, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x96, 0x00, 0, .rex },
- .{ .setnae, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x92, 0x00, 0, .none },
- .{ .setnae, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x92, 0x00, 0, .rex },
- .{ .setnb, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x93, 0x00, 0, .none },
- .{ .setnb, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x93, 0x00, 0, .rex },
- .{ .setnbe, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x97, 0x00, 0, .none },
- .{ .setnbe, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x97, 0x00, 0, .rex },
- .{ .setnc, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x93, 0x00, 0, .none },
- .{ .setnc, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x93, 0x00, 0, .rex },
- .{ .setne, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x95, 0x00, 0, .none },
- .{ .setne, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x95, 0x00, 0, .rex },
- .{ .setng, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9e, 0x00, 0, .none },
- .{ .setng, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9e, 0x00, 0, .rex },
- .{ .setnge, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9c, 0x00, 0, .none },
- .{ .setnge, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9c, 0x00, 0, .rex },
- .{ .setnl, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9d, 0x00, 0, .none },
- .{ .setnl, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9d, 0x00, 0, .rex },
- .{ .setnle, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9f, 0x00, 0, .none },
- .{ .setnle, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9f, 0x00, 0, .rex },
- .{ .setno, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x91, 0x00, 0, .none },
- .{ .setno, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x91, 0x00, 0, .rex },
- .{ .setnp, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9b, 0x00, 0, .none },
- .{ .setnp, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9b, 0x00, 0, .rex },
- .{ .setns, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x99, 0x00, 0, .none },
- .{ .setns, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x99, 0x00, 0, .rex },
- .{ .setnz, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x95, 0x00, 0, .none },
- .{ .setnz, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x95, 0x00, 0, .rex },
- .{ .seto, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x90, 0x00, 0, .none },
- .{ .seto, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x90, 0x00, 0, .rex },
- .{ .setp, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9a, 0x00, 0, .none },
- .{ .setp, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9a, 0x00, 0, .rex },
- .{ .setpe, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9a, 0x00, 0, .none },
- .{ .setpe, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9a, 0x00, 0, .rex },
- .{ .setpo, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9b, 0x00, 0, .none },
- .{ .setpo, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x9b, 0x00, 0, .rex },
- .{ .sets, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x98, 0x00, 0, .none },
- .{ .sets, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x98, 0x00, 0, .rex },
- .{ .setz, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x94, 0x00, 0, .none },
- .{ .setz, .m, .rm8, .none, .none, .none, 2, 0x0f, 0x94, 0x00, 0, .rex },
+ .{ .seta, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .none },
+ .{ .seta, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .rex },
+ .{ .setae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .none },
+ .{ .setae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .rex },
+ .{ .setb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .none },
+ .{ .setb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .rex },
+ .{ .setbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .none },
+ .{ .setbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .rex },
+ .{ .setc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .none },
+ .{ .setc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .rex },
+ .{ .sete, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .none },
+ .{ .sete, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .rex },
+ .{ .setg, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .none },
+ .{ .setg, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .rex },
+ .{ .setge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .none },
+ .{ .setge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .rex },
+ .{ .setl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .none },
+ .{ .setl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .rex },
+ .{ .setle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .none },
+ .{ .setle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .rex },
+ .{ .setna, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .none },
+ .{ .setna, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x96 }, 0, .rex },
+ .{ .setnae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .none },
+ .{ .setnae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x92 }, 0, .rex },
+ .{ .setnb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .none },
+ .{ .setnb, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .rex },
+ .{ .setnbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .none },
+ .{ .setnbe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .rex },
+ .{ .setnc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .none },
+ .{ .setnc, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .rex },
+ .{ .setne, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .none },
+ .{ .setne, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .rex },
+ .{ .setng, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .none },
+ .{ .setng, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9e }, 0, .rex },
+ .{ .setnge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .none },
+ .{ .setnge, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9c }, 0, .rex },
+ .{ .setnl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .none },
+ .{ .setnl, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9d }, 0, .rex },
+ .{ .setnle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .none },
+ .{ .setnle, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9f }, 0, .rex },
+ .{ .setno, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x91 }, 0, .none },
+ .{ .setno, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x91 }, 0, .rex },
+ .{ .setnp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .none },
+ .{ .setnp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .rex },
+ .{ .setns, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x99 }, 0, .none },
+ .{ .setns, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x99 }, 0, .rex },
+ .{ .setnz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .none },
+ .{ .setnz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x95 }, 0, .rex },
+ .{ .seto, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x90 }, 0, .none },
+ .{ .seto, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x90 }, 0, .rex },
+ .{ .setp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .none },
+ .{ .setp, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .rex },
+ .{ .setpe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .none },
+ .{ .setpe, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9a }, 0, .rex },
+ .{ .setpo, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .none },
+ .{ .setpo, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x9b }, 0, .rex },
+ .{ .sets, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x98 }, 0, .none },
+ .{ .sets, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x98 }, 0, .rex },
+ .{ .setz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .none },
+ .{ .setz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .rex },
- .{ .shl, .m1, .rm8, .unity, .none, .none, 1, 0xd0, 0x00, 0x00, 4, .none },
- .{ .shl, .m1, .rm8, .unity, .none, .none, 1, 0xd0, 0x00, 0x00, 4, .rex },
- .{ .shl, .m1, .rm16, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 4, .none },
- .{ .shl, .m1, .rm32, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 4, .none },
- .{ .shl, .m1, .rm64, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 4, .long },
- .{ .shl, .mc, .rm8, .cl, .none, .none, 1, 0xd2, 0x00, 0x00, 4, .none },
- .{ .shl, .mc, .rm8, .cl, .none, .none, 1, 0xd2, 0x00, 0x00, 4, .rex },
- .{ .shl, .mc, .rm16, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 4, .none },
- .{ .shl, .mc, .rm32, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 4, .none },
- .{ .shl, .mc, .rm64, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 4, .long },
- .{ .shl, .mi, .rm8, .imm8, .none, .none, 1, 0xc0, 0x00, 0x00, 4, .none },
- .{ .shl, .mi, .rm8, .imm8, .none, .none, 1, 0xc0, 0x00, 0x00, 4, .rex },
- .{ .shl, .mi, .rm16, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 4, .none },
- .{ .shl, .mi, .rm32, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 4, .none },
- .{ .shl, .mi, .rm64, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 4, .long },
+ .{ .shl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none },
+ .{ .shl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex },
+ .{ .shl, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none },
+ .{ .shl, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 4, .none },
+ .{ .shl, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 4, .long },
+ .{ .shl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .none },
+ .{ .shl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 4, .rex },
+ .{ .shl, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 4, .none },
+ .{ .shl, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 4, .none },
+ .{ .shl, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 4, .long },
+ .{ .shl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .none },
+ .{ .shl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 4, .rex },
+ .{ .shl, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },
+ .{ .shl, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },
+ .{ .shl, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 4, .long },
- .{ .shr, .m1, .rm8, .unity, .none, .none, 1, 0xd0, 0x00, 0x00, 5, .none },
- .{ .shr, .m1, .rm8, .unity, .none, .none, 1, 0xd0, 0x00, 0x00, 5, .rex },
- .{ .shr, .m1, .rm16, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 5, .none },
- .{ .shr, .m1, .rm32, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 5, .none },
- .{ .shr, .m1, .rm64, .unity, .none, .none, 1, 0xd1, 0x00, 0x00, 5, .long },
- .{ .shr, .mc, .rm8, .cl, .none, .none, 1, 0xd2, 0x00, 0x00, 5, .none },
- .{ .shr, .mc, .rm8, .cl, .none, .none, 1, 0xd2, 0x00, 0x00, 5, .rex },
- .{ .shr, .mc, .rm16, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 5, .none },
- .{ .shr, .mc, .rm32, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 5, .none },
- .{ .shr, .mc, .rm64, .cl, .none, .none, 1, 0xd3, 0x00, 0x00, 5, .long },
- .{ .shr, .mi, .rm8, .imm8, .none, .none, 1, 0xc0, 0x00, 0x00, 5, .none },
- .{ .shr, .mi, .rm8, .imm8, .none, .none, 1, 0xc0, 0x00, 0x00, 5, .rex },
- .{ .shr, .mi, .rm16, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 5, .none },
- .{ .shr, .mi, .rm32, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 5, .none },
- .{ .shr, .mi, .rm64, .imm8, .none, .none, 1, 0xc1, 0x00, 0x00, 5, .long },
+ .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .none },
+ .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .rex },
+ .{ .shr, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 5, .none },
+ .{ .shr, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 5, .none },
+ .{ .shr, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 5, .long },
+ .{ .shr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 5, .none },
+ .{ .shr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 5, .rex },
+ .{ .shr, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 5, .none },
+ .{ .shr, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 5, .none },
+ .{ .shr, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 5, .long },
+ .{ .shr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 5, .none },
+ .{ .shr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 5, .rex },
+ .{ .shr, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 5, .none },
+ .{ .shr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 5, .none },
+ .{ .shr, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 5, .long },
- .{ .sub, .zi, .al, .imm8, .none, .none, 1, 0x2c, 0x00, 0x00, 0, .none },
- .{ .sub, .zi, .ax, .imm16, .none, .none, 1, 0x2d, 0x00, 0x00, 0, .none },
- .{ .sub, .zi, .eax, .imm32, .none, .none, 1, 0x2d, 0x00, 0x00, 0, .none },
- .{ .sub, .zi, .rax, .imm32s, .none, .none, 1, 0x2d, 0x00, 0x00, 0, .long },
- .{ .sub, .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 5, .none },
- .{ .sub, .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 5, .rex },
- .{ .sub, .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 5, .none },
- .{ .sub, .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 5, .none },
- .{ .sub, .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 5, .long },
- .{ .sub, .mi, .rm16, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 5, .none },
- .{ .sub, .mi, .rm32, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 5, .none },
- .{ .sub, .mi, .rm64, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 5, .long },
- .{ .sub, .mr, .rm8, .r8, .none, .none, 1, 0x28, 0x00, 0x00, 0, .none },
- .{ .sub, .mr, .rm8, .r8, .none, .none, 1, 0x28, 0x00, 0x00, 0, .rex },
- .{ .sub, .mr, .rm16, .r16, .none, .none, 1, 0x29, 0x00, 0x00, 0, .none },
- .{ .sub, .mr, .rm32, .r32, .none, .none, 1, 0x29, 0x00, 0x00, 0, .none },
- .{ .sub, .mr, .rm64, .r64, .none, .none, 1, 0x29, 0x00, 0x00, 0, .long },
- .{ .sub, .rm, .r8, .rm8, .none, .none, 1, 0x2a, 0x00, 0x00, 0, .none },
- .{ .sub, .rm, .r8, .rm8, .none, .none, 1, 0x2a, 0x00, 0x00, 0, .rex },
- .{ .sub, .rm, .r16, .rm16, .none, .none, 1, 0x2b, 0x00, 0x00, 0, .none },
- .{ .sub, .rm, .r32, .rm32, .none, .none, 1, 0x2b, 0x00, 0x00, 0, .none },
- .{ .sub, .rm, .r64, .rm64, .none, .none, 1, 0x2b, 0x00, 0x00, 0, .long },
+ .{ .sub, .zi, .al, .imm8, .none, .none, &.{ 0x2c }, 0, .none },
+ .{ .sub, .zi, .ax, .imm16, .none, .none, &.{ 0x2d }, 0, .none },
+ .{ .sub, .zi, .eax, .imm32, .none, .none, &.{ 0x2d }, 0, .none },
+ .{ .sub, .zi, .rax, .imm32s, .none, .none, &.{ 0x2d }, 0, .long },
+ .{ .sub, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 5, .none },
+ .{ .sub, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 5, .rex },
+ .{ .sub, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 5, .none },
+ .{ .sub, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 5, .none },
+ .{ .sub, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 5, .long },
+ .{ .sub, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 5, .none },
+ .{ .sub, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 5, .none },
+ .{ .sub, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 5, .long },
+ .{ .sub, .mr, .rm8, .r8, .none, .none, &.{ 0x28 }, 0, .none },
+ .{ .sub, .mr, .rm8, .r8, .none, .none, &.{ 0x28 }, 0, .rex },
+ .{ .sub, .mr, .rm16, .r16, .none, .none, &.{ 0x29 }, 0, .none },
+ .{ .sub, .mr, .rm32, .r32, .none, .none, &.{ 0x29 }, 0, .none },
+ .{ .sub, .mr, .rm64, .r64, .none, .none, &.{ 0x29 }, 0, .long },
+ .{ .sub, .rm, .r8, .rm8, .none, .none, &.{ 0x2a }, 0, .none },
+ .{ .sub, .rm, .r8, .rm8, .none, .none, &.{ 0x2a }, 0, .rex },
+ .{ .sub, .rm, .r16, .rm16, .none, .none, &.{ 0x2b }, 0, .none },
+ .{ .sub, .rm, .r32, .rm32, .none, .none, &.{ 0x2b }, 0, .none },
+ .{ .sub, .rm, .r64, .rm64, .none, .none, &.{ 0x2b }, 0, .long },
- .{ .syscall, .np, .none, .none, .none, .none, 2, 0x0f, 0x05, 0x00, 0, .none },
+ .{ .syscall, .np, .none, .none, .none, .none, &.{ 0x0f, 0x05 }, 0, .none },
- .{ .@"test", .zi, .al, .imm8, .none, .none, 1, 0xa8, 0x00, 0x00, 0, .none },
- .{ .@"test", .zi, .ax, .imm16, .none, .none, 1, 0xa9, 0x00, 0x00, 0, .none },
- .{ .@"test", .zi, .eax, .imm32, .none, .none, 1, 0xa9, 0x00, 0x00, 0, .none },
- .{ .@"test", .zi, .rax, .imm32s, .none, .none, 1, 0xa9, 0x00, 0x00, 0, .long },
- .{ .@"test", .mi, .rm8, .imm8, .none, .none, 1, 0xf6, 0x00, 0x00, 0, .none },
- .{ .@"test", .mi, .rm8, .imm8, .none, .none, 1, 0xf6, 0x00, 0x00, 0, .rex },
- .{ .@"test", .mi, .rm16, .imm16, .none, .none, 1, 0xf7, 0x00, 0x00, 0, .none },
- .{ .@"test", .mi, .rm32, .imm32, .none, .none, 1, 0xf7, 0x00, 0x00, 0, .none },
- .{ .@"test", .mi, .rm64, .imm32s, .none, .none, 1, 0xf7, 0x00, 0x00, 0, .long },
- .{ .@"test", .mr, .rm8, .r8, .none, .none, 1, 0x84, 0x00, 0x00, 0, .none },
- .{ .@"test", .mr, .rm8, .r8, .none, .none, 1, 0x84, 0x00, 0x00, 0, .rex },
- .{ .@"test", .mr, .rm16, .r16, .none, .none, 1, 0x85, 0x00, 0x00, 0, .none },
- .{ .@"test", .mr, .rm32, .r32, .none, .none, 1, 0x85, 0x00, 0x00, 0, .none },
- .{ .@"test", .mr, .rm64, .r64, .none, .none, 1, 0x85, 0x00, 0x00, 0, .long },
+ .{ .@"test", .zi, .al, .imm8, .none, .none, &.{ 0xa8 }, 0, .none },
+ .{ .@"test", .zi, .ax, .imm16, .none, .none, &.{ 0xa9 }, 0, .none },
+ .{ .@"test", .zi, .eax, .imm32, .none, .none, &.{ 0xa9 }, 0, .none },
+ .{ .@"test", .zi, .rax, .imm32s, .none, .none, &.{ 0xa9 }, 0, .long },
+ .{ .@"test", .mi, .rm8, .imm8, .none, .none, &.{ 0xf6 }, 0, .none },
+ .{ .@"test", .mi, .rm8, .imm8, .none, .none, &.{ 0xf6 }, 0, .rex },
+ .{ .@"test", .mi, .rm16, .imm16, .none, .none, &.{ 0xf7 }, 0, .none },
+ .{ .@"test", .mi, .rm32, .imm32, .none, .none, &.{ 0xf7 }, 0, .none },
+ .{ .@"test", .mi, .rm64, .imm32s, .none, .none, &.{ 0xf7 }, 0, .long },
+ .{ .@"test", .mr, .rm8, .r8, .none, .none, &.{ 0x84 }, 0, .none },
+ .{ .@"test", .mr, .rm8, .r8, .none, .none, &.{ 0x84 }, 0, .rex },
+ .{ .@"test", .mr, .rm16, .r16, .none, .none, &.{ 0x85 }, 0, .none },
+ .{ .@"test", .mr, .rm32, .r32, .none, .none, &.{ 0x85 }, 0, .none },
+ .{ .@"test", .mr, .rm64, .r64, .none, .none, &.{ 0x85 }, 0, .long },
- .{ .ud2, .np, .none, .none, .none, .none, 2, 0x0f, 0x0b, 0x00, 0, .none },
+ .{ .ud2, .np, .none, .none, .none, .none, &.{ 0x0f, 0x0b }, 0, .none },
- .{ .xor, .zi, .al, .imm8, .none, .none, 1, 0x34, 0x00, 0x00, 0, .none },
- .{ .xor, .zi, .ax, .imm16, .none, .none, 1, 0x35, 0x00, 0x00, 0, .none },
- .{ .xor, .zi, .eax, .imm32, .none, .none, 1, 0x35, 0x00, 0x00, 0, .none },
- .{ .xor, .zi, .rax, .imm32s, .none, .none, 1, 0x35, 0x00, 0x00, 0, .long },
- .{ .xor, .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 6, .none },
- .{ .xor, .mi, .rm8, .imm8, .none, .none, 1, 0x80, 0x00, 0x00, 6, .rex },
- .{ .xor, .mi, .rm16, .imm16, .none, .none, 1, 0x81, 0x00, 0x00, 6, .none },
- .{ .xor, .mi, .rm32, .imm32, .none, .none, 1, 0x81, 0x00, 0x00, 6, .none },
- .{ .xor, .mi, .rm64, .imm32s, .none, .none, 1, 0x81, 0x00, 0x00, 6, .long },
- .{ .xor, .mi, .rm16, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 6, .none },
- .{ .xor, .mi, .rm32, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 6, .none },
- .{ .xor, .mi, .rm64, .imm8s, .none, .none, 1, 0x83, 0x00, 0x00, 6, .long },
- .{ .xor, .mr, .rm8, .r8, .none, .none, 1, 0x30, 0x00, 0x00, 0, .none },
- .{ .xor, .mr, .rm8, .r8, .none, .none, 1, 0x30, 0x00, 0x00, 0, .rex },
- .{ .xor, .mr, .rm16, .r16, .none, .none, 1, 0x31, 0x00, 0x00, 0, .none },
- .{ .xor, .mr, .rm32, .r32, .none, .none, 1, 0x31, 0x00, 0x00, 0, .none },
- .{ .xor, .mr, .rm64, .r64, .none, .none, 1, 0x31, 0x00, 0x00, 0, .long },
- .{ .xor, .rm, .r8, .rm8, .none, .none, 1, 0x32, 0x00, 0x00, 0, .none },
- .{ .xor, .rm, .r8, .rm8, .none, .none, 1, 0x32, 0x00, 0x00, 0, .rex },
- .{ .xor, .rm, .r16, .rm16, .none, .none, 1, 0x33, 0x00, 0x00, 0, .none },
- .{ .xor, .rm, .r32, .rm32, .none, .none, 1, 0x33, 0x00, 0x00, 0, .none },
- .{ .xor, .rm, .r64, .rm64, .none, .none, 1, 0x33, 0x00, 0x00, 0, .long },
+ .{ .xor, .zi, .al, .imm8, .none, .none, &.{ 0x34 }, 0, .none },
+ .{ .xor, .zi, .ax, .imm16, .none, .none, &.{ 0x35 }, 0, .none },
+ .{ .xor, .zi, .eax, .imm32, .none, .none, &.{ 0x35 }, 0, .none },
+ .{ .xor, .zi, .rax, .imm32s, .none, .none, &.{ 0x35 }, 0, .long },
+ .{ .xor, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 6, .none },
+ .{ .xor, .mi, .rm8, .imm8, .none, .none, &.{ 0x80 }, 6, .rex },
+ .{ .xor, .mi, .rm16, .imm16, .none, .none, &.{ 0x81 }, 6, .none },
+ .{ .xor, .mi, .rm32, .imm32, .none, .none, &.{ 0x81 }, 6, .none },
+ .{ .xor, .mi, .rm64, .imm32s, .none, .none, &.{ 0x81 }, 6, .long },
+ .{ .xor, .mi, .rm16, .imm8s, .none, .none, &.{ 0x83 }, 6, .none },
+ .{ .xor, .mi, .rm32, .imm8s, .none, .none, &.{ 0x83 }, 6, .none },
+ .{ .xor, .mi, .rm64, .imm8s, .none, .none, &.{ 0x83 }, 6, .long },
+ .{ .xor, .mr, .rm8, .r8, .none, .none, &.{ 0x30 }, 0, .none },
+ .{ .xor, .mr, .rm8, .r8, .none, .none, &.{ 0x30 }, 0, .rex },
+ .{ .xor, .mr, .rm16, .r16, .none, .none, &.{ 0x31 }, 0, .none },
+ .{ .xor, .mr, .rm32, .r32, .none, .none, &.{ 0x31 }, 0, .none },
+ .{ .xor, .mr, .rm64, .r64, .none, .none, &.{ 0x31 }, 0, .long },
+ .{ .xor, .rm, .r8, .rm8, .none, .none, &.{ 0x32 }, 0, .none },
+ .{ .xor, .rm, .r8, .rm8, .none, .none, &.{ 0x32 }, 0, .rex },
+ .{ .xor, .rm, .r16, .rm16, .none, .none, &.{ 0x33 }, 0, .none },
+ .{ .xor, .rm, .r32, .rm32, .none, .none, &.{ 0x33 }, 0, .none },
+ .{ .xor, .rm, .r64, .rm64, .none, .none, &.{ 0x33 }, 0, .long },
// SSE
- .{ .addss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x58, 0, .sse },
+ .{ .addss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x58 }, 0, .sse },
- .{ .cmpss, .rmi, .xmm, .xmm_m32, .imm8, .none, 3, 0xf3, 0x0f, 0xc2, 0, .sse },
+ .{ .cmpss, .rmi, .xmm, .xmm_m32, .imm8, .none, &.{ 0xf3, 0x0f, 0xc2 }, 0, .sse },
- .{ .divss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5e, 0, .sse },
+ .{ .divss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse },
- .{ .maxss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5f, 0, .sse },
+ .{ .maxss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse },
- .{ .minss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5d, 0, .sse },
+ .{ .minss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5d }, 0, .sse },
- .{ .movss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x10, 0, .sse },
- .{ .movss, .mr, .xmm_m32, .xmm, .none, .none, 3, 0xf3, 0x0f, 0x11, 0, .sse },
+ .{ .movss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x10 }, 0, .sse },
+ .{ .movss, .mr, .xmm_m32, .xmm, .none, .none, &.{ 0xf3, 0x0f, 0x11 }, 0, .sse },
- .{ .mulss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x59, 0, .sse },
+ .{ .mulss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x59 }, 0, .sse },
- .{ .subss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5c, 0, .sse },
+ .{ .subss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0xf3, 0x0f, 0x5c }, 0, .sse },
- .{ .ucomiss, .rm, .xmm, .xmm_m32, .none, .none, 2, 0x0f, 0x2e, 0x00, 0, .sse },
+ .{ .ucomiss, .rm, .xmm, .xmm_m32, .none, .none, &.{ 0x0f, 0x2e }, 0, .sse },
// SSE2
- .{ .addsd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf2, 0x0f, 0x58, 0, .sse2 },
+ .{ .addsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x58 }, 0, .sse2 },
- .{ .cmpsd, .rmi, .xmm, .xmm_m64, .imm8, .none, 3, 0xf2, 0x0f, 0xc2, 0, .sse2 },
+ .{ .cmpsd, .rmi, .xmm, .xmm_m64, .imm8, .none, &.{ 0xf2, 0x0f, 0xc2 }, 0, .sse2 },
- .{ .divsd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf2, 0x0f, 0x5e, 0, .sse2 },
+ .{ .divsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 },
- .{ .maxsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x5f, 0, .sse2 },
+ .{ .maxsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 },
- .{ .minsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x5d, 0, .sse2 },
+ .{ .minsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5d }, 0, .sse2 },
- .{ .movq, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf3, 0x0f, 0x7e, 0, .sse2 },
- .{ .movq, .mr, .xmm_m64, .xmm, .none, .none, 3, 0x66, 0x0f, 0xd6, 0, .sse2 },
+ .{ .movq, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 },
+ .{ .movq, .mr, .xmm_m64, .xmm, .none, .none, &.{ 0x66, 0x0f, 0xd6 }, 0, .sse2 },
- .{ .mulsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x59, 0, .sse2 },
+ .{ .mulsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x59 }, 0, .sse2 },
- .{ .subsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x5c, 0, .sse2 },
+ .{ .subsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x5c }, 0, .sse2 },
- .{ .movsd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf2, 0x0f, 0x10, 0, .sse2 },
- .{ .movsd, .mr, .xmm_m64, .xmm, .none, .none, 3, 0xf2, 0x0f, 0x11, 0, .sse2 },
+ .{ .movsd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0xf2, 0x0f, 0x10 }, 0, .sse2 },
+ .{ .movsd, .mr, .xmm_m64, .xmm, .none, .none, &.{ 0xf2, 0x0f, 0x11 }, 0, .sse2 },
- .{ .ucomisd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0x66, 0x0f, 0x2e, 0, .sse2 },
+ .{ .ucomisd, .rm, .xmm, .xmm_m64, .none, .none, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 },
+
+ // SSE4.1
+ .{ .roundss, .rmi, .xmm, .xmm_m32, .imm8, .none, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 },
+ .{ .roundsd, .rmi, .xmm, .xmm_m64, .imm8, .none, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 },
};
// zig fmt: on
-
From edd63f9abaa7dae1786a4cd91cc3031264bd3ef0 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 18 Mar 2023 05:49:20 -0400
Subject: [PATCH 051/216] x86_64: reimplement inline memcpy and memset
---
src/arch/x86_64/CodeGen.zig | 225 +++++++++++++---------------------
src/arch/x86_64/Emit.zig | 50 +++++---
src/arch/x86_64/Encoding.zig | 48 ++++----
src/arch/x86_64/Mir.zig | 43 +++++++
src/arch/x86_64/bits.zig | 3 +
src/arch/x86_64/encoder.zig | 71 +++++------
src/arch/x86_64/encodings.zig | 45 +++++++
7 files changed, 270 insertions(+), 215 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 04e8a7ebe3..7271f8f7f6 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -1286,7 +1286,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {
}
}
-pub fn spillRegisters(self: *Self, comptime count: comptime_int, registers: [count]Register) !void {
+pub fn spillRegisters(self: *Self, registers: []const Register) !void {
for (registers) |reg| {
try self.register_manager.getReg(reg, null);
}
@@ -1540,7 +1540,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
break :result try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
}
- try self.spillRegisters(2, .{ .rax, .rdx });
+ try self.spillRegisters(&.{ .rax, .rdx });
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
@@ -1594,7 +1594,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
try self.spillEflagsIfOccupied();
if (tag == .shl_with_overflow) {
- try self.spillRegisters(1, .{.rcx});
+ try self.spillRegisters(&.{.rcx});
}
const partial: MCValue = switch (tag) {
@@ -1721,7 +1721,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
try self.spillEflagsIfOccupied();
self.eflags_inst = inst;
- try self.spillRegisters(2, .{ .rax, .rdx });
+ try self.spillRegisters(&.{ .rax, .rdx });
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
@@ -1774,7 +1774,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
break :dst_reg dst_reg;
},
.unsigned => {
- try self.spillRegisters(2, .{ .rax, .rdx });
+ try self.spillRegisters(&.{ .rax, .rdx });
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
@@ -1888,7 +1888,7 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
}
- try self.spillRegisters(1, .{.rcx});
+ try self.spillRegisters(&.{.rcx});
const tag = self.air.instructions.items(.tag)[inst];
const lhs = try self.resolveInst(bin_op.lhs);
@@ -2832,6 +2832,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
.unreach => unreachable,
.eflags => unreachable,
.undef => {
+ if (!self.wantSafety()) return; // The already existing value will do just fine.
switch (abi_size) {
1 => try self.store(ptr, .{ .immediate = 0xaa }, ptr_ty, value_ty),
2 => try self.store(ptr, .{ .immediate = 0xaaaa }, ptr_ty, value_ty),
@@ -4035,11 +4036,40 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
defer info.deinit(self);
try self.spillEflagsIfOccupied();
+ try self.spillRegisters(abi.getCallerPreservedRegs(self.target.*));
- for (abi.getCallerPreservedRegs(self.target.*)) |reg| {
- try self.register_manager.getReg(reg, null);
+ // set stack arguments first because this can clobber registers
+ // also clobber spill arguments as we go
+ if (info.return_value == .stack_offset) {
+ try self.spillRegisters(&.{abi.getCAbiIntParamRegs(self.target.*)[0]});
+ }
+ for (args, info.args) |arg, mc_arg| {
+ const arg_ty = self.air.typeOf(arg);
+ const arg_mcv = try self.resolveInst(arg);
+ // Here we do not use setRegOrMem even though the logic is similar, because
+ // the function call will move the stack pointer, so the offsets are different.
+ switch (mc_arg) {
+ .none => {},
+ .register => |reg| try self.spillRegisters(&.{reg}),
+ .stack_offset => |off| {
+ // TODO rewrite using `genSetStack`
+ try self.genSetStackArg(arg_ty, off, arg_mcv);
+ },
+ .ptr_stack_offset => {
+ return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
+ },
+ .undef => unreachable,
+ .immediate => unreachable,
+ .unreach => unreachable,
+ .dead => unreachable,
+ .memory => unreachable,
+ .linker_load => unreachable,
+ .eflags => unreachable,
+ .register_overflow => unreachable,
+ }
}
+ // now we are free to set register arguments
const ret_reg_lock: ?RegisterLock = blk: {
if (info.return_value == .stack_offset) {
const ret_ty = fn_ty.fnReturnType();
@@ -4049,7 +4079,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
log.debug("airCall: return value on stack at offset {}", .{stack_offset});
const ret_reg = abi.getCAbiIntParamRegs(self.target.*)[0];
- try self.register_manager.getReg(ret_reg, null);
try self.genSetReg(Type.usize, ret_reg, .{ .ptr_stack_offset = stack_offset });
const ret_reg_lock = self.register_manager.lockRegAssumeUnused(ret_reg);
@@ -4061,25 +4090,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
};
defer if (ret_reg_lock) |lock| self.register_manager.unlockReg(lock);
- for (args, info.args) |arg, info_arg| {
- const mc_arg = info_arg;
+ for (args, info.args) |arg, mc_arg| {
const arg_ty = self.air.typeOf(arg);
const arg_mcv = try self.resolveInst(arg);
- // Here we do not use setRegOrMem even though the logic is similar, because
- // the function call will move the stack pointer, so the offsets are different.
switch (mc_arg) {
- .none => continue,
- .register => |reg| {
- try self.register_manager.getReg(reg, null);
- try self.genSetReg(arg_ty, reg, arg_mcv);
- },
- .stack_offset => |off| {
- // TODO rewrite using `genSetStack`
- try self.genSetStackArg(arg_ty, off, arg_mcv);
- },
- .ptr_stack_offset => {
- return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
- },
+ .none, .stack_offset, .ptr_stack_offset => {},
+ .register => |reg| try self.genSetReg(arg_ty, reg, arg_mcv),
.undef => unreachable,
.immediate => unreachable,
.unreach => unreachable,
@@ -5277,6 +5293,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
.dead => unreachable,
.unreach, .none => return,
.undef => {
+ if (!self.wantSafety()) return; // The already existing value will do just fine.
if (abi_size <= 8) {
const reg = try self.copyToTmpRegister(ty, mcv);
return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
@@ -5384,8 +5401,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
.dead => unreachable,
.unreach, .none => return, // Nothing to do.
.undef => {
- if (!self.wantSafety())
- return; // The already existing value will do just fine.
+ if (!self.wantSafety()) return; // The already existing value will do just fine.
// TODO Upgrade this to a memset call when we have that available.
switch (abi_size) {
1, 2, 4 => {
@@ -5607,19 +5623,14 @@ fn genInlineMemcpy(
null;
defer if (dsbase_lock) |lock| self.register_manager.unlockReg(lock);
- const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp);
- const dst_addr_reg = regs[0];
- const src_addr_reg = regs[1];
- const index_reg = regs[2].to64();
- const count_reg = regs[3].to64();
- const tmp_reg = regs[4].to8();
+ try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
switch (dst_ptr) {
.memory, .linker_load => {
- try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_ptr);
+ try self.loadMemPtrIntoRegister(.rdi, Type.usize, dst_ptr);
},
.ptr_stack_offset, .stack_offset => |off| {
- try self.asmRegisterMemory(.lea, dst_addr_reg.to64(), Memory.sib(.qword, .{
+ try self.asmRegisterMemory(.lea, .rdi, Memory.sib(.qword, .{
.base = opts.dest_stack_base orelse .rbp,
.disp = -off,
}));
@@ -5627,7 +5638,7 @@ fn genInlineMemcpy(
.register => |reg| {
try self.asmRegisterRegister(
.mov,
- registerAlias(dst_addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
+ registerAlias(.rdi, @intCast(u32, @divExact(reg.bitSize(), 8))),
reg,
);
},
@@ -5638,10 +5649,10 @@ fn genInlineMemcpy(
switch (src_ptr) {
.memory, .linker_load => {
- try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_ptr);
+ try self.loadMemPtrIntoRegister(.rsi, Type.usize, src_ptr);
},
.ptr_stack_offset, .stack_offset => |off| {
- try self.asmRegisterMemory(.lea, src_addr_reg.to64(), Memory.sib(.qword, .{
+ try self.asmRegisterMemory(.lea, .rsi, Memory.sib(.qword, .{
.base = opts.source_stack_base orelse .rbp,
.disp = -off,
}));
@@ -5649,7 +5660,7 @@ fn genInlineMemcpy(
.register => |reg| {
try self.asmRegisterRegister(
.mov,
- registerAlias(src_addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
+ registerAlias(.rsi, @intCast(u32, @divExact(reg.bitSize(), 8))),
reg,
);
},
@@ -5658,37 +5669,12 @@ fn genInlineMemcpy(
},
}
- try self.genSetReg(Type.usize, count_reg, len);
- try self.asmRegisterImmediate(.mov, index_reg, Immediate.u(0));
- const loop_start = try self.addInst(.{
- .tag = .cmp,
- .ops = .ri_u,
- .data = .{ .ri = .{
- .r1 = count_reg,
- .imm = 0,
- } },
+ try self.genSetReg(Type.usize, .rcx, len);
+ _ = try self.addInst(.{
+ .tag = .movs,
+ .ops = .string,
+ .data = .{ .string = .{ .repeat = .rep, .width = .b } },
});
- const loop_reloc = try self.asmJccReloc(undefined, .e);
- try self.asmRegisterMemory(.mov, tmp_reg.to8(), Memory.sib(.byte, .{
- .base = src_addr_reg,
- .scale_index = .{
- .scale = 1,
- .index = index_reg,
- },
- .disp = 0,
- }));
- try self.asmMemoryRegister(.mov, Memory.sib(.byte, .{
- .base = dst_addr_reg,
- .scale_index = .{
- .scale = 1,
- .index = index_reg,
- },
- .disp = 0,
- }), tmp_reg.to8());
- try self.asmRegisterImmediate(.add, index_reg, Immediate.u(1));
- try self.asmRegisterImmediate(.sub, count_reg, Immediate.u(1));
- _ = try self.asmJmpReloc(loop_start);
- try self.performReloc(loop_reloc);
}
fn genInlineMemset(
@@ -5698,28 +5684,20 @@ fn genInlineMemset(
len: MCValue,
opts: InlineMemcpyOpts,
) InnerError!void {
- const ssbase_lock: ?RegisterLock = if (opts.source_stack_base) |reg|
- self.register_manager.lockReg(reg)
- else
- null;
- defer if (ssbase_lock) |reg| self.register_manager.unlockReg(reg);
-
const dsbase_lock: ?RegisterLock = if (opts.dest_stack_base) |reg|
self.register_manager.lockReg(reg)
else
null;
defer if (dsbase_lock) |lock| self.register_manager.unlockReg(lock);
- const regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
- const addr_reg = regs[0];
- const index_reg = regs[1].to64();
+ try self.spillRegisters(&.{ .rdi, .al, .rcx });
switch (dst_ptr) {
.memory, .linker_load => {
- try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_ptr);
+ try self.loadMemPtrIntoRegister(.rdi, Type.usize, dst_ptr);
},
.ptr_stack_offset, .stack_offset => |off| {
- try self.asmRegisterMemory(.lea, addr_reg.to64(), Memory.sib(.qword, .{
+ try self.asmRegisterMemory(.lea, .rdi, Memory.sib(.qword, .{
.base = opts.dest_stack_base orelse .rbp,
.disp = -off,
}));
@@ -5727,48 +5705,22 @@ fn genInlineMemset(
.register => |reg| {
try self.asmRegisterRegister(
.mov,
- registerAlias(addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
+ registerAlias(.rdi, @intCast(u32, @divExact(reg.bitSize(), 8))),
reg,
);
},
else => {
- return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr});
+ return self.fail("TODO implement memset for setting stack when dest is {}", .{dst_ptr});
},
}
- try self.genSetReg(Type.usize, index_reg, len);
- try self.genBinOpMir(.sub, Type.usize, .{ .register = index_reg }, .{ .immediate = 1 });
-
- const loop_start = try self.addInst(.{
- .tag = .cmp,
- .ops = .ri_s,
- .data = .{ .ri = .{
- .r1 = index_reg,
- .imm = @bitCast(u32, @as(i32, -1)),
- } },
+ try self.genSetReg(Type.u8, .al, value);
+ try self.genSetReg(Type.usize, .rcx, len);
+ _ = try self.addInst(.{
+ .tag = .stos,
+ .ops = .string,
+ .data = .{ .string = .{ .repeat = .rep, .width = .b } },
});
- const loop_reloc = try self.asmJccReloc(undefined, .e);
-
- switch (value) {
- .immediate => |x| {
- if (x > math.maxInt(i32)) {
- return self.fail("TODO inline memset for value immediate larger than 32bits", .{});
- }
- try self.asmMemoryImmediate(.mov, Memory.sib(.byte, .{
- .base = addr_reg,
- .scale_index = .{
- .scale = 1,
- .index = index_reg,
- },
- .disp = 0,
- }), Immediate.u(@intCast(u8, x)));
- },
- else => return self.fail("TODO inline memset for value of type {}", .{value}),
- }
-
- try self.asmRegisterImmediate(.sub, index_reg, Immediate.u(1));
- _ = try self.asmJmpReloc(loop_start);
- try self.performReloc(loop_reloc);
}
fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
@@ -5788,8 +5740,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
},
.unreach, .none => return, // Nothing to do.
.undef => {
- if (!self.wantSafety())
- return; // The already existing value will do just fine.
+ if (!self.wantSafety()) return; // The already existing value will do just fine.
// Write the debug undefined value.
switch (registerAlias(reg, abi_size).bitSize()) {
8 => return self.genSetReg(ty, reg, .{ .immediate = 0xaa }),
@@ -5802,27 +5753,27 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
.eflags => |cc| {
return self.asmSetccRegister(reg.to8(), cc);
},
- .immediate => |x| {
- if (x == 0) {
+ .immediate => |imm| {
+ if (imm == 0) {
// 32-bit moves zero-extend to 64-bit, so xoring the 32-bit
// register is the fastest way to zero a register.
- return self.asmRegisterRegister(.xor, reg.to32(), reg.to32());
+ try self.asmRegisterRegister(.xor, reg.to32(), reg.to32());
+ } else if (abi_size > 4 and math.cast(u32, imm) != null) {
+ // 32-bit moves zero-extend to 64-bit.
+ try self.asmRegisterImmediate(.mov, reg.to32(), Immediate.u(imm));
+ } else if (abi_size <= 4 and @bitCast(i64, imm) < 0) {
+ try self.asmRegisterImmediate(
+ .mov,
+ registerAlias(reg, abi_size),
+ Immediate.s(@intCast(i32, @bitCast(i64, imm))),
+ );
+ } else {
+ try self.asmRegisterImmediate(
+ .mov,
+ registerAlias(reg, abi_size),
+ Immediate.u(imm),
+ );
}
- if (ty.isSignedInt()) {
- const signed_x = @bitCast(i64, x);
- if (math.minInt(i32) <= signed_x and signed_x <= math.maxInt(i32)) {
- return self.asmRegisterImmediate(
- .mov,
- registerAlias(reg, abi_size),
- Immediate.s(@intCast(i32, signed_x)),
- );
- }
- }
- return self.asmRegisterImmediate(
- .mov,
- registerAlias(reg, abi_size),
- Immediate.u(x),
- );
},
.register => |src_reg| {
// If the registers are the same, nothing to do.
@@ -6136,7 +6087,7 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {
_ = inst;
- return self.fail("TODO implement x86 airAtomicRaw", .{});
+ return self.fail("TODO implement x86 airAtomicRmw", .{});
}
fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void {
@@ -6177,7 +6128,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) !void {
try self.genInlineMemset(dst_ptr, src_val, len, .{});
- return self.finishAir(inst, .none, .{ pl_op.operand, .none, .none });
+ return self.finishAir(inst, .none, .{ pl_op.operand, extra.lhs, extra.rhs });
}
fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
@@ -6229,7 +6180,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
try self.genInlineMemcpy(dst_ptr, src, len, .{});
- return self.finishAir(inst, .none, .{ pl_op.operand, .none, .none });
+ return self.finishAir(inst, .none, .{ pl_op.operand, extra.lhs, extra.rhs });
}
fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index 95c5c41170..cf948f6023 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -130,6 +130,13 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.ucomisd,
=> try emit.mirEncodeGeneric(tag, inst),
+ .cmps,
+ .lods,
+ .movs,
+ .scas,
+ .stos,
+ => try emit.mirString(tag, inst),
+
.jmp_reloc => try emit.mirJmpReloc(inst),
.call_extern => try emit.mirCallExtern(inst),
@@ -183,18 +190,8 @@ fn fixupRelocs(emit: *Emit) InnerError!void {
}
}
-fn encode(emit: *Emit, mnemonic: Instruction.Mnemonic, ops: struct {
- op1: Instruction.Operand = .none,
- op2: Instruction.Operand = .none,
- op3: Instruction.Operand = .none,
- op4: Instruction.Operand = .none,
-}) InnerError!void {
- const inst = try Instruction.new(mnemonic, .{
- .op1 = ops.op1,
- .op2 = ops.op2,
- .op3 = ops.op3,
- .op4 = ops.op4,
- });
+fn encode(emit: *Emit, mnemonic: Instruction.Mnemonic, ops: Instruction.Init) InnerError!void {
+ const inst = try Instruction.new(mnemonic, ops);
return inst.encode(emit.code.writer());
}
@@ -318,6 +315,28 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
});
}
+fn mirString(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
+ const ops = emit.mir.instructions.items(.ops)[inst];
+ switch (ops) {
+ .string => {
+ const data = emit.mir.instructions.items(.data)[inst].string;
+ const mnemonic = switch (tag) {
+ inline .cmps, .lods, .movs, .scas, .stos => |comptime_tag| switch (data.width) {
+ inline else => |comptime_width| @field(
+ Instruction.Mnemonic,
+ @tagName(comptime_tag) ++ @tagName(comptime_width),
+ ),
+ },
+ else => unreachable,
+ };
+ return emit.encode(mnemonic, .{ .prefix = switch (data.repeat) {
+ inline else => |comptime_repeat| @field(Instruction.Prefix, @tagName(comptime_repeat)),
+ } });
+ },
+ else => unreachable,
+ }
+}
+
fn mirMovMoffs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
const ops = emit.mir.instructions.items(.ops)[inst];
const payload = emit.mir.instructions.items(.data)[inst].payload;
@@ -377,10 +396,9 @@ fn mirMovsx(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
}
fn mnemonicFromConditionCode(comptime basename: []const u8, cc: bits.Condition) Instruction.Mnemonic {
- inline for (@typeInfo(bits.Condition).Enum.fields) |field| {
- if (mem.eql(u8, field.name, @tagName(cc)))
- return @field(Instruction.Mnemonic, basename ++ field.name);
- } else unreachable;
+ return switch (cc) {
+ inline else => |comptime_cc| @field(Instruction.Mnemonic, basename ++ @tagName(comptime_cc)),
+ };
}
fn mirCmovcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig
index 275c001bd7..96396640d6 100644
--- a/src/arch/x86_64/Encoding.zig
+++ b/src/arch/x86_64/Encoding.zig
@@ -24,12 +24,7 @@ opc: [7]u8,
modrm_ext: u3,
mode: Mode,
-pub fn findByMnemonic(mnemonic: Mnemonic, args: struct {
- op1: Instruction.Operand,
- op2: Instruction.Operand,
- op3: Instruction.Operand,
- op4: Instruction.Operand,
-}) !?Encoding {
+pub fn findByMnemonic(mnemonic: Mnemonic, args: Instruction.Init) !?Encoding {
const input_op1 = Op.fromOperand(args.op1);
const input_op2 = Op.fromOperand(args.op2);
const input_op3 = Op.fromOperand(args.op3);
@@ -109,17 +104,13 @@ pub fn findByMnemonic(mnemonic: Mnemonic, args: struct {
if (count == 1) return candidates[0];
const EncodingLength = struct {
- fn estimate(encoding: Encoding, params: struct {
- op1: Instruction.Operand,
- op2: Instruction.Operand,
- op3: Instruction.Operand,
- op4: Instruction.Operand,
- }) usize {
+ fn estimate(encoding: Encoding, params: Instruction.Init) usize {
var inst = Instruction{
.op1 = params.op1,
.op2 = params.op2,
.op3 = params.op3,
.op4 = params.op4,
+ .prefix = params.prefix,
.encoding = encoding,
};
var cwriter = std.io.countingWriter(std.io.null_writer);
@@ -140,12 +131,7 @@ pub fn findByMnemonic(mnemonic: Mnemonic, args: struct {
else => {},
}
- const len = EncodingLength.estimate(candidate, .{
- .op1 = args.op1,
- .op2 = args.op2,
- .op3 = args.op3,
- .op4 = args.op4,
- });
+ const len = EncodingLength.estimate(candidate, args);
const current = shortest_encoding orelse {
shortest_encoding = .{ .index = i, .len = len };
continue;
@@ -228,7 +214,11 @@ pub fn modRmExt(encoding: Encoding) u3 {
}
pub fn operandBitSize(encoding: Encoding) u64 {
- if (encoding.mode == .long) return 64;
+ switch (encoding.mode) {
+ .short => return 16,
+ .long => return 64,
+ else => {},
+ }
const bit_size: u64 = switch (encoding.op_en) {
.np => switch (encoding.op1) {
.o16 => 16,
@@ -317,10 +307,13 @@ pub const Mnemonic = enum {
// zig fmt: off
// General-purpose
adc, add, @"and",
- call, cbw, cwde, cdqe, cwd, cdq, cqo, cmp,
+ call, cbw, cdq, cdqe,
cmova, cmovae, cmovb, cmovbe, cmovc, cmove, cmovg, cmovge, cmovl, cmovle, cmovna,
cmovnae, cmovnb, cmovnbe, cmovnc, cmovne, cmovng, cmovnge, cmovnl, cmovnle, cmovno,
cmovnp, cmovns, cmovnz, cmovo, cmovp, cmovpe, cmovpo, cmovs, cmovz,
+ cmp,
+ cmps, cmpsb, cmpsd, cmpsq, cmpsw,
+ cqo, cwd, cwde,
div,
fisttp, fld,
idiv, imul, int3,
@@ -328,15 +321,21 @@ pub const Mnemonic = enum {
jnc, jne, jng, jnge, jnl, jnle, jno, jnp, jns, jnz, jo, jp, jpe, jpo, js, jz,
jmp,
lea,
- mov, movsx, movsxd, movzx, mul,
+ lods, lodsb, lodsd, lodsq, lodsw,
+ mov,
+ movs, movsb, movsd, movsq, movsw,
+ movsx, movsxd, movzx, mul,
nop,
@"or",
pop, push,
ret,
- sal, sar, sbb, shl, shr, sub, syscall,
+ sal, sar, sbb,
+ scas, scasb, scasd, scasq, scasw,
+ shl, shr, sub, syscall,
seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,
setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,
setnz, seto, setp, setpe, setpo, sets, setz,
+ stos, stosb, stosd, stosq, stosw,
@"test",
ud2,
xor,
@@ -351,10 +350,10 @@ pub const Mnemonic = enum {
ucomiss,
// SSE2
addsd,
- cmpsd,
+ //cmpsd,
divsd,
maxsd, minsd,
- movq, movsd,
+ movq, //movsd,
mulsd,
subsd,
ucomisd,
@@ -591,6 +590,7 @@ pub const Op = enum {
pub const Mode = enum {
none,
+ short,
fpu,
rex,
long,
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index ed10bed9b6..2f2c424517 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -150,6 +150,17 @@ pub const Inst = struct {
/// Unordered compare scalar double-precision floating-point values
ucomisd,
+ /// Compare string operands
+ cmps,
+ /// Load string
+ lods,
+ /// Move data from string to string
+ movs,
+ /// Scan string
+ scas,
+ /// Store string
+ stos,
+
/// Conditional move
cmovcc,
/// Conditional jump
@@ -268,6 +279,30 @@ pub const Inst = struct {
/// Memory (RIP), register operands.
/// Uses `rx` payload with extra data of type `MemoryRip`.
mr_rip,
+ /// Single memory (SIB) operand with lock prefix.
+ /// Uses `payload` with extra data of type `MemorySib`.
+ lock_m_sib,
+ /// Single memory (RIP) operand with lock prefix.
+ /// Uses `payload` with extra data of type `MemoryRip`.
+ lock_m_rip,
+ /// Memory (SIB), immediate (unsigned) operands with lock prefix.
+ /// Uses `xi` payload with extra data of type `MemorySib`.
+ lock_mi_u_sib,
+ /// Memory (RIP), immediate (unsigned) operands with lock prefix.
+ /// Uses `xi` payload with extra data of type `MemoryRip`.
+ lock_mi_u_rip,
+ /// Memory (SIB), immediate (sign-extend) operands with lock prefix.
+ /// Uses `xi` payload with extra data of type `MemorySib`.
+ lock_mi_s_sib,
+ /// Memory (RIP), immediate (sign-extend) operands with lock prefix.
+ /// Uses `xi` payload with extra data of type `MemoryRip`.
+ lock_mi_s_rip,
+ /// Memory (SIB), register operands with lock prefix.
+ /// Uses `rx` payload with extra data of type `MemorySib`.
+ lock_mr_sib,
+ /// Memory (RIP), register operands with lock prefix.
+ /// Uses `rx` payload with extra data of type `MemoryRip`.
+ lock_mr_rip,
/// Rax, Memory moffs.
/// Uses `payload` with extra data of type `MemoryMoffs`.
rax_moffs,
@@ -280,6 +315,9 @@ pub const Inst = struct {
/// References another Mir instruction directly with condition code (CC).
/// Uses `inst_cc` payload.
inst_cc,
+ /// String repeat and width
+ /// Uses `string` payload.
+ string,
/// Uses `reloc` payload.
reloc,
/// Linker relocation - GOT indirection.
@@ -353,6 +391,11 @@ pub const Inst = struct {
payload: u32,
imm: u32,
},
+ /// String instruction prefix and width.
+ string: struct {
+ repeat: bits.StringRepeat,
+ width: bits.StringWidth,
+ },
/// Relocation for the linker where:
/// * `atom_index` is the index of the source
/// * `sym_index` is the index of the target
diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig
index 72d7b159cf..48a3c64093 100644
--- a/src/arch/x86_64/bits.zig
+++ b/src/arch/x86_64/bits.zig
@@ -6,6 +6,9 @@ const Allocator = std.mem.Allocator;
const ArrayList = std.ArrayList;
const DW = std.dwarf;
+pub const StringRepeat = enum(u3) { none, rep, repe, repz, repne, repnz };
+pub const StringWidth = enum(u2) { b, w, d, q };
+
/// EFLAGS condition codes
pub const Condition = enum(u5) {
/// above
diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig
index 7e29f95069..2a2d6ea031 100644
--- a/src/arch/x86_64/encoder.zig
+++ b/src/arch/x86_64/encoder.zig
@@ -15,10 +15,21 @@ pub const Instruction = struct {
op2: Operand = .none,
op3: Operand = .none,
op4: Operand = .none,
+ prefix: Prefix = .none,
encoding: Encoding,
pub const Mnemonic = Encoding.Mnemonic;
+ pub const Prefix = enum(u3) {
+ none,
+ lock,
+ rep,
+ repe,
+ repz,
+ repne,
+ repnz,
+ };
+
pub const Operand = union(enum) {
none,
reg: Register,
@@ -96,18 +107,16 @@ pub const Instruction = struct {
}
};
- pub fn new(mnemonic: Mnemonic, args: struct {
+ pub const Init = struct {
+ prefix: Prefix = .none,
op1: Operand = .none,
op2: Operand = .none,
op3: Operand = .none,
op4: Operand = .none,
- }) !Instruction {
- const encoding = (try Encoding.findByMnemonic(mnemonic, .{
- .op1 = args.op1,
- .op2 = args.op2,
- .op3 = args.op3,
- .op4 = args.op4,
- })) orelse {
+ };
+
+ pub fn new(mnemonic: Mnemonic, args: Init) !Instruction {
+ const encoding = (try Encoding.findByMnemonic(mnemonic, args)) orelse {
log.debug("no encoding found for: {s} {s} {s} {s} {s}", .{
@tagName(mnemonic),
@tagName(Encoding.Op.fromOperand(args.op1)),
@@ -119,6 +128,7 @@ pub const Instruction = struct {
};
log.debug("selected encoding: {}", .{encoding});
return .{
+ .prefix = args.prefix,
.op1 = args.op1,
.op2 = args.op2,
.op3 = args.op3,
@@ -128,6 +138,7 @@ pub const Instruction = struct {
}
pub fn fmtPrint(inst: Instruction, writer: anytype) !void {
+ if (inst.prefix != .none) try writer.print("{s} ", .{@tagName(inst.prefix)});
try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)});
const ops = [_]struct { Operand, Encoding.Op }{
.{ inst.op1, inst.encoding.op1 },
@@ -215,6 +226,14 @@ pub const Instruction = struct {
const op_en = enc.op_en;
var legacy = LegacyPrefixes{};
+
+ switch (inst.prefix) {
+ .none => {},
+ .lock => legacy.prefix_f0 = true,
+ .repne, .repnz => legacy.prefix_f2 = true,
+ .rep, .repe, .repz => legacy.prefix_f3 = true,
+ }
+
if (enc.mode == .none) {
const bit_size = enc.operandBitSize();
if (bit_size == 16) {
@@ -811,15 +830,11 @@ const TestEncode = struct {
buffer: [32]u8 = undefined,
index: usize = 0,
- fn encode(enc: *TestEncode, mnemonic: Instruction.Mnemonic, args: struct {
- op1: Instruction.Operand = .none,
- op2: Instruction.Operand = .none,
- op3: Instruction.Operand = .none,
- op4: Instruction.Operand = .none,
- }) !void {
+ fn encode(enc: *TestEncode, mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void {
var stream = std.io.fixedBufferStream(&enc.buffer);
var count_writer = std.io.countingWriter(stream.writer());
const inst = try Instruction.new(mnemonic, .{
+ .prefix = args.prefix,
.op1 = args.op1,
.op2 = args.op2,
.op3 = args.op3,
@@ -1447,18 +1462,8 @@ test "lower NP encoding" {
try expectEqualHexStrings("\x0f\x05", enc.code(), "syscall");
}
-fn invalidInstruction(mnemonic: Instruction.Mnemonic, args: struct {
- op1: Instruction.Operand = .none,
- op2: Instruction.Operand = .none,
- op3: Instruction.Operand = .none,
- op4: Instruction.Operand = .none,
-}) !void {
- const err = Instruction.new(mnemonic, .{
- .op1 = args.op1,
- .op2 = args.op2,
- .op3 = args.op3,
- .op4 = args.op4,
- });
+fn invalidInstruction(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void {
+ const err = Instruction.new(mnemonic, args);
try testing.expectError(error.InvalidInstruction, err);
}
@@ -1479,18 +1484,8 @@ test "invalid instruction" {
try invalidInstruction(.push, .{ .op1 = .{ .imm = Immediate.u(0x1000000000000000) } });
}
-fn cannotEncode(mnemonic: Instruction.Mnemonic, args: struct {
- op1: Instruction.Operand = .none,
- op2: Instruction.Operand = .none,
- op3: Instruction.Operand = .none,
- op4: Instruction.Operand = .none,
-}) !void {
- try testing.expectError(error.CannotEncode, Instruction.new(mnemonic, .{
- .op1 = args.op1,
- .op2 = args.op2,
- .op3 = args.op3,
- .op4 = args.op4,
- }));
+fn cannotEncode(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void {
+ try testing.expectError(error.CannotEncode, Instruction.new(mnemonic, args));
}
test "cannot encode" {
diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig
index 57b330b9ce..6f2334ba4a 100644
--- a/src/arch/x86_64/encodings.zig
+++ b/src/arch/x86_64/encodings.zig
@@ -207,6 +207,15 @@ pub const table = &[_]Entry{
.{ .cmp, .rm, .r32, .rm32, .none, .none, &.{ 0x3b }, 0, .none },
.{ .cmp, .rm, .r64, .rm64, .none, .none, &.{ 0x3b }, 0, .long },
+ .{ .cmps, .np, .m8, .m8, .none, .none, &.{ 0xa6 }, 0, .none },
+ .{ .cmps, .np, .m16, .m16, .none, .none, &.{ 0xa7 }, 0, .none },
+ .{ .cmps, .np, .m32, .m32, .none, .none, &.{ 0xa7 }, 0, .none },
+ .{ .cmps, .np, .m64, .m64, .none, .none, &.{ 0xa7 }, 0, .long },
+ .{ .cmpsb, .np, .none, .none, .none, .none, &.{ 0xa6 }, 0, .none },
+ .{ .cmpsw, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .short },
+ .{ .cmpsd, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .none },
+ .{ .cmpsq, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .long },
+
.{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .none },
.{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .rex },
.{ .div, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 6, .none },
@@ -283,6 +292,15 @@ pub const table = &[_]Entry{
.{ .lea, .rm, .r32, .m, .none, .none, &.{ 0x8d }, 0, .none },
.{ .lea, .rm, .r64, .m, .none, .none, &.{ 0x8d }, 0, .long },
+ .{ .lods, .np, .m8, .none, .none, .none, &.{ 0xac }, 0, .none },
+ .{ .lods, .np, .m16, .none, .none, .none, &.{ 0xad }, 0, .none },
+ .{ .lods, .np, .m32, .none, .none, .none, &.{ 0xad }, 0, .none },
+ .{ .lods, .np, .m64, .none, .none, .none, &.{ 0xad }, 0, .long },
+ .{ .lodsb, .np, .none, .none, .none, .none, &.{ 0xac }, 0, .none },
+ .{ .lodsw, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .short },
+ .{ .lodsd, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .none },
+ .{ .lodsq, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .long },
+
.{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .none },
.{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .rex },
.{ .mov, .mr, .rm16, .r16, .none, .none, &.{ 0x89 }, 0, .none },
@@ -316,6 +334,15 @@ pub const table = &[_]Entry{
.{ .mov, .mi, .rm32, .imm32, .none, .none, &.{ 0xc7 }, 0, .none },
.{ .mov, .mi, .rm64, .imm32s, .none, .none, &.{ 0xc7 }, 0, .long },
+ .{ .movs, .np, .m8, .m8, .none, .none, &.{ 0xa4 }, 0, .none },
+ .{ .movs, .np, .m16, .m16, .none, .none, &.{ 0xa5 }, 0, .none },
+ .{ .movs, .np, .m32, .m32, .none, .none, &.{ 0xa5 }, 0, .none },
+ .{ .movs, .np, .m64, .m64, .none, .none, &.{ 0xa5 }, 0, .long },
+ .{ .movsb, .np, .none, .none, .none, .none, &.{ 0xa4 }, 0, .none },
+ .{ .movsw, .np, .none, .none, .none, .none, &.{ 0xa5 }, 0, .short },
+ .{ .movsd, .np, .none, .none, .none, .none, &.{ 0xa5 }, 0, .none },
+ .{ .movsq, .np, .none, .none, .none, .none, &.{ 0xa5 }, 0, .long },
+
.{ .movsx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .none },
.{ .movsx, .rm, .r16, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .rex },
.{ .movsx, .rm, .r32, .rm8, .none, .none, &.{ 0x0f, 0xbe }, 0, .none },
@@ -435,6 +462,15 @@ pub const table = &[_]Entry{
.{ .sbb, .rm, .r32, .rm32, .none, .none, &.{ 0x1b }, 0, .none },
.{ .sbb, .rm, .r64, .rm64, .none, .none, &.{ 0x1b }, 0, .long },
+ .{ .scas, .np, .m8, .none, .none, .none, &.{ 0xae }, 0, .none },
+ .{ .scas, .np, .m16, .none, .none, .none, &.{ 0xaf }, 0, .none },
+ .{ .scas, .np, .m32, .none, .none, .none, &.{ 0xaf }, 0, .none },
+ .{ .scas, .np, .m64, .none, .none, .none, &.{ 0xaf }, 0, .long },
+ .{ .scasb, .np, .none, .none, .none, .none, &.{ 0xae }, 0, .none },
+ .{ .scasw, .np, .none, .none, .none, .none, &.{ 0xaf }, 0, .short },
+ .{ .scasd, .np, .none, .none, .none, .none, &.{ 0xaf }, 0, .none },
+ .{ .scasq, .np, .none, .none, .none, .none, &.{ 0xaf }, 0, .long },
+
.{ .seta, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .none },
.{ .seta, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x97 }, 0, .rex },
.{ .setae, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x93 }, 0, .none },
@@ -528,6 +564,15 @@ pub const table = &[_]Entry{
.{ .shr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 5, .none },
.{ .shr, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 5, .long },
+ .{ .stos, .np, .m8, .none, .none, .none, &.{ 0xaa }, 0, .none },
+ .{ .stos, .np, .m16, .none, .none, .none, &.{ 0xab }, 0, .none },
+ .{ .stos, .np, .m32, .none, .none, .none, &.{ 0xab }, 0, .none },
+ .{ .stos, .np, .m64, .none, .none, .none, &.{ 0xab }, 0, .long },
+ .{ .stosb, .np, .none, .none, .none, .none, &.{ 0xaa }, 0, .none },
+ .{ .stosw, .np, .none, .none, .none, .none, &.{ 0xab }, 0, .short },
+ .{ .stosd, .np, .none, .none, .none, .none, &.{ 0xab }, 0, .none },
+ .{ .stosq, .np, .none, .none, .none, .none, &.{ 0xab }, 0, .long },
+
.{ .sub, .zi, .al, .imm8, .none, .none, &.{ 0x2c }, 0, .none },
.{ .sub, .zi, .ax, .imm16, .none, .none, &.{ 0x2d }, 0, .none },
.{ .sub, .zi, .eax, .imm32, .none, .none, &.{ 0x2d }, 0, .none },
From 53ec2a955eb02dc829af8610f17af42717d512fb Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 18 Mar 2023 08:02:17 -0400
Subject: [PATCH 052/216] x86_64: implement clz, ctz, and popCount
---
src/arch/x86_64/CodeGen.zig | 141 ++++++++++++++++++++++++++++++----
src/arch/x86_64/Emit.zig | 5 ++
src/arch/x86_64/Encoding.zig | 6 +-
src/arch/x86_64/Mir.zig | 10 +++
src/arch/x86_64/encodings.zig | 24 +++++-
5 files changed, 169 insertions(+), 17 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 7271f8f7f6..317a50e0ec 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -2597,28 +2597,143 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
fn airClz(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement airClz for {}", .{self.target.cpu.arch});
+ const result = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const dst_ty = self.air.typeOfIndex(inst);
+ const src_ty = self.air.typeOf(ty_op.operand);
+ const src_bits = src_ty.bitSize(self.target.*);
+
+ const src_mcv = try self.resolveInst(ty_op.operand);
+ const mat_src_mcv = switch (src_mcv) {
+ .immediate => MCValue{ .register = try self.copyToTmpRegister(src_ty, src_mcv) },
+ else => src_mcv,
+ };
+ const mat_src_lock = switch (mat_src_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ else => null,
+ };
+ defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const dst_reg = try self.register_manager.allocReg(inst, gp);
+ const dst_mcv = MCValue{ .register = dst_reg };
+ const dst_lock = self.register_manager.lockReg(dst_reg);
+ defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
+
+ if (Target.x86.featureSetHas(self.target.cpu.features, .lzcnt)) {
+ try self.genBinOpMir(.lzcnt, src_ty, dst_mcv, mat_src_mcv);
+ const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
+ const extra_bits = registerAlias(dst_reg, src_abi_size).bitSize() - src_bits;
+ if (extra_bits > 0) {
+ try self.genBinOpMir(.sub, dst_ty, dst_mcv, .{ .immediate = extra_bits });
+ }
+ break :result dst_mcv;
+ }
+
+ const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits });
+ const width_mcv = MCValue{ .register = width_reg };
+ try self.genBinOpMir(.bsr, src_ty, dst_mcv, mat_src_mcv);
+
+ const dst_abi_size = @intCast(u32, @max(dst_ty.abiSize(self.target.*), 2));
+ try self.asmCmovccRegisterRegister(
+ registerAlias(dst_reg, dst_abi_size),
+ registerAlias(width_reg, dst_abi_size),
+ .z,
+ );
+
+ try self.genBinOpMir(.sub, dst_ty, width_mcv, dst_mcv);
+ break :result width_mcv;
+ };
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement airCtz for {}", .{self.target.cpu.arch});
+ const result = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const dst_ty = self.air.typeOfIndex(inst);
+ const src_ty = self.air.typeOf(ty_op.operand);
+ const src_bits = src_ty.bitSize(self.target.*);
+
+ const src_mcv = try self.resolveInst(ty_op.operand);
+ const mat_src_mcv = switch (src_mcv) {
+ .immediate => MCValue{ .register = try self.copyToTmpRegister(src_ty, src_mcv) },
+ else => src_mcv,
+ };
+ const mat_src_lock = switch (mat_src_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ else => null,
+ };
+ defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const dst_reg = try self.register_manager.allocReg(inst, gp);
+ const dst_mcv = MCValue{ .register = dst_reg };
+ const dst_lock = self.register_manager.lockReg(dst_reg);
+ defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
+
+ if (Target.x86.featureSetHas(self.target.cpu.features, .bmi)) {
+ const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
+ const extra_bits = registerAlias(dst_reg, src_abi_size).bitSize() - src_bits;
+ const masked_mcv = if (extra_bits > 0) masked: {
+ const mask_mcv = MCValue{
+ .immediate = ((@as(u64, 1) << @intCast(u6, extra_bits)) - 1) << @intCast(u6, src_bits),
+ };
+ const tmp_mcv = tmp: {
+ if (src_mcv.isImmediate() or self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) {
+ break :tmp src_mcv;
+ }
+ try self.genSetReg(src_ty, dst_reg, src_mcv);
+ break :tmp dst_mcv;
+ };
+ try self.genBinOpMir(.@"or", src_ty, tmp_mcv, mask_mcv);
+ break :masked tmp_mcv;
+ } else mat_src_mcv;
+ try self.genBinOpMir(.tzcnt, src_ty, dst_mcv, masked_mcv);
+ break :result dst_mcv;
+ }
+
+ const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits });
+ try self.genBinOpMir(.bsf, src_ty, dst_mcv, mat_src_mcv);
+
+ const abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2);
+ try self.asmCmovccRegisterRegister(
+ registerAlias(dst_reg, abi_size),
+ registerAlias(width_reg, abi_size),
+ .z,
+ );
+
+ break :result dst_mcv;
+ };
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement airPopcount for {}", .{self.target.cpu.arch});
+ const result = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const op_ty = self.air.typeOf(ty_op.operand);
+
+ if (Target.x86.featureSetHas(self.target.cpu.features, .popcnt)) {
+ const op_mcv = try self.resolveInst(ty_op.operand);
+ const mat_op_mcv = switch (op_mcv) {
+ .immediate => MCValue{ .register = try self.copyToTmpRegister(op_ty, op_mcv) },
+ else => op_mcv,
+ };
+ const mat_op_lock = switch (mat_op_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ else => null,
+ };
+ defer if (mat_op_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, gp) };
+ try self.genBinOpMir(.popcnt, op_ty, dst_mcv, mat_op_mcv);
+ break :result dst_mcv;
+ }
+
+ return self.fail("TODO implement airPopcount for {}", .{op_ty.fmt(self.bin_file.options.module.?)});
+ };
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
@@ -3491,7 +3606,7 @@ fn genBinOp(
if (lhs.isRegister() and self.reuseOperand(inst, lhs_air, 0, lhs)) {
break :blk lhs;
}
- if (rhs.isRegister() and is_commutative and self.reuseOperand(inst, rhs_air, 1, rhs)) {
+ if (is_commutative and rhs.isRegister() and self.reuseOperand(inst, rhs_air, 1, rhs)) {
flipped = true;
break :blk rhs;
}
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index cf948f6023..2da56c08cd 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -73,6 +73,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.adc,
.add,
.@"and",
+ .bsf,
+ .bsr,
.call,
.cbw,
.cwde,
@@ -89,12 +91,14 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.int3,
.jmp,
.lea,
+ .lzcnt,
.mov,
.movzx,
.mul,
.nop,
.@"or",
.pop,
+ .popcnt,
.push,
.ret,
.sal,
@@ -105,6 +109,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.sub,
.syscall,
.@"test",
+ .tzcnt,
.ud2,
.xor,
diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig
index 96396640d6..177b996346 100644
--- a/src/arch/x86_64/Encoding.zig
+++ b/src/arch/x86_64/Encoding.zig
@@ -307,6 +307,7 @@ pub const Mnemonic = enum {
// zig fmt: off
// General-purpose
adc, add, @"and",
+ bsf, bsr,
call, cbw, cdq, cdqe,
cmova, cmovae, cmovb, cmovbe, cmovc, cmove, cmovg, cmovge, cmovl, cmovle, cmovna,
cmovnae, cmovnb, cmovnbe, cmovnc, cmovne, cmovng, cmovnge, cmovnl, cmovnle, cmovno,
@@ -322,12 +323,13 @@ pub const Mnemonic = enum {
jmp,
lea,
lods, lodsb, lodsd, lodsq, lodsw,
+ lzcnt,
mov,
movs, movsb, movsd, movsq, movsw,
movsx, movsxd, movzx, mul,
nop,
@"or",
- pop, push,
+ pop, popcnt, push,
ret,
sal, sar, sbb,
scas, scasb, scasd, scasq, scasw,
@@ -336,7 +338,7 @@ pub const Mnemonic = enum {
setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,
setnz, seto, setp, setpe, setpo, sets, setz,
stos, stosb, stosd, stosq, stosw,
- @"test",
+ @"test", tzcnt,
ud2,
xor,
// SSE
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index 2f2c424517..befd1c692d 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -38,6 +38,10 @@ pub const Inst = struct {
add,
/// Logical and
@"and",
+ /// Bit scan forward
+ bsf,
+ /// Bit scan reverse
+ bsr,
/// Call
call,
/// Convert byte to word
@@ -70,6 +74,8 @@ pub const Inst = struct {
jmp,
/// Load effective address
lea,
+ /// Count the number of leading zero bits
+ lzcnt,
/// Move
mov,
/// Move with sign extension
@@ -84,6 +90,8 @@ pub const Inst = struct {
@"or",
/// Pop
pop,
+ /// Return the count of number of bits set to 1
+ popcnt,
/// Push
push,
/// Return
@@ -104,6 +112,8 @@ pub const Inst = struct {
syscall,
/// Test condition
@"test",
+ /// Count the number of trailing zero bits
+ tzcnt,
/// Undefined instruction
ud2,
/// Logical exclusive-or
diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig
index 6f2334ba4a..1d9663d6c4 100644
--- a/src/arch/x86_64/encodings.zig
+++ b/src/arch/x86_64/encodings.zig
@@ -81,6 +81,14 @@ pub const table = &[_]Entry{
.{ .@"and", .rm, .r32, .rm32, .none, .none, &.{ 0x23 }, 0, .none },
.{ .@"and", .rm, .r64, .rm64, .none, .none, &.{ 0x23 }, 0, .long },
+ .{ .bsf, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0xbc }, 0, .none },
+ .{ .bsf, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbc }, 0, .none },
+ .{ .bsf, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbc }, 0, .long },
+
+ .{ .bsr, .rm, .r16, .rm16, .none, .none, &.{ 0x0f, 0xbd }, 0, .none },
+ .{ .bsr, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbd }, 0, .none },
+ .{ .bsr, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbd }, 0, .long },
+
// This is M encoding according to Intel, but D makes more sense here.
.{ .call, .d, .rel32, .none, .none, .none, &.{ 0xe8 }, 0, .none },
.{ .call, .m, .rm64, .none, .none, .none, &.{ 0xff }, 2, .none },
@@ -301,6 +309,10 @@ pub const table = &[_]Entry{
.{ .lodsd, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .none },
.{ .lodsq, .np, .none, .none, .none, .none, &.{ 0xad }, 0, .long },
+ .{ .lzcnt, .rm, .r16, .rm16, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },
+ .{ .lzcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },
+ .{ .lzcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .long },
+
.{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .none },
.{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .rex },
.{ .mov, .mr, .rm16, .r16, .none, .none, &.{ 0x89 }, 0, .none },
@@ -397,6 +409,10 @@ pub const table = &[_]Entry{
.{ .pop, .m, .rm16, .none, .none, .none, &.{ 0x8f }, 0, .none },
.{ .pop, .m, .rm64, .none, .none, .none, &.{ 0x8f }, 0, .none },
+ .{ .popcnt, .rm, .r16, .rm16, .none, .none, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },
+ .{ .popcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none },
+ .{ .popcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xb8 }, 0, .long },
+
.{ .push, .o, .r16, .none, .none, .none, &.{ 0x50 }, 0, .none },
.{ .push, .o, .r64, .none, .none, .none, &.{ 0x50 }, 0, .none },
.{ .push, .m, .rm16, .none, .none, .none, &.{ 0xff }, 6, .none },
@@ -596,8 +612,8 @@ pub const table = &[_]Entry{
.{ .sub, .rm, .r32, .rm32, .none, .none, &.{ 0x2b }, 0, .none },
.{ .sub, .rm, .r64, .rm64, .none, .none, &.{ 0x2b }, 0, .long },
- .{ .syscall, .np, .none, .none, .none, .none, &.{ 0x0f, 0x05 }, 0, .none },
-
+ .{ .syscall, .np, .none, .none, .none, .none, &.{ 0x0f, 0x05 }, 0, .none }
+,
.{ .@"test", .zi, .al, .imm8, .none, .none, &.{ 0xa8 }, 0, .none },
.{ .@"test", .zi, .ax, .imm16, .none, .none, &.{ 0xa9 }, 0, .none },
.{ .@"test", .zi, .eax, .imm32, .none, .none, &.{ 0xa9 }, 0, .none },
@@ -613,6 +629,10 @@ pub const table = &[_]Entry{
.{ .@"test", .mr, .rm32, .r32, .none, .none, &.{ 0x85 }, 0, .none },
.{ .@"test", .mr, .rm64, .r64, .none, .none, &.{ 0x85 }, 0, .long },
+ .{ .tzcnt, .rm, .r16, .rm16, .none, .none, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },
+ .{ .tzcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xbc }, 0, .none },
+ .{ .tzcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xbc }, 0, .long },
+
.{ .ud2, .np, .none, .none, .none, .none, &.{ 0x0f, 0x0b }, 0, .none },
.{ .xor, .zi, .al, .imm8, .none, .none, &.{ 0x34 }, 0, .none },
From 80427796df5f8eb23ac7ca8ee03ac572b737757f Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 18 Mar 2023 23:10:44 -0400
Subject: [PATCH 053/216] x86_64: implement @returnAddress and @frameAddress
---
src/arch/x86_64/CodeGen.zig | 11 +++++++++--
test/behavior/return_address.zig | 1 -
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 317a50e0ec..7cf6865053 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -4119,12 +4119,19 @@ fn airBreakpoint(self: *Self) !void {
}
fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void {
- const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airRetAddr for x86_64", .{});
+ const result: MCValue = if (self.liveness.isUnused(inst))
+ .dead
+ else
+ .{ .stack_offset = -@as(i32, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)) };
return self.finishAir(inst, result, .{ .none, .none, .none });
}
fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
- const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFrameAddress for x86_64", .{});
+ const result = if (self.liveness.isUnused(inst)) .dead else result: {
+ const dst_mcv = try self.allocRegOrMem(inst, true);
+ try self.genBinOpMir(.mov, Type.usize, dst_mcv, .{ .register = .rbp });
+ break :result dst_mcv;
+ };
return self.finishAir(inst, result, .{ .none, .none, .none });
}
diff --git a/test/behavior/return_address.zig b/test/behavior/return_address.zig
index fe48f21ec2..123b90a66e 100644
--- a/test/behavior/return_address.zig
+++ b/test/behavior/return_address.zig
@@ -7,7 +7,6 @@ fn retAddr() usize {
test "return address" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
From bbd05e2d972b26038bf307f03aa569a7e7a2ac2c Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sun, 19 Mar 2023 02:43:55 -0400
Subject: [PATCH 054/216] x86_64: improve codegen for neg and not
---
src/arch/x86_64/CodeGen.zig | 323 +++++++++++++++++++++++++---------
src/arch/x86_64/Emit.zig | 2 +
src/arch/x86_64/Encoding.zig | 2 +-
src/arch/x86_64/Mir.zig | 4 +
src/arch/x86_64/encodings.zig | 12 ++
5 files changed, 263 insertions(+), 80 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 7cf6865053..4d8c804a0d 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -813,6 +813,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
switch (air_tags[inst]) {
// zig fmt: off
+ .not,
+ => |tag| try self.airUnOp(inst, tag),
+
.add,
.addwrap,
.sub,
@@ -905,7 +908,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.is_err_ptr => try self.airIsErrPtr(inst),
.load => try self.airLoad(inst),
.loop => try self.airLoop(inst),
- .not => try self.airNot(inst),
.ptrtoint => try self.airPtrToInt(inst),
.ret => try self.airRet(inst),
.ret_load => try self.airRetLoad(inst),
@@ -1419,8 +1421,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
// when truncating a `u16` to `u5`, for example, those top 3 bits in the result
// have to be removed. this only happens if the dst if not a power-of-two size.
- const dst_bit_size = dst_ty.bitSize(self.target.*);
- if (!math.isPowerOfTwo(dst_bit_size) or dst_bit_size < 8) {
+ if (self.regExtraBits(dst_ty) > 0) {
try self.truncateRegister(dst_ty, reg);
}
@@ -1434,58 +1435,6 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ un_op, .none, .none });
}
-fn airNot(self: *Self, inst: Air.Inst.Index) !void {
- const ty_op = self.air.instructions.items(.data)[inst].ty_op;
-
- if (self.liveness.isUnused(inst)) {
- return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
- }
-
- const operand_ty = self.air.typeOf(ty_op.operand);
- const operand = try self.resolveInst(ty_op.operand);
-
- const result: MCValue = result: {
- switch (operand) {
- .dead => unreachable,
- .unreach => unreachable,
- .eflags => |cc| {
- break :result MCValue{ .eflags = cc.negate() };
- },
- else => {},
- }
-
- const operand_lock: ?RegisterLock = switch (operand) {
- .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
- else => null,
- };
- defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
-
- const dst_mcv: MCValue = blk: {
- if (self.reuseOperand(inst, ty_op.operand, 0, operand) and operand.isRegister()) {
- break :blk operand;
- }
- break :blk try self.copyToRegisterWithInstTracking(inst, operand_ty, operand);
- };
- const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
- .register => |reg| self.register_manager.lockReg(reg),
- else => null,
- };
- defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
-
- const mask = switch (operand_ty.abiSize(self.target.*)) {
- 1 => ~@as(u8, 0),
- 2 => ~@as(u16, 0),
- 4 => ~@as(u32, 0),
- 8 => ~@as(u64, 0),
- else => unreachable,
- };
- try self.genBinOpMir(.xor, operand_ty, dst_mcv, .{ .immediate = mask });
-
- break :result dst_mcv;
- };
- return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
-}
-
fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
@@ -1507,6 +1456,16 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
+fn airUnOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+
+ const result = if (self.liveness.isUnused(inst))
+ .dead
+ else
+ try self.genUnOp(inst, tag, ty_op.operand);
+ return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
+}
+
fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -2602,7 +2561,6 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
const dst_ty = self.air.typeOfIndex(inst);
const src_ty = self.air.typeOf(ty_op.operand);
- const src_bits = src_ty.bitSize(self.target.*);
const src_mcv = try self.resolveInst(ty_op.operand);
const mat_src_mcv = switch (src_mcv) {
@@ -2622,14 +2580,14 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
if (Target.x86.featureSetHas(self.target.cpu.features, .lzcnt)) {
try self.genBinOpMir(.lzcnt, src_ty, dst_mcv, mat_src_mcv);
- const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
- const extra_bits = registerAlias(dst_reg, src_abi_size).bitSize() - src_bits;
+ const extra_bits = self.regExtraBits(src_ty);
if (extra_bits > 0) {
try self.genBinOpMir(.sub, dst_ty, dst_mcv, .{ .immediate = extra_bits });
}
break :result dst_mcv;
}
+ const src_bits = src_ty.bitSize(self.target.*);
const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits });
const width_mcv = MCValue{ .register = width_reg };
try self.genBinOpMir(.bsr, src_ty, dst_mcv, mat_src_mcv);
@@ -2673,8 +2631,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
if (Target.x86.featureSetHas(self.target.cpu.features, .bmi)) {
- const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
- const extra_bits = registerAlias(dst_reg, src_abi_size).bitSize() - src_bits;
+ const extra_bits = self.regExtraBits(src_ty);
const masked_mcv = if (extra_bits > 0) masked: {
const mask_mcv = MCValue{
.immediate = ((@as(u64, 1) << @intCast(u6, extra_bits)) - 1) << @intCast(u6, src_bits),
@@ -3293,6 +3250,106 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
+fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue {
+ const src_ty = self.air.typeOf(src_air);
+ const src_mcv = try self.resolveInst(src_air);
+ if (src_ty.zigTypeTag() == .Vector) {
+ return self.fail("TODO implement genBinOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
+ }
+ if (src_ty.abiSize(self.target.*) > 8) {
+ return self.fail("TODO implement genBinOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
+ }
+
+ switch (src_mcv) {
+ .eflags => |cc| switch (tag) {
+ .not => return .{ .eflags = cc.negate() },
+ else => {},
+ },
+ else => {},
+ }
+
+ const src_lock = switch (src_mcv) {
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ else => null,
+ };
+ defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const dst_mcv: MCValue = if (maybe_inst) |inst|
+ if (self.reuseOperand(inst, src_air, 0, src_mcv))
+ src_mcv
+ else
+ try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv)
+ else
+ .{ .register = try self.copyToTmpRegister(src_ty, src_mcv) };
+ const dst_lock = switch (dst_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ else => null,
+ };
+ defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
+
+ switch (tag) {
+ .not => {
+ const int_info = if (src_ty.tag() == .bool)
+ std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 }
+ else
+ src_ty.intInfo(self.target.*);
+ const extra_bits = self.regExtraBits(src_ty);
+ if (int_info.signedness == .unsigned and extra_bits > 0) {
+ const mask = (@as(u64, 1) << @intCast(u6, src_ty.bitSize(self.target.*))) - 1;
+ try self.genBinOpMir(.xor, src_ty, dst_mcv, .{ .immediate = mask });
+ } else try self.genUnOpMir(.not, src_ty, dst_mcv);
+ },
+
+ .neg => try self.genUnOpMir(.neg, src_ty, dst_mcv),
+
+ else => unreachable,
+ }
+ return dst_mcv;
+}
+
+fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue) !void {
+ const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
+ switch (dst_mcv) {
+ .none => unreachable,
+ .undef => unreachable,
+ .dead, .unreach, .immediate => unreachable,
+ .eflags => unreachable,
+ .register_overflow => unreachable,
+ .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
+ .ptr_stack_offset, .stack_offset => |off| {
+ if (off > math.maxInt(i32)) {
+ return self.fail("stack offset too large", .{});
+ }
+ if (abi_size > 8) {
+ return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag});
+ }
+
+ try self.asmMemory(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
+ .base = .rbp,
+ .disp = -off,
+ }));
+ },
+ .memory, .linker_load => {
+ const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
+ const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
+ defer self.register_manager.unlockReg(addr_reg_lock);
+
+ try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv);
+
+ // To get the actual address of the value we want to modify we have to go through the GOT
+ try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{
+ .base = addr_reg,
+ .disp = 0,
+ }));
+
+ try self.asmMemory(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
+ .base = addr_reg,
+ .disp = 0,
+ }));
+ },
+ }
+}
+
/// Clobbers .rcx for non-immediate shift value.
fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shift: MCValue) !void {
assert(reg.to64() != .rcx);
@@ -3573,6 +3630,17 @@ fn genBinOp(
return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});
}
+ switch (lhs) {
+ .immediate => |imm| switch (imm) {
+ 0 => switch (tag) {
+ .sub, .subwrap => return self.genUnOp(maybe_inst, .neg, rhs_air),
+ else => {},
+ },
+ else => {},
+ },
+ else => {},
+ }
+
const is_commutative: bool = switch (tag) {
.add,
.addwrap,
@@ -3595,7 +3663,7 @@ fn genBinOp(
defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
const rhs_lock: ?RegisterLock = switch (rhs) {
- .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ .register => |reg| self.register_manager.lockReg(reg),
else => null,
};
defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
@@ -3740,7 +3808,28 @@ fn genBinOp(
const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
switch (dst_mcv) {
+ .none,
+ .undef,
+ .dead,
+ .unreach,
+ .immediate,
+ .eflags,
+ .register_overflow,
+ .stack_offset,
+ .ptr_stack_offset,
+ .memory,
+ .linker_load,
+ => unreachable,
.register => |dst_reg| switch (mat_src_mcv) {
+ .none,
+ .undef,
+ .dead,
+ .unreach,
+ .immediate,
+ .eflags,
+ .register_overflow,
+ .ptr_stack_offset,
+ => unreachable,
.register => |src_reg| try self.asmCmovccRegisterRegister(
registerAlias(dst_reg, abi_size),
registerAlias(src_reg, abi_size),
@@ -3748,12 +3837,36 @@ fn genBinOp(
),
.stack_offset => |off| try self.asmCmovccRegisterMemory(
registerAlias(dst_reg, abi_size),
- Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
+ .base = .rbp,
+ .disp = -off,
+ }),
cc,
),
- else => unreachable,
+ .memory, .linker_load => {
+ const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
+ const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
+ defer self.register_manager.unlockReg(addr_reg_lock);
+
+ try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv);
+
+ // To get the actual address of the value we want to modify we
+ // we have to go through the GOT
+ try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{
+ .base = addr_reg,
+ .disp = 0,
+ }));
+
+ try self.asmCmovccRegisterMemory(
+ registerAlias(dst_reg, abi_size),
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
+ .base = addr_reg,
+ .disp = 0,
+ }),
+ cc,
+ );
+ },
},
- else => unreachable,
}
},
.Float => try self.genBinOpMir(switch (lhs_ty.tag()) {
@@ -3813,16 +3926,15 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
),
},
.immediate => |imm| {
- switch (abi_size) {
- 0 => unreachable,
- 1...4 => {
+ switch (self.regBitSize(dst_ty)) {
+ 8, 16, 32 => {
try self.asmRegisterImmediate(
mir_tag,
registerAlias(dst_reg, abi_size),
Immediate.u(@intCast(u32, imm)),
);
},
- 5...8 => {
+ 64 => {
if (math.cast(i32, @bitCast(i64, imm))) |small| {
try self.asmRegisterImmediate(
mir_tag,
@@ -3883,11 +3995,40 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
}), registerAlias(src_reg, abi_size));
},
.immediate => |imm| {
- // TODO
- try self.asmMemoryImmediate(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
- .base = .rbp,
- .disp = -off,
- }), Immediate.u(@intCast(u32, imm)));
+ switch (self.regBitSize(dst_ty)) {
+ 8, 16, 32 => {
+ try self.asmMemoryImmediate(
+ mir_tag,
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
+ .base = .rbp,
+ .disp = -off,
+ }),
+ Immediate.u(@intCast(u32, imm)),
+ );
+ },
+ 64 => {
+ if (math.cast(i32, @bitCast(i64, imm))) |small| {
+ try self.asmMemoryImmediate(
+ mir_tag,
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
+ .base = .rbp,
+ .disp = -off,
+ }),
+ Immediate.s(small),
+ );
+ } else {
+ try self.asmMemoryRegister(
+ mir_tag,
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
+ .base = .rbp,
+ .disp = -off,
+ }),
+ registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),
+ );
+ }
+ },
+ else => return self.fail("TODO getBinOpMir implement large immediate ABI", .{}),
+ }
},
.memory,
.stack_offset,
@@ -4119,17 +4260,20 @@ fn airBreakpoint(self: *Self) !void {
}
fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void {
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- .{ .stack_offset = -@as(i32, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)) };
+ const result = if (self.liveness.isUnused(inst)) .dead else result: {
+ const dst_mcv = try self.allocRegOrMem(inst, true);
+ try self.setRegOrMem(Type.usize, dst_mcv, .{
+ .stack_offset = -@as(i32, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)),
+ });
+ break :result dst_mcv;
+ };
return self.finishAir(inst, result, .{ .none, .none, .none });
}
fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
const result = if (self.liveness.isUnused(inst)) .dead else result: {
const dst_mcv = try self.allocRegOrMem(inst, true);
- try self.genBinOpMir(.mov, Type.usize, dst_mcv, .{ .register = .rbp });
+ try self.setRegOrMem(Type.usize, dst_mcv, .{ .register = .rbp });
break :result dst_mcv;
};
return self.finishAir(inst, result, .{ .none, .none, .none });
@@ -5864,7 +6008,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
.undef => {
if (!self.wantSafety()) return; // The already existing value will do just fine.
// Write the debug undefined value.
- switch (registerAlias(reg, abi_size).bitSize()) {
+ switch (self.regBitSize(ty)) {
8 => return self.genSetReg(ty, reg, .{ .immediate = 0xaa }),
16 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaa }),
32 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaa }),
@@ -6763,6 +6907,27 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
}
}
+fn regBitSize(self: *Self, ty: Type) u64 {
+ return switch (ty.zigTypeTag()) {
+ else => switch (ty.abiSize(self.target.*)) {
+ 1 => 8,
+ 2 => 16,
+ 3...4 => 32,
+ 5...8 => 64,
+ else => unreachable,
+ },
+ .Float => switch (ty.abiSize(self.target.*)) {
+ 1...16 => 128,
+ 17...32 => 256,
+ else => unreachable,
+ },
+ };
+}
+
+fn regExtraBits(self: *Self, ty: Type) u64 {
+ return self.regBitSize(ty) - ty.bitSize(self.target.*);
+}
+
fn intrinsicsAllowed(target: Target, ty: Type) bool {
return switch (ty.tag()) {
.f32,
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index 2da56c08cd..b2a13a192a 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -95,7 +95,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.mov,
.movzx,
.mul,
+ .neg,
.nop,
+ .not,
.@"or",
.pop,
.popcnt,
diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig
index 177b996346..c813f2bece 100644
--- a/src/arch/x86_64/Encoding.zig
+++ b/src/arch/x86_64/Encoding.zig
@@ -327,7 +327,7 @@ pub const Mnemonic = enum {
mov,
movs, movsb, movsd, movsq, movsw,
movsx, movsxd, movzx, mul,
- nop,
+ neg, nop, not,
@"or",
pop, popcnt, push,
ret,
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index befd1c692d..9f9122dd5e 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -84,8 +84,12 @@ pub const Inst = struct {
movzx,
/// Multiply
mul,
+ /// Two's complement negation
+ neg,
/// No-op
nop,
+ /// One's complement negation
+ not,
/// Logical or
@"or",
/// Pop
diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig
index 1d9663d6c4..7ade1be11b 100644
--- a/src/arch/x86_64/encodings.zig
+++ b/src/arch/x86_64/encodings.zig
@@ -379,8 +379,20 @@ pub const table = &[_]Entry{
.{ .mul, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 4, .none },
.{ .mul, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 4, .long },
+ .{ .neg, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 3, .none },
+ .{ .neg, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 3, .rex },
+ .{ .neg, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 3, .none },
+ .{ .neg, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 3, .none },
+ .{ .neg, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 3, .long },
+
.{ .nop, .np, .none, .none, .none, .none, &.{ 0x90 }, 0, .none },
+ .{ .not, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 2, .none },
+ .{ .not, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 2, .rex },
+ .{ .not, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 2, .none },
+ .{ .not, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 2, .none },
+ .{ .not, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 2, .long },
+
.{ .@"or", .zi, .al, .imm8, .none, .none, &.{ 0x0c }, 0, .none },
.{ .@"or", .zi, .ax, .imm16, .none, .none, &.{ 0x0d }, 0, .none },
.{ .@"or", .zi, .eax, .imm32, .none, .none, &.{ 0x0d }, 0, .none },
From 24f0900ecba3ea67b7c6df31836ed40de22b7ab8 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sun, 19 Mar 2023 03:51:51 -0400
Subject: [PATCH 055/216] x86_64: implement some error union ops
---
src/arch/x86_64/CodeGen.zig | 121 ++++++++++++++++++++++++++++++------
test/behavior/error.zig | 1 -
2 files changed, 101 insertions(+), 21 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 4d8c804a0d..95068a2bee 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -994,10 +994,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.optional_payload => try self.airOptionalPayload(inst),
.optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
.optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
- .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
- .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
- .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
- .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
+ .unwrap_errunion_err => try self.airUnwrapErrUnionErr(inst),
+ .unwrap_errunion_payload => try self.airUnwrapErrUnionPayload(inst),
+ .unwrap_errunion_err_ptr => try self.airUnwrapErrUnionErrPtr(inst),
+ .unwrap_errunion_payload_ptr=> try self.airUnwrapErrUnionPayloadPtr(inst),
.errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
.err_return_trace => try self.airErrReturnTrace(inst),
.set_err_return_trace => try self.airSetErrReturnTrace(inst),
@@ -1923,7 +1923,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
-fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
+fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
if (self.liveness.isUnused(inst)) {
return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
@@ -1967,7 +1967,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
-fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
+fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
if (self.liveness.isUnused(inst)) {
return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
@@ -2021,31 +2021,112 @@ fn genUnwrapErrorUnionPayloadMir(
}
// *(E!T) -> E
-fn airUnwrapErrErrPtr(self: *Self, inst: Air.Inst.Index) !void {
+fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement unwrap error union error ptr for {}", .{self.target.cpu.arch});
+ const result: MCValue = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const src_ty = self.air.typeOf(ty_op.operand);
+ const src_mcv = try self.resolveInst(ty_op.operand);
+ const src_reg = switch (src_mcv) {
+ .register => |reg| reg,
+ else => try self.copyToTmpRegister(src_ty, src_mcv),
+ };
+ const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
+ defer self.register_manager.unlockReg(src_lock);
+
+ const dst_reg = try self.register_manager.allocReg(inst, gp);
+ const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
+ defer self.register_manager.unlockReg(dst_lock);
+
+ const eu_ty = src_ty.childType();
+ const pl_ty = eu_ty.errorUnionPayload();
+ const err_ty = eu_ty.errorUnionSet();
+ const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*));
+ const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*));
+ try self.asmRegisterMemory(
+ .mov,
+ registerAlias(dst_reg, err_abi_size),
+ Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{ .base = src_reg, .disp = err_off }),
+ );
+ break :result .{ .register = dst_reg };
+ };
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
// *(E!T) -> *T
-fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
+fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement unwrap error union payload ptr for {}", .{self.target.cpu.arch});
+ const result: MCValue = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const src_ty = self.air.typeOf(ty_op.operand);
+ const src_mcv = try self.resolveInst(ty_op.operand);
+ const src_reg = switch (src_mcv) {
+ .register => |reg| reg,
+ else => try self.copyToTmpRegister(src_ty, src_mcv),
+ };
+ const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
+ defer self.register_manager.unlockReg(src_lock);
+
+ const dst_ty = self.air.typeOfIndex(inst);
+ const dst_reg = try self.register_manager.allocReg(inst, gp);
+ const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
+ defer self.register_manager.unlockReg(dst_lock);
+
+ const eu_ty = src_ty.childType();
+ const pl_ty = eu_ty.errorUnionPayload();
+ const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*));
+ const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
+ try self.asmRegisterMemory(
+ .lea,
+ registerAlias(dst_reg, dst_abi_size),
+ Memory.sib(.qword, .{ .base = src_reg, .disp = pl_off }),
+ );
+ break :result .{ .register = dst_reg };
+ };
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch});
+ const result: MCValue = result: {
+ const src_ty = self.air.typeOf(ty_op.operand);
+ const src_mcv = try self.resolveInst(ty_op.operand);
+ const src_reg = switch (src_mcv) {
+ .register => |reg| reg,
+ else => try self.copyToTmpRegister(src_ty, src_mcv),
+ };
+ const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
+ defer self.register_manager.unlockReg(src_lock);
+
+ const eu_ty = src_ty.childType();
+ const pl_ty = eu_ty.errorUnionPayload();
+ const err_ty = eu_ty.errorUnionSet();
+ const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*));
+ const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*));
+ try self.asmMemoryImmediate(
+ .mov,
+ Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{ .base = src_reg, .disp = err_off }),
+ Immediate.u(0),
+ );
+
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const dst_ty = self.air.typeOfIndex(inst);
+ const dst_reg = try self.register_manager.allocReg(inst, gp);
+ const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
+ defer self.register_manager.unlockReg(dst_lock);
+
+ const pl_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*));
+ const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
+ try self.asmRegisterMemory(
+ .lea,
+ registerAlias(dst_reg, dst_abi_size),
+ Memory.sib(.qword, .{ .base = src_reg, .disp = pl_off }),
+ );
+ break :result .{ .register = dst_reg };
+ };
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
diff --git a/test/behavior/error.zig b/test/behavior/error.zig
index 9d4b154311..294b4ac2eb 100644
--- a/test/behavior/error.zig
+++ b/test/behavior/error.zig
@@ -731,7 +731,6 @@ test "pointer to error union payload" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
var err_union: anyerror!u8 = 15;
From f95faac5aeeebe0b77ff7023513cdd3e34b71de1 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sun, 19 Mar 2023 06:49:50 -0400
Subject: [PATCH 056/216] x86_64: (re)implement optional ops
Note that this commit also changes the layout of optional for all
other backends using `src/codegen.zig` without updating them!
---
src/arch/x86_64/CodeGen.zig | 320 +++++++++++++++++++++-------------
src/arch/x86_64/Emit.zig | 4 +
src/arch/x86_64/Encoding.zig | 2 +-
src/arch/x86_64/Mir.zig | 8 +
src/arch/x86_64/encodings.zig | 28 +++
src/codegen.zig | 5 +-
test/behavior/bugs/12984.zig | 1 -
test/behavior/bugs/13785.zig | 1 -
test/behavior/call.zig | 1 -
test/behavior/cast.zig | 1 -
test/behavior/error.zig | 1 -
test/behavior/if.zig | 1 -
test/behavior/null.zig | 2 -
test/behavior/optional.zig | 7 -
test/behavior/ptrcast.zig | 1 -
test/behavior/struct.zig | 3 -
test/behavior/tuple.zig | 4 -
test/behavior/union.zig | 1 -
test/behavior/while.zig | 1 -
19 files changed, 243 insertions(+), 149 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 95068a2bee..f788dbd531 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -1871,55 +1871,74 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- if (self.liveness.isUnused(inst)) {
- return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
- }
-
- const payload_ty = self.air.typeOfIndex(inst);
- const optional_ty = self.air.typeOf(ty_op.operand);
- const operand = try self.resolveInst(ty_op.operand);
const result: MCValue = result: {
- if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
- if (optional_ty.isPtrLikeOptional()) {
- if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {
- break :result operand;
+ if (self.liveness.isUnused(inst)) break :result .none;
+
+ const pl_ty = self.air.typeOfIndex(inst);
+ const opt_mcv = try self.resolveInst(ty_op.operand);
+
+ if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) {
+ switch (opt_mcv) {
+ .register => |reg| try self.truncateRegister(pl_ty, reg),
+ else => {},
}
- break :result try self.copyToRegisterWithInstTracking(inst, payload_ty, operand);
+ break :result opt_mcv;
}
- const offset = optional_ty.abiSize(self.target.*) - payload_ty.abiSize(self.target.*);
- switch (operand) {
- .stack_offset => |off| {
- break :result MCValue{ .stack_offset = off - @intCast(i32, offset) };
- },
- .register => {
- // TODO reuse the operand
- const result = try self.copyToRegisterWithInstTracking(inst, optional_ty, operand);
- const shift = @intCast(u8, offset * @sizeOf(usize));
- try self.genShiftBinOpMir(.shr, optional_ty, result.register, .{ .immediate = @intCast(u8, shift) });
- break :result result;
- },
- else => return self.fail("TODO implement optional_payload when operand is {}", .{operand}),
- }
+ const pl_mcv = try self.allocRegOrMem(inst, true);
+ try self.setRegOrMem(pl_ty, pl_mcv, opt_mcv);
+ break :result pl_mcv;
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement .optional_payload_ptr for {}", .{self.target.cpu.arch});
+ const result: MCValue = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const dst_ty = self.air.typeOfIndex(inst);
+ const opt_mcv = try self.resolveInst(ty_op.operand);
+
+ break :result if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv))
+ opt_mcv
+ else
+ try self.copyToRegisterWithInstTracking(inst, dst_ty, opt_mcv);
+ };
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement .optional_payload_ptr_set for {}", .{self.target.cpu.arch});
+ const result = result: {
+ const dst_ty = self.air.typeOfIndex(inst);
+ const src_ty = self.air.typeOf(ty_op.operand);
+ const opt_ty = src_ty.childType();
+ const src_mcv = try self.resolveInst(ty_op.operand);
+
+ if (opt_ty.optionalReprIsPayload()) {
+ break :result if (self.liveness.isUnused(inst))
+ .dead
+ else if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ src_mcv
+ else
+ try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
+ }
+
+ const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ src_mcv
+ else
+ try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
+
+ const pl_ty = dst_ty.childType();
+ const pl_abi_size = @intCast(i32, pl_ty.abiSize(self.target.*));
+ try self.asmMemoryImmediate(
+ .mov,
+ Memory.sib(.byte, .{ .base = dst_mcv.register, .disp = pl_abi_size }),
+ Immediate.u(1),
+ );
+ break :result if (self.liveness.isUnused(inst)) .dead else dst_mcv;
+ };
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
@@ -2150,41 +2169,45 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void {
fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- if (self.liveness.isUnused(inst)) {
- return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
- }
-
- const payload_ty = self.air.typeOf(ty_op.operand);
const result: MCValue = result: {
- if (!payload_ty.hasRuntimeBits()) {
- break :result MCValue{ .immediate = 1 };
- }
+ if (self.liveness.isUnused(inst)) break :result .dead;
- const optional_ty = self.air.typeOfIndex(inst);
- const operand = try self.resolveInst(ty_op.operand);
- const operand_lock: ?RegisterLock = switch (operand) {
+ const pl_ty = self.air.typeOf(ty_op.operand);
+ if (!pl_ty.hasRuntimeBits()) break :result .{ .immediate = 1 };
+
+ const opt_ty = self.air.typeOfIndex(inst);
+ const pl_mcv = try self.resolveInst(ty_op.operand);
+ const same_repr = opt_ty.optionalReprIsPayload();
+ if (same_repr and self.reuseOperand(inst, ty_op.operand, 0, pl_mcv)) break :result pl_mcv;
+
+ const pl_lock: ?RegisterLock = switch (pl_mcv) {
.register => |reg| self.register_manager.lockRegAssumeUnused(reg),
else => null,
};
- defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
+ defer if (pl_lock) |lock| self.register_manager.unlockReg(lock);
- if (optional_ty.isPtrLikeOptional()) {
- // TODO should we check if we can reuse the operand?
- if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {
- break :result operand;
+ const opt_mcv = try self.allocRegOrMem(inst, true);
+ try self.setRegOrMem(pl_ty, opt_mcv, pl_mcv);
+
+ if (!same_repr) {
+ const pl_abi_size = @intCast(i32, pl_ty.abiSize(self.target.*));
+ switch (opt_mcv) {
+ else => unreachable,
+
+ .register => |opt_reg| try self.asmRegisterImmediate(
+ .bts,
+ opt_reg,
+ Immediate.u(@intCast(u6, pl_abi_size * 8)),
+ ),
+
+ .stack_offset => |off| try self.asmMemoryImmediate(
+ .mov,
+ Memory.sib(.byte, .{ .base = .rsp, .disp = pl_abi_size - off }),
+ Immediate.u(0),
+ ),
}
- break :result try self.copyToRegisterWithInstTracking(inst, payload_ty, operand);
}
-
- const optional_abi_size = @intCast(u32, optional_ty.abiSize(self.target.*));
- const optional_abi_align = optional_ty.abiAlignment(self.target.*);
- const payload_abi_size = @intCast(u32, payload_ty.abiSize(self.target.*));
- const offset = optional_abi_size - payload_abi_size;
-
- const stack_offset = @intCast(i32, try self.allocMem(inst, optional_abi_size, optional_abi_align));
- try self.genSetStack(Type.bool, stack_offset, .{ .immediate = 1 }, .{});
- try self.genSetStack(payload_ty, stack_offset - @intCast(i32, offset), operand, .{});
- break :result MCValue{ .stack_offset = stack_offset };
+ break :result opt_mcv;
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
@@ -2619,7 +2642,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
},
.register => {
const shift: u6 = if (layout.tag_align < layout.payload_align)
- @intCast(u6, layout.payload_size * @sizeOf(usize))
+ @intCast(u6, layout.payload_size * 8)
else
0;
const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);
@@ -3271,7 +3294,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
// Shift by struct_field_offset.
- const shift = @intCast(u8, struct_field_offset * @sizeOf(usize));
+ const shift = @intCast(u8, struct_field_offset * 8);
try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv.register, .{ .immediate = shift });
// Mask with reg.bitSize() - struct_field_size
@@ -4928,25 +4951,107 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, .unreach, .{ .none, .none, .none });
}
-fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
+fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MCValue {
try self.spillEflagsIfOccupied();
self.eflags_inst = inst;
- const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: {
- var buf: Type.Payload.ElemType = undefined;
- const payload_ty = ty.optionalChild(&buf);
- break :blk if (payload_ty.hasRuntimeBitsIgnoreComptime()) Type.bool else ty;
- } else ty;
+ var pl_buf: Type.Payload.ElemType = undefined;
+ const pl_ty = opt_ty.optionalChild(&pl_buf);
- try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 });
+ var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
+ const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload())
+ .{ .off = 0, .ty = if (pl_ty.isSlice()) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty }
+ else
+ .{ .off = @intCast(i32, pl_ty.abiSize(self.target.*)), .ty = Type.bool };
- return MCValue{ .eflags = .e };
+ switch (opt_mcv) {
+ .none,
+ .unreach,
+ .dead,
+ .undef,
+ .immediate,
+ .register_overflow,
+ .ptr_stack_offset,
+ .eflags,
+ => unreachable,
+
+ .register => |opt_reg| {
+ if (some_info.off == 0) {
+ const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
+ const alias_reg = registerAlias(opt_reg, some_abi_size);
+ assert(some_abi_size * 8 == alias_reg.bitSize());
+ try self.asmRegisterRegister(.@"test", alias_reg, alias_reg);
+ return .{ .eflags = .z };
+ }
+ assert(some_info.ty.tag() == .bool);
+ const opt_abi_size = @intCast(u32, opt_ty.abiSize(self.target.*));
+ try self.asmRegisterImmediate(
+ .bt,
+ registerAlias(opt_reg, opt_abi_size),
+ Immediate.u(@intCast(u6, some_info.off * 8)),
+ );
+ return .{ .eflags = .nc };
+ },
+
+ .memory, .linker_load => {
+ const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
+ const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
+ defer self.register_manager.unlockReg(addr_reg_lock);
+
+ try self.loadMemPtrIntoRegister(addr_reg, Type.usize, opt_mcv);
+
+ // To get the actual address of the value we want to modify we have to go through the GOT
+ try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{
+ .base = addr_reg,
+ .disp = 0,
+ }));
+
+ const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
+ try self.asmMemoryImmediate(.cmp, Memory.sib(
+ Memory.PtrSize.fromSize(some_abi_size),
+ .{ .base = addr_reg, .disp = some_info.off },
+ ), Immediate.u(0));
+ return .{ .eflags = .e };
+ },
+
+ .stack_offset => |off| {
+ const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
+ try self.asmMemoryImmediate(.cmp, Memory.sib(
+ Memory.PtrSize.fromSize(some_abi_size),
+ .{ .base = .rbp, .disp = some_info.off - off },
+ ), Immediate.u(0));
+ return .{ .eflags = .e };
+ },
+ }
}
-fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
- const is_null_res = try self.isNull(inst, ty, operand);
- assert(is_null_res.eflags == .e);
- return MCValue{ .eflags = is_null_res.eflags.negate() };
+fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue {
+ try self.spillEflagsIfOccupied();
+ self.eflags_inst = inst;
+
+ const opt_ty = ptr_ty.childType();
+ var pl_buf: Type.Payload.ElemType = undefined;
+ const pl_ty = opt_ty.optionalChild(&pl_buf);
+
+ var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
+ const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload())
+ .{ .off = 0, .ty = if (pl_ty.isSlice()) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty }
+ else
+ .{ .off = @intCast(i32, pl_ty.abiSize(self.target.*)), .ty = Type.bool };
+
+ const ptr_reg = switch (ptr_mcv) {
+ .register => |reg| reg,
+ else => try self.copyToTmpRegister(ptr_ty, ptr_mcv),
+ };
+ const ptr_lock = self.register_manager.lockReg(ptr_reg);
+ defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
+ try self.asmMemoryImmediate(.cmp, Memory.sib(
+ Memory.PtrSize.fromSize(some_abi_size),
+ .{ .base = ptr_reg, .disp = some_info.off },
+ ), Immediate.u(0));
+ return .{ .eflags = .e };
}
fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
@@ -5012,29 +5117,11 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
const un_op = self.air.instructions.items(.data)[inst].un_op;
-
- if (self.liveness.isUnused(inst)) {
- return self.finishAir(inst, .dead, .{ un_op, .none, .none });
- }
-
- const operand_ptr = try self.resolveInst(un_op);
- const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) {
- .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
- else => null,
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
+ const operand = try self.resolveInst(un_op);
+ const ty = self.air.typeOf(un_op);
+ break :result try self.isNullPtr(inst, ty, operand);
};
- defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock);
-
- const ptr_ty = self.air.typeOf(un_op);
- const elem_ty = ptr_ty.childType();
- const operand = if (elem_ty.isPtrLikeOptional() and self.reuseOperand(inst, un_op, 0, operand_ptr))
- // The MCValue that holds the pointer can be re-used as the value.
- operand_ptr
- else
- try self.allocTempRegOrMem(elem_ty, true);
- try self.load(operand, operand_ptr, ptr_ty);
-
- const result = try self.isNull(inst, elem_ty, operand);
-
return self.finishAir(inst, result, .{ un_op, .none, .none });
}
@@ -5043,36 +5130,24 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
const operand = try self.resolveInst(un_op);
const ty = self.air.typeOf(un_op);
- break :result try self.isNonNull(inst, ty, operand);
+ break :result switch (try self.isNull(inst, ty, operand)) {
+ .eflags => |cc| .{ .eflags = cc.negate() },
+ else => unreachable,
+ };
};
return self.finishAir(inst, result, .{ un_op, .none, .none });
}
fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
const un_op = self.air.instructions.items(.data)[inst].un_op;
-
- if (self.liveness.isUnused(inst)) {
- return self.finishAir(inst, .dead, .{ un_op, .none, .none });
- }
-
- const operand_ptr = try self.resolveInst(un_op);
- const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) {
- .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
- else => null,
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
+ const operand = try self.resolveInst(un_op);
+ const ty = self.air.typeOf(un_op);
+ break :result switch (try self.isNullPtr(inst, ty, operand)) {
+ .eflags => |cc| .{ .eflags = cc.negate() },
+ else => unreachable,
+ };
};
- defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock);
-
- const ptr_ty = self.air.typeOf(un_op);
- const elem_ty = ptr_ty.childType();
- const operand = if (elem_ty.isPtrLikeOptional() and self.reuseOperand(inst, un_op, 0, operand_ptr))
- // The MCValue that holds the pointer can be re-used as the value.
- operand_ptr
- else
- try self.allocTempRegOrMem(elem_ty, true);
- try self.load(operand, operand_ptr, ptr_ty);
-
- const result = try self.isNonNull(inst, ptr_ty.elemType(), operand);
-
return self.finishAir(inst, result, .{ un_op, .none, .none });
}
@@ -6967,7 +7042,10 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
/// Truncates the value in the register in place.
/// Clobbers any remaining bits.
fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
- const int_info = ty.intInfo(self.target.*);
+ const int_info = if (ty.isAbiInt()) ty.intInfo(self.target.*) else std.builtin.Type.Int{
+ .signedness = .unsigned,
+ .bits = @intCast(u16, ty.bitSize(self.target.*)),
+ };
const max_reg_bit_width = Register.rax.bitSize();
switch (int_info.signedness) {
.signed => {
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index b2a13a192a..4c63385e6b 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -75,6 +75,10 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.@"and",
.bsf,
.bsr,
+ .bt,
+ .btc,
+ .btr,
+ .bts,
.call,
.cbw,
.cwde,
diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig
index c813f2bece..436202ca3e 100644
--- a/src/arch/x86_64/Encoding.zig
+++ b/src/arch/x86_64/Encoding.zig
@@ -307,7 +307,7 @@ pub const Mnemonic = enum {
// zig fmt: off
// General-purpose
adc, add, @"and",
- bsf, bsr,
+ bsf, bsr, bt, btc, btr, bts,
call, cbw, cdq, cdqe,
cmova, cmovae, cmovb, cmovbe, cmovc, cmove, cmovg, cmovge, cmovl, cmovle, cmovna,
cmovnae, cmovnb, cmovnbe, cmovnc, cmovne, cmovng, cmovnge, cmovnl, cmovnle, cmovno,
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index 9f9122dd5e..e7d75e7446 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -42,6 +42,14 @@ pub const Inst = struct {
bsf,
/// Bit scan reverse
bsr,
+ /// Bit test
+ bt,
+ /// Bit test and complement
+ btc,
+ /// Bit test and reset
+ btr,
+ /// Bit test and set
+ bts,
/// Call
call,
/// Convert byte to word
diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig
index 7ade1be11b..ea21af2067 100644
--- a/src/arch/x86_64/encodings.zig
+++ b/src/arch/x86_64/encodings.zig
@@ -89,6 +89,34 @@ pub const table = &[_]Entry{
.{ .bsr, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbd }, 0, .none },
.{ .bsr, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbd }, 0, .long },
+ .{ .bt, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none },
+ .{ .bt, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none },
+ .{ .bt, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xa3 }, 0, .long },
+ .{ .bt, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .none },
+ .{ .bt, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .none },
+ .{ .bt, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .long },
+
+ .{ .btc, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xbb }, 0, .none },
+ .{ .btc, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xbb }, 0, .none },
+ .{ .btc, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xbb }, 0, .long },
+ .{ .btc, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .none },
+ .{ .btc, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .none },
+ .{ .btc, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .long },
+
+ .{ .btr, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb3 }, 0, .none },
+ .{ .btr, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb3 }, 0, .none },
+ .{ .btr, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb3 }, 0, .long },
+ .{ .btr, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .none },
+ .{ .btr, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .none },
+ .{ .btr, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .long },
+
+ .{ .bts, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xab }, 0, .none },
+ .{ .bts, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xab }, 0, .none },
+ .{ .bts, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xab }, 0, .long },
+ .{ .bts, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .none },
+ .{ .bts, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .none },
+ .{ .bts, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .long },
+
// This is M encoding according to Intel, but D makes more sense here.
.{ .call, .d, .rel32, .none, .none, .none, &.{ 0xe8 }, 0, .none },
.{ .call, .m, .rm64, .none, .none, .none, &.{ 0xff }, 2, .none },
diff --git a/src/codegen.zig b/src/codegen.zig
index a91795841c..c48200e845 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -608,7 +608,6 @@ pub fn generateSymbol(
const payload_type = typed_value.ty.optionalChild(&opt_buf);
const is_pl = !typed_value.val.isNull();
const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow;
- const offset = abi_size - (math.cast(usize, payload_type.abiSize(target)) orelse return error.Overflow);
if (!payload_type.hasRuntimeBits()) {
try code.writer().writeByteNTimes(@boolToInt(is_pl), abi_size);
@@ -639,8 +638,8 @@ pub fn generateSymbol(
return Result.ok;
}
+ const padding = abi_size - (math.cast(usize, payload_type.abiSize(target)) orelse return error.Overflow) - 1;
const value = if (typed_value.val.castTag(.opt_payload)) |payload| payload.data else Value.initTag(.undef);
- try code.writer().writeByteNTimes(@boolToInt(is_pl), offset);
switch (try generateSymbol(bin_file, src_loc, .{
.ty = payload_type,
.val = value,
@@ -648,6 +647,8 @@ pub fn generateSymbol(
.ok => {},
.fail => |em| return Result{ .fail = em },
}
+ try code.writer().writeByte(@boolToInt(is_pl));
+ try code.writer().writeByteNTimes(0, padding);
return Result.ok;
},
diff --git a/test/behavior/bugs/12984.zig b/test/behavior/bugs/12984.zig
index fec32947c9..75f2747eda 100644
--- a/test/behavior/bugs/12984.zig
+++ b/test/behavior/bugs/12984.zig
@@ -14,7 +14,6 @@ pub const CustomDraw = DeleagateWithContext(fn (?OnConfirm) void);
test "simple test" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
var c: CustomDraw = undefined;
_ = c;
diff --git a/test/behavior/bugs/13785.zig b/test/behavior/bugs/13785.zig
index d0cced6a79..463cdbec68 100644
--- a/test/behavior/bugs/13785.zig
+++ b/test/behavior/bugs/13785.zig
@@ -3,7 +3,6 @@ const std = @import("std");
const S = packed struct { a: u0 = 0 };
test {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/call.zig b/test/behavior/call.zig
index b51a459932..ab947f69dd 100644
--- a/test/behavior/call.zig
+++ b/test/behavior/call.zig
@@ -329,7 +329,6 @@ test "inline call preserves tail call" {
test "inline call doesn't re-evaluate non generic struct" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const S = struct {
fn foo(f: struct { a: u8, b: u8 }) !void {
diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig
index 275533d6ec..e601385bca 100644
--- a/test/behavior/cast.zig
+++ b/test/behavior/cast.zig
@@ -1206,7 +1206,6 @@ fn cast128Float(x: u128) f128 {
test "implicit cast from *[N]T to ?[*]T" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
var x: ?[*]u16 = null;
diff --git a/test/behavior/error.zig b/test/behavior/error.zig
index 294b4ac2eb..8119a10028 100644
--- a/test/behavior/error.zig
+++ b/test/behavior/error.zig
@@ -451,7 +451,6 @@ test "optional error set is the same size as error set" {
}
test "nested catch" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/if.zig b/test/behavior/if.zig
index 6632cdd5c2..948629038b 100644
--- a/test/behavior/if.zig
+++ b/test/behavior/if.zig
@@ -130,7 +130,6 @@ test "if peer expressions inferred optional type" {
}
test "if-else expression with runtime condition result location is inferred optional" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/null.zig b/test/behavior/null.zig
index c78a995833..6ef51cf3bd 100644
--- a/test/behavior/null.zig
+++ b/test/behavior/null.zig
@@ -29,7 +29,6 @@ test "optional type" {
}
test "test maybe object and get a pointer to the inner value" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -138,7 +137,6 @@ test "optional pointer to 0 bit type null value at runtime" {
}
test "if var maybe pointer" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig
index bbcc5b3ce6..95b39f2170 100644
--- a/test/behavior/optional.zig
+++ b/test/behavior/optional.zig
@@ -91,7 +91,6 @@ test "address of unwrap optional" {
test "nested optional field in struct" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const S2 = struct {
@@ -109,7 +108,6 @@ test "nested optional field in struct" {
test "equality compare optional with non-optional" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
try test_cmp_optional_non_optional();
@@ -227,7 +225,6 @@ test "assigning to an unwrapped optional field in an inline loop" {
}
test "coerce an anon struct literal to optional struct" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -247,7 +244,6 @@ test "coerce an anon struct literal to optional struct" {
}
test "0-bit child type coerced to optional return ptr result location" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -299,7 +295,6 @@ test "0-bit child type coerced to optional" {
}
test "array of optional unaligned types" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -336,7 +331,6 @@ test "array of optional unaligned types" {
}
test "optional pointer to zero bit optional payload" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -450,7 +444,6 @@ test "Optional slice size is optimized" {
test "peer type resolution in nested if expressions" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const Thing = struct { n: i32 };
var a = false;
diff --git a/test/behavior/ptrcast.zig b/test/behavior/ptrcast.zig
index 845ea3751e..becdee6b05 100644
--- a/test/behavior/ptrcast.zig
+++ b/test/behavior/ptrcast.zig
@@ -18,7 +18,6 @@ fn testReinterpretBytesAsInteger() !void {
}
test "reinterpret an array over multiple elements, with no well-defined layout" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig
index 2a1acebc0f..b250b5b087 100644
--- a/test/behavior/struct.zig
+++ b/test/behavior/struct.zig
@@ -1149,7 +1149,6 @@ test "anon init through error unions and optionals" {
}
test "anon init through optional" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -1456,7 +1455,6 @@ test "struct has only one reference" {
test "no dependency loop on pointer to optional struct" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const S = struct {
const A = struct { b: B };
@@ -1509,7 +1507,6 @@ test "no dependency loop on optional field wrapped in generic function" {
}
test "optional field init with tuple" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig
index 79db21424e..3f557bc40e 100644
--- a/test/behavior/tuple.zig
+++ b/test/behavior/tuple.zig
@@ -263,7 +263,6 @@ test "initializing anon struct with mixed comptime-runtime fields" {
test "tuple in tuple passed to generic function" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const S = struct {
@@ -283,7 +282,6 @@ test "tuple in tuple passed to generic function" {
test "coerce tuple to tuple" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const T = std.meta.Tuple(&.{u8});
@@ -298,7 +296,6 @@ test "coerce tuple to tuple" {
test "tuple type with void field" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const T = std.meta.Tuple(&[_]type{void});
const x = T{{}};
@@ -335,7 +332,6 @@ test "zero sized struct in tuple handled correctly" {
test "tuple type with void field and a runtime field" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const T = std.meta.Tuple(&[_]type{ usize, void });
var t: T = .{ 5, {} };
diff --git a/test/behavior/union.zig b/test/behavior/union.zig
index 9b49f8bf47..3b040fcba9 100644
--- a/test/behavior/union.zig
+++ b/test/behavior/union.zig
@@ -1227,7 +1227,6 @@ test "union tag is set when initiated as a temporary value at runtime" {
}
test "extern union most-aligned field is smaller" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/while.zig b/test/behavior/while.zig
index 956aa30f7b..fc3c6e85d8 100644
--- a/test/behavior/while.zig
+++ b/test/behavior/while.zig
@@ -341,7 +341,6 @@ test "else continue outer while" {
}
test "try terminating an infinite loop" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
From 958c8e1ce97671bcd7dc5b2dd9ddc1b87d0d1196 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sun, 19 Mar 2023 08:26:05 -0400
Subject: [PATCH 057/216] x86_64: implement @popCount for older processors
This fixes the behavior tests when compiled for baseline.
---
src/arch/x86_64/CodeGen.zig | 105 ++++++++++++++++++++++++++++++++----
src/arch/x86_64/bits.zig | 1 +
2 files changed, 95 insertions(+), 11 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index f788dbd531..cbc645eb9d 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -2771,29 +2771,112 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result = result: {
+ const result: MCValue = result: {
if (self.liveness.isUnused(inst)) break :result .dead;
- const op_ty = self.air.typeOf(ty_op.operand);
+ const src_ty = self.air.typeOf(ty_op.operand);
+ const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
+ const src_mcv = try self.resolveInst(ty_op.operand);
if (Target.x86.featureSetHas(self.target.cpu.features, .popcnt)) {
- const op_mcv = try self.resolveInst(ty_op.operand);
- const mat_op_mcv = switch (op_mcv) {
- .immediate => MCValue{ .register = try self.copyToTmpRegister(op_ty, op_mcv) },
- else => op_mcv,
+ const mat_src_mcv = switch (src_mcv) {
+ .immediate => MCValue{ .register = try self.copyToTmpRegister(src_ty, src_mcv) },
+ else => src_mcv,
};
- const mat_op_lock = switch (mat_op_mcv) {
+ const mat_src_lock = switch (mat_src_mcv) {
.register => |reg| self.register_manager.lockReg(reg),
else => null,
};
- defer if (mat_op_lock) |lock| self.register_manager.unlockReg(lock);
+ defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);
- const dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, gp) };
- try self.genBinOpMir(.popcnt, op_ty, dst_mcv, mat_op_mcv);
+ const dst_mcv: MCValue = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ src_mcv
+ else
+ .{ .register = try self.register_manager.allocReg(inst, gp) };
+
+ const popcnt_ty = if (src_abi_size > 1) src_ty else Type.u16;
+ try self.genBinOpMir(.popcnt, popcnt_ty, dst_mcv, mat_src_mcv);
break :result dst_mcv;
}
- return self.fail("TODO implement airPopcount for {}", .{op_ty.fmt(self.bin_file.options.module.?)});
+ const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - src_abi_size * 8);
+ const imm_0_1 = Immediate.u(mask / 0b1_1);
+ const imm_00_11 = Immediate.u(mask / 0b01_01);
+ const imm_0000_1111 = Immediate.u(mask / 0b0001_0001);
+ const imm_0000_0001 = Immediate.u(mask / 0b1111_1111);
+
+ const tmp_reg = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ src_mcv.register
+ else
+ try self.copyToTmpRegister(src_ty, src_mcv);
+ const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
+ defer self.register_manager.unlockReg(tmp_lock);
+
+ const dst_reg = try self.register_manager.allocReg(inst, gp);
+ const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
+ defer self.register_manager.unlockReg(dst_lock);
+
+ {
+ const dst = registerAlias(dst_reg, src_abi_size);
+ const tmp = registerAlias(tmp_reg, src_abi_size);
+ const imm = if (src_abi_size > 4)
+ try self.register_manager.allocReg(null, gp)
+ else
+ undefined;
+
+ // tmp = operand
+ try self.asmRegisterRegister(.mov, dst, tmp);
+ // dst = operand
+ try self.asmRegisterImmediate(.shr, tmp, Immediate.u(1));
+ // tmp = operand >> 1
+ if (src_abi_size > 4) {
+ try self.asmRegisterImmediate(.mov, imm, imm_0_1);
+ try self.asmRegisterRegister(.@"and", tmp, imm);
+ } else try self.asmRegisterImmediate(.@"and", tmp, imm_0_1);
+ // tmp = (operand >> 1) & 0x55...55
+ try self.asmRegisterRegister(.sub, dst, tmp);
+ // dst = temp1 = operand - ((operand >> 1) & 0x55...55)
+ try self.asmRegisterRegister(.mov, tmp, dst);
+ // tmp = temp1
+ try self.asmRegisterImmediate(.shr, dst, Immediate.u(2));
+ // dst = temp1 >> 2
+ if (src_abi_size > 4) {
+ try self.asmRegisterImmediate(.mov, imm, imm_00_11);
+ try self.asmRegisterRegister(.@"and", tmp, imm);
+ try self.asmRegisterRegister(.@"and", dst, imm);
+ } else {
+ try self.asmRegisterImmediate(.@"and", tmp, imm_00_11);
+ try self.asmRegisterImmediate(.@"and", dst, imm_00_11);
+ }
+ // tmp = temp1 & 0x33...33
+ // dst = (temp1 >> 2) & 0x33...33
+ try self.asmRegisterRegister(.add, tmp, dst);
+ // tmp = temp2 = (temp1 & 0x33...33) + ((temp1 >> 2) & 0x33...33)
+ try self.asmRegisterRegister(.mov, dst, tmp);
+ // dst = temp2
+ try self.asmRegisterImmediate(.shr, tmp, Immediate.u(4));
+ // tmp = temp2 >> 4
+ try self.asmRegisterRegister(.add, dst, tmp);
+ // dst = temp2 + (temp2 >> 4)
+ if (src_abi_size > 4) {
+ try self.asmRegisterImmediate(.mov, imm, imm_0000_1111);
+ try self.asmRegisterImmediate(.mov, tmp, imm_0000_0001);
+ try self.asmRegisterRegister(.@"and", dst, imm);
+ try self.asmRegisterRegister(.imul, dst, tmp);
+ } else {
+ try self.asmRegisterImmediate(.@"and", dst, imm_0000_1111);
+ if (src_abi_size > 1) {
+ try self.asmRegisterRegisterImmediate(.imul, dst, dst, imm_0000_0001);
+ }
+ }
+ // dst = temp3 = (temp2 + (temp2 >> 4)) & 0x0f...0f
+ // dst = temp3 * 0x01...01
+ if (src_abi_size > 1) {
+ try self.asmRegisterImmediate(.shr, dst, Immediate.u((src_abi_size - 1) * 8));
+ }
+ // dst = (temp3 * 0x01...01) >> (bits - 8)
+ }
+ break :result .{ .register = dst_reg };
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig
index 48a3c64093..250eedeafc 100644
--- a/src/arch/x86_64/bits.zig
+++ b/src/arch/x86_64/bits.zig
@@ -476,6 +476,7 @@ pub const Memory = union(enum) {
base: ?Register = null,
scale_index: ?ScaleIndex = null,
}) Memory {
+ if (args.scale_index) |si| assert(std.math.isPowerOfTwo(si.scale));
return .{ .sib = .{
.base = args.base,
.disp = args.disp,
From 6c453dd806d9a0207b1f1e64adfc38eca0c38f16 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sun, 19 Mar 2023 09:43:07 -0400
Subject: [PATCH 058/216] x86_64: implement some slice ops
---
src/arch/x86_64/CodeGen.zig | 68 +++++++++++++++++++++++++++++--------
1 file changed, 54 insertions(+), 14 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index cbc645eb9d..8e1beed798 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -2089,9 +2089,12 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
defer self.register_manager.unlockReg(src_lock);
const dst_ty = self.air.typeOfIndex(inst);
- const dst_reg = try self.register_manager.allocReg(inst, gp);
- const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
- defer self.register_manager.unlockReg(dst_lock);
+ const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ src_reg
+ else
+ try self.register_manager.allocReg(inst, gp);
+ const dst_lock = self.register_manager.lockReg(dst_reg);
+ defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
const eu_ty = src_ty.childType();
const pl_ty = eu_ty.errorUnionPayload();
@@ -2133,9 +2136,12 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
if (self.liveness.isUnused(inst)) break :result .dead;
const dst_ty = self.air.typeOfIndex(inst);
- const dst_reg = try self.register_manager.allocReg(inst, gp);
- const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
- defer self.register_manager.unlockReg(dst_lock);
+ const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ src_reg
+ else
+ try self.register_manager.allocReg(inst, gp);
+ const dst_lock = self.register_manager.lockReg(dst_reg);
+ defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
const pl_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*));
const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
@@ -2309,19 +2315,53 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement ptr_slice_len_ptr for {}", .{self.target.cpu.arch});
+ const result: MCValue = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const src_ty = self.air.typeOf(ty_op.operand);
+ const src_mcv = try self.resolveInst(ty_op.operand);
+ const src_reg = switch (src_mcv) {
+ .register => |reg| reg,
+ else => try self.copyToTmpRegister(src_ty, src_mcv),
+ };
+ const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
+ defer self.register_manager.unlockReg(src_lock);
+
+ const dst_ty = self.air.typeOfIndex(inst);
+ const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ src_reg
+ else
+ try self.register_manager.allocReg(inst, gp);
+ const dst_lock = self.register_manager.lockReg(dst_reg);
+ defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
+ try self.asmRegisterMemory(
+ .lea,
+ registerAlias(dst_reg, dst_abi_size),
+ Memory.sib(.qword, .{
+ .base = src_reg,
+ .disp = @divExact(self.target.cpu.arch.ptrBitWidth(), 8),
+ }),
+ );
+ break :result .{ .register = dst_reg };
+ };
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{self.target.cpu.arch});
+ const result: MCValue = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const dst_ty = self.air.typeOfIndex(inst);
+ const opt_mcv = try self.resolveInst(ty_op.operand);
+
+ break :result if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv))
+ opt_mcv
+ else
+ try self.copyToRegisterWithInstTracking(inst, dst_ty, opt_mcv);
+ };
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
From 3f4569bf187bfe296323aee6fbb59ab374041243 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sun, 19 Mar 2023 22:43:59 -0400
Subject: [PATCH 059/216] codegen: fix backend breakage due to optional layout
change
---
src/arch/aarch64/CodeGen.zig | 82 ++++++++++++++++++++----------------
src/arch/wasm/CodeGen.zig | 49 ++++++++-------------
test/behavior/error.zig | 1 +
3 files changed, 65 insertions(+), 67 deletions(-)
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig
index e20cf900af..e2e2ce9ead 100644
--- a/src/arch/aarch64/CodeGen.zig
+++ b/src/arch/aarch64/CodeGen.zig
@@ -3011,41 +3011,16 @@ fn optionalPayload(self: *Self, inst: Air.Inst.Index, mcv: MCValue, optional_ty:
return MCValue{ .register = reg };
}
- const offset = @intCast(u32, optional_ty.abiSize(self.target.*) - payload_ty.abiSize(self.target.*));
switch (mcv) {
- .register => |source_reg| {
+ .register => {
// TODO should we reuse the operand here?
const raw_reg = try self.register_manager.allocReg(inst, gp);
const dest_reg = raw_reg.toX();
- const shift = @intCast(u6, offset * 8);
- if (shift == 0) {
- try self.genSetReg(payload_ty, dest_reg, mcv);
- } else {
- _ = try self.addInst(.{
- .tag = if (payload_ty.isSignedInt())
- Mir.Inst.Tag.asr_immediate
- else
- Mir.Inst.Tag.lsr_immediate,
- .data = .{ .rr_shift = .{
- .rd = dest_reg,
- .rn = source_reg.toX(),
- .shift = shift,
- } },
- });
- }
-
+ try self.genSetReg(payload_ty, dest_reg, mcv);
return MCValue{ .register = self.registerAlias(dest_reg, payload_ty) };
},
- .stack_argument_offset => |off| {
- return MCValue{ .stack_argument_offset = off + offset };
- },
- .stack_offset => |off| {
- return MCValue{ .stack_offset = off - offset };
- },
- .memory => |addr| {
- return MCValue{ .memory = addr + offset };
- },
+ .stack_argument_offset, .stack_offset, .memory => return mcv,
else => unreachable, // invalid MCValue for an error union
}
}
@@ -3289,12 +3264,11 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
const optional_abi_size = @intCast(u32, optional_ty.abiSize(self.target.*));
const optional_abi_align = optional_ty.abiAlignment(self.target.*);
- const payload_abi_size = @intCast(u32, payload_ty.abiSize(self.target.*));
- const offset = optional_abi_size - payload_abi_size;
+ const offset = @intCast(u32, payload_ty.abiSize(self.target.*));
const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst);
- try self.genSetStack(Type.bool, stack_offset, .{ .immediate = 1 });
- try self.genSetStack(payload_ty, stack_offset - @intCast(u32, offset), operand);
+ try self.genSetStack(payload_ty, stack_offset, operand);
+ try self.genSetStack(Type.bool, stack_offset - offset, .{ .immediate = 1 });
break :result MCValue{ .stack_offset = stack_offset };
};
@@ -4834,13 +4808,49 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
}
fn isNull(self: *Self, operand_bind: ReadArg.Bind, operand_ty: Type) !MCValue {
- const sentinel_ty: Type = if (!operand_ty.isPtrLikeOptional()) blk: {
+ const sentinel: struct { ty: Type, bind: ReadArg.Bind } = if (!operand_ty.isPtrLikeOptional()) blk: {
var buf: Type.Payload.ElemType = undefined;
const payload_ty = operand_ty.optionalChild(&buf);
- break :blk if (payload_ty.hasRuntimeBitsIgnoreComptime()) Type.bool else operand_ty;
- } else operand_ty;
+ if (!payload_ty.hasRuntimeBitsIgnoreComptime())
+ break :blk .{ .ty = operand_ty, .bind = operand_bind };
+
+ const offset = @intCast(u32, payload_ty.abiSize(self.target.*));
+ const operand_mcv = try operand_bind.resolveToMcv(self);
+ const new_mcv: MCValue = switch (operand_mcv) {
+ .register => |source_reg| new: {
+ // TODO should we reuse the operand here?
+ const raw_reg = try self.register_manager.allocReg(null, gp);
+ const dest_reg = raw_reg.toX();
+
+ const shift = @intCast(u6, offset * 8);
+ if (shift == 0) {
+ try self.genSetReg(payload_ty, dest_reg, operand_mcv);
+ } else {
+ _ = try self.addInst(.{
+ .tag = if (payload_ty.isSignedInt())
+ Mir.Inst.Tag.asr_immediate
+ else
+ Mir.Inst.Tag.lsr_immediate,
+ .data = .{ .rr_shift = .{
+ .rd = dest_reg,
+ .rn = source_reg.toX(),
+ .shift = shift,
+ } },
+ });
+ }
+
+ break :new .{ .register = self.registerAlias(dest_reg, payload_ty) };
+ },
+ .stack_argument_offset => |off| .{ .stack_argument_offset = off + offset },
+ .stack_offset => |off| .{ .stack_offset = off - offset },
+ .memory => |addr| .{ .memory = addr + offset },
+ else => unreachable, // invalid MCValue for an optional
+ };
+
+ break :blk .{ .ty = Type.bool, .bind = .{ .mcv = new_mcv } };
+ } else .{ .ty = operand_ty, .bind = operand_bind };
const imm_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = 0 } };
- return self.cmp(operand_bind, imm_bind, sentinel_ty, .eq);
+ return self.cmp(sentinel.bind, imm_bind, sentinel.ty, .eq);
}
fn isNonNull(self: *Self, operand_bind: ReadArg.Bind, operand_ty: Type) !MCValue {
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index c05f07a602..9af66eb40c 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -2715,20 +2715,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, ptr_child_ty: Type) InnerError
},
.opt_payload_ptr => {
const payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
- const parent_ptr = try func.lowerParentPtr(payload_ptr.container_ptr, payload_ptr.container_ty);
- var buf: Type.Payload.ElemType = undefined;
- const payload_ty = payload_ptr.container_ty.optionalChild(&buf);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime() or payload_ty.optionalReprIsPayload()) {
- return parent_ptr;
- }
-
- const abi_size = payload_ptr.container_ty.abiSize(func.target);
- const offset = abi_size - payload_ty.abiSize(func.target);
-
- return WValue{ .memory_offset = .{
- .pointer = parent_ptr.memory,
- .offset = @intCast(u32, offset),
- } };
+ return func.lowerParentPtr(payload_ptr.container_ptr, payload_ptr.container_ty);
},
else => |tag| return func.fail("TODO: Implement lowerParentPtr for tag: {}", .{tag}),
}
@@ -2889,7 +2876,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
}
} else {
const is_pl = val.tag() == .opt_payload;
- return WValue{ .imm32 = if (is_pl) @as(u32, 1) else 0 };
+ return WValue{ .imm32 = @boolToInt(is_pl) };
},
.Struct => {
const struct_obj = ty.castTag(.@"struct").?.data;
@@ -3882,7 +3869,11 @@ fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcod
// When payload is zero-bits, we can treat operand as a value, rather than
// a pointer to the stack value
if (payload_ty.hasRuntimeBitsIgnoreComptime()) {
- try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset(), .alignment = 1 });
+ const offset = std.math.cast(u32, payload_ty.abiSize(func.target)) orelse {
+ const module = func.bin_file.base.options.module.?;
+ return func.fail("Optional type {} too big to fit into stack frame", .{optional_ty.fmt(module)});
+ };
+ try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset() + offset, .alignment = 1 });
}
} else if (payload_ty.isSlice()) {
switch (func.arch()) {
@@ -3911,13 +3902,11 @@ fn airOptionalPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const operand = try func.resolveInst(ty_op.operand);
if (opt_ty.optionalReprIsPayload()) break :result func.reuseOperand(ty_op.operand, operand);
- const offset = opt_ty.abiSize(func.target) - payload_ty.abiSize(func.target);
-
if (isByRef(payload_ty, func.target)) {
- break :result try func.buildPointerOffset(operand, offset, .new);
+ break :result try func.buildPointerOffset(operand, 0, .new);
}
- const payload = try func.load(operand, payload_ty, @intCast(u32, offset));
+ const payload = try func.load(operand, payload_ty, 0);
break :result try payload.toLocal(func, payload_ty);
};
func.finishAir(inst, result, &.{ty_op.operand});
@@ -3936,8 +3925,7 @@ fn airOptionalPayloadPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
break :result func.reuseOperand(ty_op.operand, operand);
}
- const offset = opt_ty.abiSize(func.target) - payload_ty.abiSize(func.target);
- break :result try func.buildPointerOffset(operand, offset, .new);
+ break :result try func.buildPointerOffset(operand, 0, .new);
};
func.finishAir(inst, result, &.{ty_op.operand});
}
@@ -3956,16 +3944,16 @@ fn airOptionalPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi
return func.finishAir(inst, operand, &.{ty_op.operand});
}
- const offset = std.math.cast(u32, opt_ty.abiSize(func.target) - payload_ty.abiSize(func.target)) orelse {
+ const offset = std.math.cast(u32, payload_ty.abiSize(func.target)) orelse {
const module = func.bin_file.base.options.module.?;
return func.fail("Optional type {} too big to fit into stack frame", .{opt_ty.fmt(module)});
};
try func.emitWValue(operand);
try func.addImm32(1);
- try func.addMemArg(.i32_store8, .{ .offset = operand.offset(), .alignment = 1 });
+ try func.addMemArg(.i32_store8, .{ .offset = operand.offset() + offset, .alignment = 1 });
- const result = try func.buildPointerOffset(operand, offset, .new);
+ const result = try func.buildPointerOffset(operand, 0, .new);
return func.finishAir(inst, result, &.{ty_op.operand});
}
@@ -3988,7 +3976,7 @@ fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
if (op_ty.optionalReprIsPayload()) {
break :result func.reuseOperand(ty_op.operand, operand);
}
- const offset = std.math.cast(u32, op_ty.abiSize(func.target) - payload_ty.abiSize(func.target)) orelse {
+ const offset = std.math.cast(u32, payload_ty.abiSize(func.target)) orelse {
const module = func.bin_file.base.options.module.?;
return func.fail("Optional type {} too big to fit into stack frame", .{op_ty.fmt(module)});
};
@@ -3997,9 +3985,9 @@ fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const result_ptr = try func.allocStack(op_ty);
try func.emitWValue(result_ptr);
try func.addImm32(1);
- try func.addMemArg(.i32_store8, .{ .offset = result_ptr.offset(), .alignment = 1 });
+ try func.addMemArg(.i32_store8, .{ .offset = result_ptr.offset() + offset, .alignment = 1 });
- const payload_ptr = try func.buildPointerOffset(result_ptr, offset, .new);
+ const payload_ptr = try func.buildPointerOffset(result_ptr, 0, .new);
try func.store(payload_ptr, operand, payload_ty, 0);
break :result result_ptr;
};
@@ -4719,7 +4707,6 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op:
assert(op == .eq or op == .neq);
var buf: Type.Payload.ElemType = undefined;
const payload_ty = operand_ty.optionalChild(&buf);
- const offset = @intCast(u32, operand_ty.abiSize(func.target) - payload_ty.abiSize(func.target));
// We store the final result in here that will be validated
// if the optional is truly equal.
@@ -4732,8 +4719,8 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op:
try func.addTag(.i32_ne); // inverse so we can exit early
try func.addLabel(.br_if, 0);
- _ = try func.load(lhs, payload_ty, offset);
- _ = try func.load(rhs, payload_ty, offset);
+ _ = try func.load(lhs, payload_ty, 0);
+ _ = try func.load(rhs, payload_ty, 0);
const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, func.target) });
try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));
try func.addLabel(.br_if, 0);
diff --git a/test/behavior/error.zig b/test/behavior/error.zig
index 8119a10028..a708971a49 100644
--- a/test/behavior/error.zig
+++ b/test/behavior/error.zig
@@ -874,6 +874,7 @@ test "field access of anyerror results in smaller error set" {
}
test "optional error union return type" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const S = struct {
From f316cb29cc094c37be191f1eb72ee70eb0dc99ee Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Mon, 20 Mar 2023 06:22:38 -0400
Subject: [PATCH 060/216] x86_64: implement atomic and fence ops
---
src/arch/x86_64/CodeGen.zig | 337 +++++++++++++++++++++--------
src/arch/x86_64/Emit.zig | 105 +++++++--
src/arch/x86_64/Encoding.zig | 15 +-
src/arch/x86_64/Mir.zig | 42 +++-
src/arch/x86_64/encoder.zig | 3 +-
src/arch/x86_64/encodings.zig | 38 ++++
src/register_manager.zig | 40 ++--
test/behavior/atomics.zig | 7 -
test/behavior/bugs/13068.zig | 1 -
test/behavior/cast.zig | 1 -
test/behavior/merge_error_sets.zig | 1 -
test/behavior/switch.zig | 1 -
12 files changed, 436 insertions(+), 155 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 8e1beed798..f32eb84afc 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -410,6 +410,25 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
});
}
+fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {
+ _ = try self.addInst(.{
+ .tag = .setcc,
+ .ops = switch (m) {
+ .sib => .m_sib_cc,
+ .rip => .m_rip_cc,
+ else => unreachable,
+ },
+ .data = .{ .x_cc = .{
+ .payload = switch (m) {
+ .sib => try self.addExtra(Mir.MemorySib.encode(m)),
+ .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+ else => unreachable,
+ },
+ .cc = cc,
+ } },
+ });
+}
+
fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
_ = try self.addInst(.{
.tag = .cmovcc,
@@ -890,7 +909,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.breakpoint => try self.airBreakpoint(),
.ret_addr => try self.airRetAddr(inst),
.frame_addr => try self.airFrameAddress(inst),
- .fence => try self.airFence(),
+ .fence => try self.airFence(inst),
.cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.fptrunc => try self.airFptrunc(inst),
@@ -1880,13 +1899,17 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) {
switch (opt_mcv) {
.register => |reg| try self.truncateRegister(pl_ty, reg),
+ .register_overflow => |ro| try self.truncateRegister(pl_ty, ro.reg),
else => {},
}
break :result opt_mcv;
}
const pl_mcv = try self.allocRegOrMem(inst, true);
- try self.setRegOrMem(pl_ty, pl_mcv, opt_mcv);
+ try self.setRegOrMem(pl_ty, pl_mcv, switch (opt_mcv) {
+ else => opt_mcv,
+ .register_overflow => |ro| .{ .register = ro.reg },
+ });
break :result pl_mcv;
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
@@ -1969,8 +1992,14 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
},
.register => |reg| {
// TODO reuse operand
- const lock = self.register_manager.lockRegAssumeUnused(reg);
- defer self.register_manager.unlockReg(lock);
+ self.register_manager.getRegAssumeFree(.rcx, null);
+ const rcx_lock =
+ if (err_off > 0) self.register_manager.lockRegAssumeUnused(.rcx) else null;
+ defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const eu_lock = self.register_manager.lockReg(reg);
+ defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
+
const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
if (err_off > 0) {
const shift = @intCast(u6, err_off * 8);
@@ -2018,8 +2047,14 @@ fn genUnwrapErrorUnionPayloadMir(
},
.register => |reg| {
// TODO reuse operand
- const lock = self.register_manager.lockRegAssumeUnused(reg);
- defer self.register_manager.unlockReg(lock);
+ self.register_manager.getRegAssumeFree(.rcx, null);
+ const rcx_lock =
+ if (payload_off > 0) self.register_manager.lockRegAssumeUnused(.rcx) else null;
+ defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const eu_lock = self.register_manager.lockReg(reg);
+ defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
+
const result_reg: Register = if (maybe_inst) |inst|
(try self.copyToRegisterWithInstTracking(inst, err_union_ty, err_union)).register
else
@@ -3129,7 +3164,12 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
.none => unreachable,
.dead => unreachable,
.unreach => unreachable,
- .eflags => unreachable,
+ .eflags => |cc| {
+ try self.asmSetccMemory(Memory.sib(
+ Memory.PtrSize.fromSize(abi_size),
+ .{ .base = reg.to64(), .disp = 0 },
+ ), cc);
+ },
.undef => {
if (!self.wantSafety()) return; // The already existing value will do just fine.
switch (abi_size) {
@@ -3598,8 +3638,7 @@ fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shi
},
else => {},
}
- assert(self.register_manager.isRegFree(.rcx));
- try self.register_manager.getReg(.rcx, null);
+ self.register_manager.getRegAssumeFree(.rcx, null);
try self.genSetReg(Type.u8, .rcx, shift);
}
@@ -3639,8 +3678,7 @@ fn genShiftBinOp(
};
defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
- assert(self.register_manager.isRegFree(.rcx));
- try self.register_manager.getReg(.rcx, null);
+ self.register_manager.getRegAssumeFree(.rcx, null);
const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
defer self.register_manager.unlockReg(rcx_lock);
@@ -4230,7 +4268,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
.base = .rbp,
.disp = -off,
}),
- Immediate.u(@intCast(u32, imm)),
+ if (math.cast(i32, @bitCast(i64, imm))) |small|
+ Immediate.s(small)
+ else
+ Immediate.u(@intCast(u32, imm)),
);
},
64 => {
@@ -4506,9 +4547,14 @@ fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ .none, .none, .none });
}
-fn airFence(self: *Self) !void {
- return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});
- //return self.finishAirBookkeeping();
+fn airFence(self: *Self, inst: Air.Inst.Index) !void {
+ const order = self.air.instructions.items(.data)[inst].fence;
+ switch (order) {
+ .Unordered, .Monotonic => unreachable,
+ .Acquire, .Release, .AcqRel => {},
+ .SeqCst => try self.asmOpOnly(.mfence),
+ }
+ return self.finishAirBookkeeping();
}
fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
@@ -5075,6 +5121,11 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
}
fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MCValue {
+ switch (opt_mcv) {
+ .register_overflow => |ro| return .{ .eflags = ro.eflags.negate() },
+ else => {},
+ }
+
try self.spillEflagsIfOccupied();
self.eflags_inst = inst;
@@ -5196,8 +5247,13 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !
try self.genBinOpMir(.cmp, Type.anyerror, .{ .stack_offset = offset }, .{ .immediate = 0 });
},
.register => |reg| {
- const maybe_lock = self.register_manager.lockReg(reg);
- defer if (maybe_lock) |lock| self.register_manager.unlockReg(lock);
+ self.register_manager.getRegAssumeFree(.rcx, null);
+ const rcx_lock = if (err_off > 0) self.register_manager.lockRegAssumeUnused(.rcx) else null;
+ defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const eu_lock = self.register_manager.lockReg(reg);
+ defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
+
const tmp_reg = try self.copyToTmpRegister(ty, operand);
if (err_off > 0) {
const shift = @intCast(u6, err_off * 8);
@@ -5389,69 +5445,6 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ .none, .none, .none });
}
-fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u32 {
- const abi_size = @intCast(u32, ty.abiSize(self.target.*));
- switch (condition) {
- .none => unreachable,
- .undef => unreachable,
- .dead, .unreach => unreachable,
- .eflags => unreachable,
- .register => |cond_reg| {
- try self.spillEflagsIfOccupied();
-
- const cond_reg_lock = self.register_manager.lockReg(cond_reg);
- defer if (cond_reg_lock) |lock| self.register_manager.unlockReg(lock);
-
- switch (case) {
- .none => unreachable,
- .undef => unreachable,
- .dead, .unreach => unreachable,
- .immediate => |imm| try self.asmRegisterImmediate(
- .xor,
- registerAlias(cond_reg, abi_size),
- Immediate.u(imm),
- ),
- .register => |reg| try self.asmRegisterRegister(
- .xor,
- registerAlias(cond_reg, abi_size),
- registerAlias(reg, abi_size),
- ),
- .stack_offset => {
- if (abi_size <= 8) {
- const reg = try self.copyToTmpRegister(ty, case);
- return self.genCondSwitchMir(ty, condition, .{ .register = reg });
- }
-
- return self.fail("TODO implement switch mir when case is stack offset with abi larger than 8 bytes", .{});
- },
- else => {
- return self.fail("TODO implement switch mir when case is {}", .{case});
- },
- }
-
- const aliased_reg = registerAlias(cond_reg, abi_size);
- try self.asmRegisterRegister(.@"test", aliased_reg, aliased_reg);
- return self.asmJccReloc(undefined, .ne);
- },
- .stack_offset => {
- try self.spillEflagsIfOccupied();
-
- if (abi_size <= 8) {
- const reg = try self.copyToTmpRegister(ty, condition);
- const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
- defer self.register_manager.unlockReg(reg_lock);
- return self.genCondSwitchMir(ty, .{ .register = reg }, case);
- }
-
- return self.fail("TODO implement switch mir when condition is stack offset with abi larger than 8 bytes", .{});
- },
- else => {
- return self.fail("TODO implemenent switch mir when condition is {}", .{condition});
- },
- }
- return 0; // TODO
-}
-
fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const condition = try self.resolveInst(pl_op.operand);
@@ -5496,8 +5489,10 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
defer self.gpa.free(relocs);
for (items, relocs) |item, *reloc| {
+ try self.spillEflagsIfOccupied();
const item_mcv = try self.resolveInst(item);
- reloc.* = try self.genCondSwitchMir(condition_ty, condition, item_mcv);
+ try self.genBinOpMir(.cmp, condition_ty, condition, item_mcv);
+ reloc.* = try self.asmJccReloc(undefined, .ne);
}
// Capture the state of register and stack allocation state so that we can revert to it.
@@ -6624,26 +6619,184 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
- const extra = self.air.extraData(Air.Block, ty_pl.payload);
- _ = extra;
- return self.fail("TODO implement x86 airCmpxchg", .{});
- // return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
+ const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
+
+ const ptr_ty = self.air.typeOf(extra.ptr);
+ const ptr_mcv = try self.resolveInst(extra.ptr);
+ const val_ty = self.air.typeOf(extra.expected_value);
+
+ const exp_mcv = try self.resolveInst(extra.expected_value);
+ try self.genSetReg(val_ty, .rax, exp_mcv);
+ const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);
+ defer self.register_manager.unlockReg(rax_lock);
+
+ const new_mcv = try self.resolveInst(extra.new_value);
+ const new_reg = try self.copyToTmpRegister(val_ty, new_mcv);
+ const new_lock = self.register_manager.lockRegAssumeUnused(new_reg);
+ defer self.register_manager.unlockReg(new_lock);
+
+ const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
+ const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
+ const ptr_mem: Memory = switch (ptr_mcv) {
+ .register => |reg| Memory.sib(ptr_size, .{ .base = reg, .disp = 0 }),
+ .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),
+ else => Memory.sib(ptr_size, .{
+ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
+ .disp = 0,
+ }),
+ };
+ const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null;
+ defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
+
+ try self.spillEflagsIfOccupied();
+ _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
+ .r1 = new_reg,
+ .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
+ } } });
+
+ const result: MCValue = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ self.eflags_inst = inst;
+ break :result .{ .register_overflow = .{ .reg = .rax, .eflags = .ne } };
+ };
+ return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
+}
+
+fn atomicOp(
+ self: *Self,
+ dst_reg: Register,
+ ptr_mcv: MCValue,
+ val_mcv: MCValue,
+ ptr_ty: Type,
+ val_ty: Type,
+ unused: bool,
+ op: ?std.builtin.AtomicRmwOp,
+ order: std.builtin.AtomicOrder,
+) InnerError!void {
+ const dst_lock = self.register_manager.lockReg(dst_reg);
+ defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const ptr_lock = switch (ptr_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ else => null,
+ };
+ defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const val_lock = switch (val_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ else => null,
+ };
+ defer if (val_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
+ const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
+ const ptr_mem: Memory = switch (ptr_mcv) {
+ .register => |reg| Memory.sib(ptr_size, .{ .base = reg, .disp = 0 }),
+ .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),
+ else => Memory.sib(ptr_size, .{
+ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
+ .disp = 0,
+ }),
+ };
+ const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null;
+ defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
+
+ try self.genSetReg(val_ty, dst_reg, val_mcv);
+
+ const need_loop = val_ty.isRuntimeFloat() or if (op) |rmw| switch (rmw) {
+ .Xchg, .Add, .Sub => false,
+ .And, .Or, .Xor => !unused,
+ .Nand, .Max, .Min => true,
+ } else false;
+ if (!need_loop) {
+ const tag: Mir.Inst.Tag = if (op) |rmw| switch (rmw) {
+ .Xchg => if (unused) .mov else .xchg,
+ .Add => if (unused) .add else .xadd,
+ .Sub => if (unused) .sub else .xadd,
+ .And => .@"and",
+ .Or => .@"or",
+ .Xor => .xor,
+ else => unreachable,
+ } else switch (order) {
+ .Unordered, .Monotonic, .Release, .AcqRel => .mov,
+ .Acquire => unreachable,
+ .SeqCst => .xchg,
+ };
+ if (op == std.builtin.AtomicRmwOp.Sub and tag == .xadd) {
+ try self.genUnOpMir(.neg, val_ty, .{ .register = dst_reg });
+ }
+ _ = try self.addInst(.{ .tag = tag, .ops = switch (tag) {
+ .mov, .xchg => .mr_sib,
+ .xadd, .add, .sub, .@"and", .@"or", .xor => .lock_mr_sib,
+ else => unreachable,
+ }, .data = .{ .rx = .{
+ .r1 = registerAlias(dst_reg, val_abi_size),
+ .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
+ } } });
+ return;
+ }
+
+ return self.fail("TODO implement x86 atomic loop", .{});
}
fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {
- _ = inst;
- return self.fail("TODO implement x86 airAtomicRmw", .{});
+ const pl_op = self.air.instructions.items(.data)[inst].pl_op;
+ const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data;
+
+ const dst_reg = try self.register_manager.allocReg(inst, gp);
+
+ const ptr_ty = self.air.typeOf(pl_op.operand);
+ const ptr_mcv = try self.resolveInst(pl_op.operand);
+
+ const val_ty = self.air.typeOf(extra.operand);
+ const val_mcv = try self.resolveInst(extra.operand);
+
+ const unused = self.liveness.isUnused(inst);
+ try self.atomicOp(dst_reg, ptr_mcv, val_mcv, ptr_ty, val_ty, unused, extra.op(), extra.ordering());
+ const result: MCValue = if (unused) .dead else .{ .register = dst_reg };
+ return self.finishAir(inst, result, .{ pl_op.operand, extra.operand, .none });
}
fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void {
- _ = inst;
- return self.fail("TODO implement airAtomicLoad for {}", .{self.target.cpu.arch});
+ const atomic_load = self.air.instructions.items(.data)[inst].atomic_load;
+
+ const result: MCValue = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const ptr_ty = self.air.typeOf(atomic_load.ptr);
+ const ptr_mcv = try self.resolveInst(atomic_load.ptr);
+ const ptr_lock = switch (ptr_mcv) {
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ else => null,
+ };
+ defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const dst_mcv =
+ if (self.reuseOperand(inst, atomic_load.ptr, 0, ptr_mcv))
+ ptr_mcv
+ else
+ try self.allocRegOrMem(inst, true);
+
+ try self.load(dst_mcv, ptr_mcv, ptr_ty);
+ break :result dst_mcv;
+ };
+ return self.finishAir(inst, result, .{ atomic_load.ptr, .none, .none });
}
fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void {
- _ = inst;
- _ = order;
- return self.fail("TODO implement airAtomicStore for {}", .{self.target.cpu.arch});
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+
+ const dst_reg = try self.register_manager.allocReg(null, gp);
+
+ const ptr_ty = self.air.typeOf(bin_op.lhs);
+ const ptr_mcv = try self.resolveInst(bin_op.lhs);
+
+ const val_ty = self.air.typeOf(bin_op.rhs);
+ const val_mcv = try self.resolveInst(bin_op.rhs);
+
+ try self.atomicOp(dst_reg, ptr_mcv, val_mcv, ptr_ty, val_ty, true, null, order);
+ return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
}
fn airMemset(self: *Self, inst: Air.Inst.Index) !void {
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index 4c63385e6b..9718548736 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -87,6 +87,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.cdq,
.cqo,
.cmp,
+ .cmpxchg,
.div,
.fisttp,
.fld,
@@ -95,7 +96,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.int3,
.jmp,
.lea,
+ .lfence,
.lzcnt,
+ .mfence,
.mov,
.movzx,
.mul,
@@ -110,6 +113,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.sal,
.sar,
.sbb,
+ .sfence,
.shl,
.shr,
.sub,
@@ -117,6 +121,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.@"test",
.tzcnt,
.ud2,
+ .xadd,
+ .xchg,
.xor,
.addss,
@@ -148,6 +154,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.stos,
=> try emit.mirString(tag, inst),
+ .cmpxchgb => try emit.mirCmpxchgBytes(inst),
+
.jmp_reloc => try emit.mirJmpReloc(inst),
.call_extern => try emit.mirCallExtern(inst),
@@ -214,6 +222,20 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
const ops = emit.mir.instructions.items(.ops)[inst];
const data = emit.mir.instructions.items(.data)[inst];
+ const prefix: Instruction.Prefix = switch (ops) {
+ .lock_m_sib,
+ .lock_m_rip,
+ .lock_mi_u_sib,
+ .lock_mi_u_rip,
+ .lock_mi_s_sib,
+ .lock_mi_s_rip,
+ .lock_mr_sib,
+ .lock_mr_rip,
+ .lock_moffs_rax,
+ => .lock,
+ else => .none,
+ };
+
var op1: Instruction.Operand = .none;
var op2: Instruction.Operand = .none;
var op3: Instruction.Operand = .none;
@@ -252,35 +274,35 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
op2 = .{ .reg = data.rri.r2 };
op3 = .{ .imm = imm };
},
- .m_sib => {
+ .m_sib, .lock_m_sib => {
const msib = emit.mir.extraData(Mir.MemorySib, data.payload).data;
op1 = .{ .mem = Mir.MemorySib.decode(msib) };
},
- .m_rip => {
+ .m_rip, .lock_m_rip => {
const mrip = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
},
- .mi_s_sib, .mi_u_sib => {
+ .mi_s_sib, .mi_u_sib, .lock_mi_s_sib, .lock_mi_u_sib => {
const msib = emit.mir.extraData(Mir.MemorySib, data.xi.payload).data;
const imm = switch (ops) {
- .mi_s_sib => Immediate.s(@bitCast(i32, data.xi.imm)),
- .mi_u_sib => Immediate.u(data.xi.imm),
+ .mi_s_sib, .lock_mi_s_sib => Immediate.s(@bitCast(i32, data.xi.imm)),
+ .mi_u_sib, .lock_mi_u_sib => Immediate.u(data.xi.imm),
else => unreachable,
};
op1 = .{ .mem = Mir.MemorySib.decode(msib) };
op2 = .{ .imm = imm };
},
- .mi_u_rip, .mi_s_rip => {
+ .mi_u_rip, .mi_s_rip, .lock_mi_u_rip, .lock_mi_s_rip => {
const mrip = emit.mir.extraData(Mir.MemoryRip, data.xi.payload).data;
const imm = switch (ops) {
- .mi_s_rip => Immediate.s(@bitCast(i32, data.xi.imm)),
- .mi_u_rip => Immediate.u(data.xi.imm),
+ .mi_s_rip, .lock_mi_s_rip => Immediate.s(@bitCast(i32, data.xi.imm)),
+ .mi_u_rip, .lock_mi_u_rip => Immediate.u(data.xi.imm),
else => unreachable,
};
op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
op2 = .{ .imm = imm };
},
- .rm_sib, .mr_sib => {
+ .rm_sib, .mr_sib, .lock_mr_sib => {
const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data;
const op_r = .{ .reg = data.rx.r1 };
const op_m = .{ .mem = Mir.MemorySib.decode(msib) };
@@ -289,23 +311,23 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
op1 = op_r;
op2 = op_m;
},
- .mr_sib => {
+ .mr_sib, .lock_mr_sib => {
op1 = op_m;
op2 = op_r;
},
else => unreachable,
}
},
- .rm_rip, .mr_rip => {
+ .rm_rip, .mr_rip, .lock_mr_rip => {
const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data;
const op_r = .{ .reg = data.rx.r1 };
const op_m = .{ .mem = Mir.MemoryRip.decode(mrip) };
switch (ops) {
- .rm_sib => {
+ .rm_rip => {
op1 = op_r;
op2 = op_m;
},
- .mr_sib => {
+ .mr_rip, .lock_mr_rip => {
op1 = op_m;
op2 = op_r;
},
@@ -319,6 +341,7 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
}
return emit.encode(mnemonic, .{
+ .prefix = prefix,
.op1 = op1,
.op2 = op2,
.op3 = op3,
@@ -348,6 +371,39 @@ fn mirString(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!vo
}
}
+fn mirCmpxchgBytes(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+ const ops = emit.mir.instructions.items(.ops)[inst];
+ const data = emit.mir.instructions.items(.data)[inst];
+
+ var op1: Instruction.Operand = .none;
+ switch (ops) {
+ .m_sib, .lock_m_sib => {
+ const sib = emit.mir.extraData(Mir.MemorySib, data.payload).data;
+ op1 = .{ .mem = Mir.MemorySib.decode(sib) };
+ },
+ .m_rip, .lock_m_rip => {
+ const rip = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
+ op1 = .{ .mem = Mir.MemoryRip.decode(rip) };
+ },
+ else => unreachable,
+ }
+
+ const mnemonic: Instruction.Mnemonic = switch (op1.mem.bitSize()) {
+ 64 => .cmpxchg8b,
+ 128 => .cmpxchg16b,
+ else => unreachable,
+ };
+
+ return emit.encode(mnemonic, .{
+ .prefix = switch (ops) {
+ .m_sib, .m_rip => .none,
+ .lock_m_sib, .lock_m_rip => .lock,
+ else => unreachable,
+ },
+ .op1 = op1,
+ });
+}
+
fn mirMovMoffs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
const ops = emit.mir.instructions.items(.ops)[inst];
const payload = emit.mir.instructions.items(.data)[inst].payload;
@@ -361,8 +417,13 @@ fn mirMovMoffs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
.op2 = .{ .mem = Memory.moffs(seg, offset) },
});
},
- .moffs_rax => {
+ .moffs_rax, .lock_moffs_rax => {
try emit.encode(.mov, .{
+ .prefix = switch (ops) {
+ .moffs_rax => .none,
+ .lock_moffs_rax => .lock,
+ else => unreachable,
+ },
.op1 = .{ .mem = Memory.moffs(seg, offset) },
.op2 = .{ .reg = .rax },
});
@@ -455,6 +516,22 @@ fn mirSetcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
.op1 = .{ .reg = data.r1 },
});
},
+ .m_sib_cc => {
+ const data = emit.mir.instructions.items(.data)[inst].x_cc;
+ const extra = emit.mir.extraData(Mir.MemorySib, data.payload).data;
+ const mnemonic = mnemonicFromConditionCode("set", data.cc);
+ return emit.encode(mnemonic, .{
+ .op1 = .{ .mem = Mir.MemorySib.decode(extra) },
+ });
+ },
+ .m_rip_cc => {
+ const data = emit.mir.instructions.items(.data)[inst].x_cc;
+ const extra = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
+ const mnemonic = mnemonicFromConditionCode("set", data.cc);
+ return emit.encode(mnemonic, .{
+ .op1 = .{ .mem = Mir.MemoryRip.decode(extra) },
+ });
+ },
else => unreachable, // TODO
}
}
diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig
index 436202ca3e..03b8abf983 100644
--- a/src/arch/x86_64/Encoding.zig
+++ b/src/arch/x86_64/Encoding.zig
@@ -314,6 +314,7 @@ pub const Mnemonic = enum {
cmovnp, cmovns, cmovnz, cmovo, cmovp, cmovpe, cmovpo, cmovs, cmovz,
cmp,
cmps, cmpsb, cmpsd, cmpsq, cmpsw,
+ cmpxchg, cmpxchg8b, cmpxchg16b,
cqo, cwd, cwde,
div,
fisttp, fld,
@@ -321,10 +322,10 @@ pub const Mnemonic = enum {
ja, jae, jb, jbe, jc, jrcxz, je, jg, jge, jl, jle, jna, jnae, jnb, jnbe,
jnc, jne, jng, jnge, jnl, jnle, jno, jnp, jns, jnz, jo, jp, jpe, jpo, js, jz,
jmp,
- lea,
+ lea, lfence,
lods, lodsb, lodsd, lodsq, lodsw,
lzcnt,
- mov,
+ mfence, mov,
movs, movsb, movsd, movsq, movsw,
movsx, movsxd, movzx, mul,
neg, nop, not,
@@ -337,10 +338,11 @@ pub const Mnemonic = enum {
seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,
setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,
setnz, seto, setp, setpe, setpo, sets, setz,
+ sfence,
stos, stosb, stosd, stosq, stosw,
@"test", tzcnt,
ud2,
- xor,
+ xadd, xchg, xor,
// SSE
addss,
cmpss,
@@ -387,7 +389,7 @@ pub const Op = enum {
cl,
r8, r16, r32, r64,
rm8, rm16, rm32, rm64,
- m8, m16, m32, m64, m80,
+ m8, m16, m32, m64, m80, m128,
rel8, rel16, rel32,
m,
moffs,
@@ -436,6 +438,7 @@ pub const Op = enum {
32 => .m32,
64 => .m64,
80 => .m80,
+ 128 => .m128,
else => unreachable,
};
},
@@ -473,7 +476,7 @@ pub const Op = enum {
.imm32, .imm32s, .eax, .r32, .m32, .rm32, .rel32, .xmm_m32 => 32,
.imm64, .rax, .r64, .m64, .rm64, .xmm_m64 => 64,
.m80 => 80,
- .xmm => 128,
+ .m128, .xmm => 128,
};
}
@@ -520,7 +523,7 @@ pub const Op = enum {
// zig fmt: off
return switch (op) {
.rm8, .rm16, .rm32, .rm64,
- .m8, .m16, .m32, .m64, .m80,
+ .m8, .m16, .m32, .m64, .m80, .m128,
.m,
.xmm_m32, .xmm_m64,
=> true,
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index e7d75e7446..d086b617f5 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -66,6 +66,10 @@ pub const Inst = struct {
cqo,
/// Logical compare
cmp,
+ /// Compare and exchange
+ cmpxchg,
+ /// Compare and exchange bytes
+ cmpxchgb,
/// Unsigned division
div,
/// Store integer with truncation
@@ -82,8 +86,12 @@ pub const Inst = struct {
jmp,
/// Load effective address
lea,
+ /// Load fence
+ lfence,
/// Count the number of leading zero bits
lzcnt,
+ /// Memory fence
+ mfence,
/// Move
mov,
/// Move with sign extension
@@ -114,6 +122,8 @@ pub const Inst = struct {
sar,
/// Integer subtraction with borrow
sbb,
+ /// Store fence
+ sfence,
/// Logical shift left
shl,
/// Logical shift right
@@ -128,6 +138,10 @@ pub const Inst = struct {
tzcnt,
/// Undefined instruction
ud2,
+ /// Exchange and add
+ xadd,
+ /// Exchange register/memory with register
+ xchg,
/// Logical exclusive-or
xor,
@@ -242,10 +256,10 @@ pub const Inst = struct {
/// Uses `rri` payload.
rri_u,
/// Register with condition code (CC).
- /// Uses `r_c` payload.
+ /// Uses `r_cc` payload.
r_cc,
/// Register, register with condition code (CC).
- /// Uses `rr_c` payload.
+ /// Uses `rr_cc` payload.
rr_cc,
/// Register, immediate (sign-extended) operands.
/// Uses `ri` payload.
@@ -283,6 +297,12 @@ pub const Inst = struct {
/// Single memory (RIP) operand.
/// Uses `payload` with extra data of type `MemoryRip`.
m_rip,
+ /// Single memory (SIB) operand with condition code (CC).
+ /// Uses `x_cc` with extra data of type `MemorySib`.
+ m_sib_cc,
+ /// Single memory (RIP) operand with condition code (CC).
+ /// Uses `x_cc` with extra data of type `MemoryRip`.
+ m_rip_cc,
/// Memory (SIB), immediate (unsigned) operands.
/// Uses `xi` payload with extra data of type `MemorySib`.
mi_u_sib,
@@ -301,6 +321,12 @@ pub const Inst = struct {
/// Memory (RIP), register operands.
/// Uses `rx` payload with extra data of type `MemoryRip`.
mr_rip,
+ /// Rax, Memory moffs.
+ /// Uses `payload` with extra data of type `MemoryMoffs`.
+ rax_moffs,
+ /// Memory moffs, rax.
+ /// Uses `payload` with extra data of type `MemoryMoffs`.
+ moffs_rax,
/// Single memory (SIB) operand with lock prefix.
/// Uses `payload` with extra data of type `MemorySib`.
lock_m_sib,
@@ -325,12 +351,9 @@ pub const Inst = struct {
/// Memory (RIP), register operands with lock prefix.
/// Uses `rx` payload with extra data of type `MemoryRip`.
lock_mr_rip,
- /// Rax, Memory moffs.
+ /// Memory moffs, rax with lock prefix.
/// Uses `payload` with extra data of type `MemoryMoffs`.
- rax_moffs,
- /// Memory moffs, rax.
- /// Uses `payload` with extra data of type `MemoryMoffs`.
- moffs_rax,
+ lock_moffs_rax,
/// References another Mir instruction directly.
/// Uses `inst` payload.
inst,
@@ -381,6 +404,11 @@ pub const Inst = struct {
r2: Register,
imm: u32,
},
+ /// Condition code (CC), followed by custom payload found in extra.
+ x_cc: struct {
+ payload: u32,
+ cc: bits.Condition,
+ },
/// Register with condition code (CC).
r_cc: struct {
r1: Register,
diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig
index 2a2d6ea031..519158d012 100644
--- a/src/arch/x86_64/encoder.zig
+++ b/src/arch/x86_64/encoder.zig
@@ -117,7 +117,8 @@ pub const Instruction = struct {
pub fn new(mnemonic: Mnemonic, args: Init) !Instruction {
const encoding = (try Encoding.findByMnemonic(mnemonic, args)) orelse {
- log.debug("no encoding found for: {s} {s} {s} {s} {s}", .{
+ log.debug("no encoding found for: {s} {s} {s} {s} {s} {s}", .{
+ @tagName(args.prefix),
@tagName(mnemonic),
@tagName(Encoding.Op.fromOperand(args.op1)),
@tagName(Encoding.Op.fromOperand(args.op2)),
diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig
index ea21af2067..602718073d 100644
--- a/src/arch/x86_64/encodings.zig
+++ b/src/arch/x86_64/encodings.zig
@@ -252,6 +252,15 @@ pub const table = &[_]Entry{
.{ .cmpsd, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .none },
.{ .cmpsq, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .long },
+ .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .none },
+ .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .rex },
+ .{ .cmpxchg, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb1 }, 0, .rex },
+ .{ .cmpxchg, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb1 }, 0, .rex },
+ .{ .cmpxchg, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb1 }, 0, .long },
+
+ .{ .cmpxchg8b , .m, .m64, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .none },
+ .{ .cmpxchg16b, .m, .m128, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .long },
+
.{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .none },
.{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .rex },
.{ .div, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 6, .none },
@@ -328,6 +337,8 @@ pub const table = &[_]Entry{
.{ .lea, .rm, .r32, .m, .none, .none, &.{ 0x8d }, 0, .none },
.{ .lea, .rm, .r64, .m, .none, .none, &.{ 0x8d }, 0, .long },
+ .{ .lfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xe8 }, 0, .none },
+
.{ .lods, .np, .m8, .none, .none, .none, &.{ 0xac }, 0, .none },
.{ .lods, .np, .m16, .none, .none, .none, &.{ 0xad }, 0, .none },
.{ .lods, .np, .m32, .none, .none, .none, &.{ 0xad }, 0, .none },
@@ -341,6 +352,8 @@ pub const table = &[_]Entry{
.{ .lzcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },
.{ .lzcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .long },
+ .{ .mfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xf0 }, 0, .none },
+
.{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .none },
.{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .rex },
.{ .mov, .mr, .rm16, .r16, .none, .none, &.{ 0x89 }, 0, .none },
@@ -588,6 +601,8 @@ pub const table = &[_]Entry{
.{ .setz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .none },
.{ .setz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .rex },
+ .{ .sfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xf8 }, 0, .none },
+
.{ .shl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none },
.{ .shl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex },
.{ .shl, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none },
@@ -675,6 +690,29 @@ pub const table = &[_]Entry{
.{ .ud2, .np, .none, .none, .none, .none, &.{ 0x0f, 0x0b }, 0, .none },
+ .{ .xadd, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xc0 }, 0, .none },
+ .{ .xadd, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xc0 }, 0, .rex },
+ .{ .xadd, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xc1 }, 0, .none },
+ .{ .xadd, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xc1 }, 0, .none },
+ .{ .xadd, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xc1 }, 0, .long },
+
+ .{ .xchg, .o, .ax, .r16, .none, .none, &.{ 0x90 }, 0, .none },
+ .{ .xchg, .o, .r16, .ax, .none, .none, &.{ 0x90 }, 0, .none },
+ .{ .xchg, .o, .eax, .r32, .none, .none, &.{ 0x90 }, 0, .none },
+ .{ .xchg, .o, .rax, .r64, .none, .none, &.{ 0x90 }, 0, .long },
+ .{ .xchg, .o, .r32, .eax, .none, .none, &.{ 0x90 }, 0, .none },
+ .{ .xchg, .o, .r64, .rax, .none, .none, &.{ 0x90 }, 0, .long },
+ .{ .xchg, .mr, .rm8, .r8, .none, .none, &.{ 0x86 }, 0, .none },
+ .{ .xchg, .mr, .rm8, .r8, .none, .none, &.{ 0x86 }, 0, .rex },
+ .{ .xchg, .rm, .r8, .rm8, .none, .none, &.{ 0x86 }, 0, .none },
+ .{ .xchg, .rm, .r8, .rm8, .none, .none, &.{ 0x86 }, 0, .rex },
+ .{ .xchg, .mr, .rm16, .r16, .none, .none, &.{ 0x87 }, 0, .none },
+ .{ .xchg, .rm, .r16, .rm16, .none, .none, &.{ 0x87 }, 0, .none },
+ .{ .xchg, .mr, .rm32, .r32, .none, .none, &.{ 0x87 }, 0, .none },
+ .{ .xchg, .mr, .rm64, .r64, .none, .none, &.{ 0x87 }, 0, .long },
+ .{ .xchg, .rm, .r32, .rm32, .none, .none, &.{ 0x87 }, 0, .none },
+ .{ .xchg, .rm, .r64, .rm64, .none, .none, &.{ 0x87 }, 0, .long },
+
.{ .xor, .zi, .al, .imm8, .none, .none, &.{ 0x34 }, 0, .none },
.{ .xor, .zi, .ax, .imm16, .none, .none, &.{ 0x35 }, 0, .none },
.{ .xor, .zi, .eax, .imm32, .none, .none, &.{ 0x35 }, 0, .none },
diff --git a/src/register_manager.zig b/src/register_manager.zig
index 4d16348c27..713b669b06 100644
--- a/src/register_manager.zig
+++ b/src/register_manager.zig
@@ -305,40 +305,32 @@ pub fn RegisterManager(
pub fn getReg(self: *Self, reg: Register, inst: ?Air.Inst.Index) AllocateRegistersError!void {
const index = indexOfRegIntoTracked(reg) orelse return;
log.debug("getReg {} for inst {?}", .{ reg, inst });
- self.markRegAllocated(reg);
- if (inst) |tracked_inst|
- if (!self.isRegFree(reg)) {
- // Move the instruction that was previously there to a
- // stack allocation.
- const spilled_inst = self.registers[index];
- self.registers[index] = tracked_inst;
- try self.getFunction().spillInstruction(reg, spilled_inst);
- } else {
- self.getRegAssumeFree(reg, tracked_inst);
- }
- else {
- if (!self.isRegFree(reg)) {
- // Move the instruction that was previously there to a
- // stack allocation.
- const spilled_inst = self.registers[index];
- try self.getFunction().spillInstruction(reg, spilled_inst);
- self.freeReg(reg);
- }
- }
+ if (!self.isRegFree(reg)) {
+ self.markRegAllocated(reg);
+
+ // Move the instruction that was previously there to a
+ // stack allocation.
+ const spilled_inst = self.registers[index];
+ if (inst) |tracked_inst| self.registers[index] = tracked_inst;
+ try self.getFunction().spillInstruction(reg, spilled_inst);
+ if (inst == null) self.freeReg(reg);
+ } else self.getRegAssumeFree(reg, inst);
}
/// Allocates the specified register with the specified
/// instruction. Asserts that the register is free and no
/// spilling is necessary.
- pub fn getRegAssumeFree(self: *Self, reg: Register, inst: Air.Inst.Index) void {
+ pub fn getRegAssumeFree(self: *Self, reg: Register, inst: ?Air.Inst.Index) void {
const index = indexOfRegIntoTracked(reg) orelse return;
- log.debug("getRegAssumeFree {} for inst {}", .{ reg, inst });
+ log.debug("getRegAssumeFree {} for inst {?}", .{ reg, inst });
self.markRegAllocated(reg);
assert(self.isRegFree(reg));
- self.registers[index] = inst;
- self.markRegUsed(reg);
+ if (inst) |tracked_inst| {
+ self.registers[index] = tracked_inst;
+ self.markRegUsed(reg);
+ }
}
/// Marks the specified register as free
diff --git a/test/behavior/atomics.zig b/test/behavior/atomics.zig
index cf7c3b1503..a1e3af6e9a 100644
--- a/test/behavior/atomics.zig
+++ b/test/behavior/atomics.zig
@@ -33,7 +33,6 @@ fn testCmpxchg() !void {
test "fence" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
@@ -44,7 +43,6 @@ test "fence" {
test "atomicrmw and atomicload" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_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
@@ -73,7 +71,6 @@ fn testAtomicLoad(ptr: *u8) !void {
test "cmpxchg with ptr" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_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
@@ -162,7 +159,6 @@ test "cmpxchg on a global variable" {
test "atomic load and rmw with enum" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_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
@@ -180,7 +176,6 @@ test "atomic load and rmw with enum" {
test "atomic store" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_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
@@ -194,7 +189,6 @@ test "atomic store" {
test "atomic store comptime" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_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
@@ -424,7 +418,6 @@ fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
test "return @atomicStore, using it as a void value" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_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
diff --git a/test/behavior/bugs/13068.zig b/test/behavior/bugs/13068.zig
index e28a410807..bfe6164e27 100644
--- a/test/behavior/bugs/13068.zig
+++ b/test/behavior/bugs/13068.zig
@@ -8,7 +8,6 @@ test {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
list.items.len = 0;
diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig
index e601385bca..7d27138ded 100644
--- a/test/behavior/cast.zig
+++ b/test/behavior/cast.zig
@@ -655,7 +655,6 @@ test "@floatCast cast down" {
}
test "peer type resolution: unreachable, error set, unreachable" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/merge_error_sets.zig b/test/behavior/merge_error_sets.zig
index 4e6d9e4c45..492cb27699 100644
--- a/test/behavior/merge_error_sets.zig
+++ b/test/behavior/merge_error_sets.zig
@@ -12,7 +12,6 @@ fn foo() C!void {
}
test "merge error sets" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (foo()) {
diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig
index 9129b73f16..1643a2f697 100644
--- a/test/behavior/switch.zig
+++ b/test/behavior/switch.zig
@@ -228,7 +228,6 @@ const SwitchProngWithVarEnum = union(enum) {
};
test "switch prong with variable" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
From c58b5732f381fe4f145537501e29347be01e2a44 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Mon, 20 Mar 2023 23:02:31 -0400
Subject: [PATCH 061/216] x86_64: implement @byteSwap and @bitReverse
---
src/arch/x86_64/CodeGen.zig | 317 ++++++++++++++++++++++++++--------
src/arch/x86_64/Emit.zig | 6 +
src/arch/x86_64/Encoding.zig | 6 +-
src/arch/x86_64/Mir.zig | 12 ++
src/arch/x86_64/bits.zig | 2 +-
src/arch/x86_64/encoder.zig | 121 ++++++-------
src/arch/x86_64/encodings.zig | 74 ++++++++
7 files changed, 388 insertions(+), 150 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index f32eb84afc..f30be0e378 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -2595,10 +2595,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
try self.asmRegisterMemory(
.mov,
registerAlias(dst_mcv.register, elem_abi_size),
- Memory.sib(Memory.PtrSize.fromSize(elem_abi_size), .{
- .base = dst_mcv.register,
- .disp = 0,
- }),
+ Memory.sib(Memory.PtrSize.fromSize(elem_abi_size), .{ .base = dst_mcv.register }),
);
break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) };
}
@@ -2956,21 +2953,197 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
+fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, mem_ok: bool) !MCValue {
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+
+ const src_bits = self.regBitSize(src_ty);
+ const src_lock = switch (src_mcv) {
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ else => null,
+ };
+ defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
+
+ switch (src_bits) {
+ else => unreachable,
+ 8 => return if ((mem_ok or src_mcv.isRegister()) and
+ self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ src_mcv
+ else
+ try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv),
+ 16 => if ((mem_ok or src_mcv.isRegister()) and
+ self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ {
+ try self.genBinOpMir(.rol, src_ty, src_mcv, .{ .immediate = 8 });
+ return src_mcv;
+ },
+ 32, 64 => if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) {
+ try self.genUnOpMir(.bswap, src_ty, src_mcv);
+ return src_mcv;
+ },
+ }
+
+ if (src_mcv.isRegister()) {
+ const dst_mcv: MCValue = if (mem_ok)
+ try self.allocRegOrMem(inst, true)
+ else
+ .{ .register = try self.register_manager.allocReg(inst, gp) };
+ if (dst_mcv.isRegister()) {
+ const dst_lock = self.register_manager.lockRegAssumeUnused(dst_mcv.register);
+ defer self.register_manager.unlockReg(dst_lock);
+
+ try self.genSetReg(src_ty, dst_mcv.register, src_mcv);
+ switch (src_bits) {
+ else => unreachable,
+ 16 => try self.genBinOpMir(.rol, src_ty, dst_mcv, .{ .immediate = 8 }),
+ 32, 64 => try self.genUnOpMir(.bswap, src_ty, dst_mcv),
+ }
+ } else try self.genBinOpMir(.movbe, src_ty, dst_mcv, src_mcv);
+ return dst_mcv;
+ }
+
+ const dst_reg = try self.register_manager.allocReg(inst, gp);
+ const dst_mcv = MCValue{ .register = dst_reg };
+ const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
+ defer self.register_manager.unlockReg(dst_lock);
+
+ try self.genBinOpMir(.movbe, src_ty, dst_mcv, src_mcv);
+ return dst_mcv;
+}
+
fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement airByteSwap for {}", .{self.target.cpu.arch});
+ const result = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const src_ty = self.air.typeOf(ty_op.operand);
+ const src_mcv = try self.resolveInst(ty_op.operand);
+
+ const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, true);
+ switch (self.regExtraBits(src_ty)) {
+ 0 => {},
+ else => |extra| try self.genBinOpMir(
+ if (src_ty.isSignedInt()) .sar else .shr,
+ src_ty,
+ dst_mcv,
+ .{ .immediate = extra },
+ ),
+ }
+ break :result dst_mcv;
+ };
+
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement airBitReverse for {}", .{self.target.cpu.arch});
+ const result = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const src_ty = self.air.typeOf(ty_op.operand);
+ const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
+ const src_mcv = try self.resolveInst(ty_op.operand);
+
+ const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, false);
+ const dst_reg = dst_mcv.register;
+ const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
+ defer self.register_manager.unlockReg(dst_lock);
+
+ const tmp_reg = try self.register_manager.allocReg(null, gp);
+ const tmp_lock = self.register_manager.lockReg(tmp_reg);
+ defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);
+
+ {
+ const dst = registerAlias(dst_reg, src_abi_size);
+ const tmp = registerAlias(tmp_reg, src_abi_size);
+ const imm = if (src_abi_size > 4)
+ try self.register_manager.allocReg(null, gp)
+ else
+ undefined;
+
+ const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - src_abi_size * 8);
+ const imm_0000_1111 = Immediate.u(mask / 0b0001_0001);
+ const imm_00_11 = Immediate.u(mask / 0b01_01);
+ const imm_0_1 = Immediate.u(mask / 0b1_1);
+
+ // dst = temp1 = bswap(operand)
+ try self.asmRegisterRegister(.mov, tmp, dst);
+ // tmp = temp1
+ try self.asmRegisterImmediate(.shr, dst, Immediate.u(4));
+ // dst = temp1 >> 4
+ if (src_abi_size > 4) {
+ try self.asmRegisterImmediate(.mov, imm, imm_0000_1111);
+ try self.asmRegisterRegister(.@"and", tmp, imm);
+ try self.asmRegisterRegister(.@"and", dst, imm);
+ } else {
+ try self.asmRegisterImmediate(.@"and", tmp, imm_0000_1111);
+ try self.asmRegisterImmediate(.@"and", dst, imm_0000_1111);
+ }
+ // tmp = temp1 & 0x0F...0F
+ // dst = (temp1 >> 4) & 0x0F...0F
+ try self.asmRegisterImmediate(.shl, tmp, Immediate.u(4));
+ // tmp = (temp1 & 0x0F...0F) << 4
+ try self.asmRegisterRegister(.@"or", dst, tmp);
+ // dst = temp2 = ((temp1 >> 4) & 0x0F...0F) | ((temp1 & 0x0F...0F) << 4)
+ try self.asmRegisterRegister(.mov, tmp, dst);
+ // tmp = temp2
+ try self.asmRegisterImmediate(.shr, dst, Immediate.u(2));
+ // dst = temp2 >> 2
+ if (src_abi_size > 4) {
+ try self.asmRegisterImmediate(.mov, imm, imm_00_11);
+ try self.asmRegisterRegister(.@"and", tmp, imm);
+ try self.asmRegisterRegister(.@"and", dst, imm);
+ } else {
+ try self.asmRegisterImmediate(.@"and", tmp, imm_00_11);
+ try self.asmRegisterImmediate(.@"and", dst, imm_00_11);
+ }
+ // tmp = temp2 & 0x33...33
+ // dst = (temp2 >> 2) & 0x33...33
+ try self.asmRegisterMemory(
+ .lea,
+ if (src_abi_size > 4) tmp.to64() else tmp.to32(),
+ Memory.sib(.qword, .{
+ .base = dst.to64(),
+ .scale_index = .{ .index = tmp.to64(), .scale = 1 << 2 },
+ }),
+ );
+ // tmp = temp3 = ((temp2 >> 2) & 0x33...33) + ((temp2 & 0x33...33) << 2)
+ try self.asmRegisterRegister(.mov, dst, tmp);
+ // dst = temp3
+ try self.asmRegisterImmediate(.shr, tmp, Immediate.u(1));
+ // tmp = temp3 >> 1
+ if (src_abi_size > 4) {
+ try self.asmRegisterImmediate(.mov, imm, imm_0_1);
+ try self.asmRegisterRegister(.@"and", dst, imm);
+ try self.asmRegisterRegister(.@"and", tmp, imm);
+ } else {
+ try self.asmRegisterImmediate(.@"and", dst, imm_0_1);
+ try self.asmRegisterImmediate(.@"and", tmp, imm_0_1);
+ }
+ // dst = temp3 & 0x55...55
+ // tmp = (temp3 >> 1) & 0x55...55
+ try self.asmRegisterMemory(
+ .lea,
+ if (src_abi_size > 4) dst.to64() else dst.to32(),
+ Memory.sib(.qword, .{
+ .base = tmp.to64(),
+ .scale_index = .{ .index = dst.to64(), .scale = 1 << 1 },
+ }),
+ );
+ // dst = ((temp3 >> 1) & 0x55...55) + ((temp3 & 0x55...55) << 1)
+ }
+
+ switch (self.regExtraBits(src_ty)) {
+ 0 => {},
+ else => |extra| try self.genBinOpMir(
+ if (src_ty.isSignedInt()) .sar else .shr,
+ src_ty,
+ dst_mcv,
+ .{ .immediate = extra },
+ ),
+ }
+ break :result dst_mcv;
+ };
+
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
@@ -3052,7 +3225,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
try self.asmRegisterMemory(
.mov,
registerAlias(dst_reg, abi_size),
- Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg, .disp = 0 }),
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg }),
);
},
.stack_offset => |off| {
@@ -3167,7 +3340,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
.eflags => |cc| {
try self.asmSetccMemory(Memory.sib(
Memory.PtrSize.fromSize(abi_size),
- .{ .base = reg.to64(), .disp = 0 },
+ .{ .base = reg.to64() },
), cc);
},
.undef => {
@@ -3187,10 +3360,10 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
Immediate.s(@intCast(i32, @bitCast(i64, imm)))
else
Immediate.u(@truncate(u32, imm));
- try self.asmMemoryImmediate(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
- .base = reg.to64(),
- .disp = 0,
- }), immediate);
+ try self.asmMemoryImmediate(.mov, Memory.sib(
+ Memory.PtrSize.fromSize(abi_size),
+ .{ .base = reg.to64() },
+ ), immediate);
},
8 => {
// TODO: optimization: if the imm is only using the lower
@@ -3262,10 +3435,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr);
// To get the actual address of the value we want to modify we have to go through the GOT
- try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{
- .base = addr_reg.to64(),
- .disp = 0,
- }));
+ try self.asmRegisterMemory(
+ .mov,
+ addr_reg.to64(),
+ Memory.sib(.qword, .{ .base = addr_reg.to64() }),
+ );
const new_ptr = MCValue{ .register = addr_reg.to64() };
@@ -3287,10 +3461,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
return self.fail("TODO imm64 would get incorrectly sign extended", .{});
}
}
- try self.asmMemoryImmediate(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
- .base = addr_reg.to64(),
- .disp = 0,
- }), Immediate.u(@intCast(u32, imm)));
+ try self.asmMemoryImmediate(
+ .mov,
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg.to64() }),
+ Immediate.u(@intCast(u32, imm)),
+ );
},
.register => {
return self.store(new_ptr, value, ptr_ty, value_ty);
@@ -3302,10 +3477,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
defer self.register_manager.unlockReg(tmp_reg_lock);
try self.loadMemPtrIntoRegister(tmp_reg, value_ty, value);
- try self.asmRegisterMemory(.mov, tmp_reg, Memory.sib(.qword, .{
- .base = tmp_reg,
- .disp = 0,
- }));
+ try self.asmRegisterMemory(
+ .mov,
+ tmp_reg,
+ Memory.sib(.qword, .{ .base = tmp_reg }),
+ );
return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
}
@@ -3604,15 +3780,16 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv);
// To get the actual address of the value we want to modify we have to go through the GOT
- try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{
- .base = addr_reg,
- .disp = 0,
- }));
+ try self.asmRegisterMemory(
+ .mov,
+ addr_reg,
+ Memory.sib(.qword, .{ .base = addr_reg }),
+ );
- try self.asmMemory(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
- .base = addr_reg,
- .disp = 0,
- }));
+ try self.asmMemory(
+ mir_tag,
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }),
+ );
},
}
}
@@ -4117,17 +4294,15 @@ fn genBinOp(
// To get the actual address of the value we want to modify we
// we have to go through the GOT
- try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{
- .base = addr_reg,
- .disp = 0,
- }));
+ try self.asmRegisterMemory(
+ .mov,
+ addr_reg,
+ Memory.sib(.qword, .{ .base = addr_reg }),
+ );
try self.asmCmovccRegisterMemory(
registerAlias(dst_reg, abi_size),
- Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
- .base = addr_reg,
- .disp = 0,
- }),
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }),
cc,
);
},
@@ -5175,10 +5350,11 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
try self.loadMemPtrIntoRegister(addr_reg, Type.usize, opt_mcv);
// To get the actual address of the value we want to modify we have to go through the GOT
- try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{
- .base = addr_reg,
- .disp = 0,
- }));
+ try self.asmRegisterMemory(
+ .mov,
+ addr_reg,
+ Memory.sib(.qword, .{ .base = addr_reg }),
+ );
const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
try self.asmMemoryImmediate(.cmp, Memory.sib(
@@ -6374,10 +6550,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
.f64 => .qword,
else => unreachable,
};
- return self.asmRegisterMemory(tag, reg.to128(), Memory.sib(ptr_size, .{
- .base = base_reg.to64(),
- .disp = 0,
- }));
+ return self.asmRegisterMemory(
+ tag,
+ reg.to128(),
+ Memory.sib(ptr_size, .{ .base = base_reg.to64() }),
+ );
}
return self.fail("TODO genSetReg from memory for float with no intrinsics", .{});
@@ -6387,7 +6564,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
try self.asmRegisterMemory(
.mov,
registerAlias(reg, abi_size),
- Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64(), .disp = 0 }),
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
);
},
}
@@ -6408,10 +6585,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
.f64 => .qword,
else => unreachable,
};
- return self.asmRegisterMemory(tag, reg.to128(), Memory.sib(ptr_size, .{
- .base = base_reg.to64(),
- .disp = 0,
- }));
+ return self.asmRegisterMemory(
+ tag,
+ reg.to128(),
+ Memory.sib(ptr_size, .{ .base = base_reg.to64() }),
+ );
}
return self.fail("TODO genSetReg from memory for float with no intrinsics", .{});
@@ -6447,7 +6625,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
try self.asmRegisterMemory(
.mov,
registerAlias(reg, abi_size),
- Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64(), .disp = 0 }),
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
);
}
}
@@ -6638,12 +6816,9 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
const ptr_mem: Memory = switch (ptr_mcv) {
- .register => |reg| Memory.sib(ptr_size, .{ .base = reg, .disp = 0 }),
+ .register => |reg| Memory.sib(ptr_size, .{ .base = reg }),
.ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),
- else => Memory.sib(ptr_size, .{
- .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
- .disp = 0,
- }),
+ else => Memory.sib(ptr_size, .{ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }),
};
const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null;
defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
@@ -6692,12 +6867,9 @@ fn atomicOp(
const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
const ptr_mem: Memory = switch (ptr_mcv) {
- .register => |reg| Memory.sib(ptr_size, .{ .base = reg, .disp = 0 }),
+ .register => |reg| Memory.sib(ptr_size, .{ .base = reg }),
.ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),
- else => Memory.sib(ptr_size, .{
- .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
- .disp = 0,
- }),
+ else => Memory.sib(ptr_size, .{ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }),
};
const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null;
defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
@@ -6861,10 +7033,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
.linker_load, .memory => {
const reg = try self.register_manager.allocReg(null, gp);
try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr);
- try self.asmRegisterMemory(.mov, reg, Memory.sib(.qword, .{
- .base = reg,
- .disp = 0,
- }));
+ try self.asmRegisterMemory(.mov, reg, Memory.sib(.qword, .{ .base = reg }));
break :blk MCValue{ .register = reg };
},
else => break :blk src_ptr,
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index 9718548736..cd8389aa49 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -75,6 +75,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.@"and",
.bsf,
.bsr,
+ .bswap,
.bt,
.btc,
.btr,
@@ -100,6 +101,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.lzcnt,
.mfence,
.mov,
+ .movbe,
.movzx,
.mul,
.neg,
@@ -109,7 +111,11 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.pop,
.popcnt,
.push,
+ .rcl,
+ .rcr,
.ret,
+ .rol,
+ .ror,
.sal,
.sar,
.sbb,
diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig
index 03b8abf983..891fc4e9a1 100644
--- a/src/arch/x86_64/Encoding.zig
+++ b/src/arch/x86_64/Encoding.zig
@@ -307,7 +307,7 @@ pub const Mnemonic = enum {
// zig fmt: off
// General-purpose
adc, add, @"and",
- bsf, bsr, bt, btc, btr, bts,
+ bsf, bsr, bswap, bt, btc, btr, bts,
call, cbw, cdq, cdqe,
cmova, cmovae, cmovb, cmovbe, cmovc, cmove, cmovg, cmovge, cmovl, cmovle, cmovna,
cmovnae, cmovnb, cmovnbe, cmovnc, cmovne, cmovng, cmovnge, cmovnl, cmovnle, cmovno,
@@ -325,13 +325,13 @@ pub const Mnemonic = enum {
lea, lfence,
lods, lodsb, lodsd, lodsq, lodsw,
lzcnt,
- mfence, mov,
+ mfence, mov, movbe,
movs, movsb, movsd, movsq, movsw,
movsx, movsxd, movzx, mul,
neg, nop, not,
@"or",
pop, popcnt, push,
- ret,
+ rcl, rcr, ret, rol, ror,
sal, sar, sbb,
scas, scasb, scasd, scasq, scasw,
shl, shr, sub, syscall,
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index d086b617f5..59c292c500 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -42,6 +42,8 @@ pub const Inst = struct {
bsf,
/// Bit scan reverse
bsr,
+ /// Byte swap
+ bswap,
/// Bit test
bt,
/// Bit test and complement
@@ -94,6 +96,8 @@ pub const Inst = struct {
mfence,
/// Move
mov,
+ /// Move data after swapping bytes
+ movbe,
/// Move with sign extension
movsx,
/// Move with zero extension
@@ -114,8 +118,16 @@ pub const Inst = struct {
popcnt,
/// Push
push,
+ /// Rotate left through carry
+ rcl,
+ /// Rotate right through carry
+ rcr,
/// Return
ret,
+ /// Rotate left
+ rol,
+ /// Rotate right
+ ror,
/// Arithmetic shift left
sal,
/// Arithmetic shift right
diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig
index 250eedeafc..c10bfe4039 100644
--- a/src/arch/x86_64/bits.zig
+++ b/src/arch/x86_64/bits.zig
@@ -472,7 +472,7 @@ pub const Memory = union(enum) {
}
pub fn sib(ptr_size: PtrSize, args: struct {
- disp: i32,
+ disp: i32 = 0,
base: ?Register = null,
scale_index: ?ScaleIndex = null,
}) Memory {
diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig
index 519158d012..b3de7ec1bd 100644
--- a/src/arch/x86_64/encoder.zig
+++ b/src/arch/x86_64/encoder.zig
@@ -211,14 +211,12 @@ pub const Instruction = struct {
fn encodeOpcode(inst: Instruction, encoder: anytype) !void {
const opcode = inst.encoding.opcode();
+ const first = @boolToInt(inst.encoding.mandatoryPrefix() != null);
+ const final = opcode.len - 1;
+ for (opcode[first..final]) |byte| try encoder.opcode_1byte(byte);
switch (inst.encoding.op_en) {
- .o, .oi => try encoder.opcode_withReg(opcode[0], inst.op1.reg.lowEnc()),
- else => {
- const index: usize = if (inst.encoding.mandatoryPrefix()) |_| 1 else 0;
- for (opcode[index..]) |byte| {
- try encoder.opcode_1byte(byte);
- }
- },
+ .o, .oi => try encoder.opcode_withReg(opcode[final], inst.op1.reg.lowEnc()),
+ else => try encoder.opcode_1byte(opcode[final]),
}
}
@@ -896,10 +894,10 @@ test "lower MI encoding" {
try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } });
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
- try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.byte, .{
- .base = .r12,
- .disp = 0,
- }) }, .op2 = .{ .imm = Immediate.u(0x10) } });
+ try enc.encode(.mov, .{
+ .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
+ .op2 = .{ .imm = Immediate.u(0x10) },
+ });
try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");
try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } });
@@ -911,10 +909,10 @@ test "lower MI encoding" {
try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10) } });
try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
- try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.dword, .{
- .base = .r11,
- .disp = 0,
- }) }, .op2 = .{ .imm = Immediate.u(0x10) } });
+ try enc.encode(.mov, .{
+ .op1 = .{ .mem = Memory.sib(.dword, .{ .base = .r11 }) },
+ .op2 = .{ .imm = Immediate.u(0x10) },
+ });
try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
try enc.encode(.mov, .{
@@ -1030,10 +1028,10 @@ test "lower MI encoding" {
test "lower RM encoding" {
var enc = TestEncode{};
- try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.sib(.qword, .{
- .base = .r11,
- .disp = 0,
- }) } });
+ try enc.encode(.mov, .{
+ .op1 = .{ .reg = .rax },
+ .op2 = .{ .mem = Memory.sib(.qword, .{ .base = .r11 }) },
+ });
try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]");
try enc.encode(.mov, .{ .op1 = .{ .reg = .rbx }, .op2 = .{ .mem = Memory.sib(.qword, .{
@@ -1116,20 +1114,16 @@ test "lower RM encoding" {
try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .reg = .bl } });
try expectEqualHexStrings("\x66\x0F\xBE\xC3", enc.code(), "movsx ax, bl");
- try enc.encode(.movsx, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.sib(.word, .{
- .base = .rbp,
- .disp = 0,
- }) } });
+ try enc.encode(.movsx, .{
+ .op1 = .{ .reg = .eax },
+ .op2 = .{ .mem = Memory.sib(.word, .{ .base = .rbp }) },
+ });
try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]");
- try enc.encode(.movsx, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.sib(.byte, .{
- .base = null,
- .scale_index = .{
- .index = .rax,
- .scale = 2,
- },
- .disp = 0,
- }) } });
+ try enc.encode(.movsx, .{
+ .op1 = .{ .reg = .eax },
+ .op2 = .{ .mem = Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) },
+ });
try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]");
try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } });
@@ -1156,14 +1150,13 @@ test "lower RM encoding" {
try enc.encode(.lea, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } });
try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]");
- try enc.encode(.lea, .{ .op1 = .{ .reg = .rsi }, .op2 = .{ .mem = Memory.sib(.qword, .{
- .base = .rbp,
- .scale_index = .{
- .scale = 1,
- .index = .rcx,
- },
- .disp = 0,
- }) } });
+ try enc.encode(.lea, .{
+ .op1 = .{ .reg = .rsi },
+ .op2 = .{ .mem = Memory.sib(.qword, .{
+ .base = .rbp,
+ .scale_index = .{ .scale = 1, .index = .rcx },
+ }) },
+ });
try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", enc.code(), "lea rsi, QWORD PTR [rbp + rcx*1 + 0]");
try enc.encode(.add, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .mem = Memory.sib(.qword, .{
@@ -1319,51 +1312,35 @@ test "lower M encoding" {
try enc.encode(.call, .{ .op1 = .{ .reg = .r12 } });
try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12");
- try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
- .base = .r12,
- .disp = 0,
- }) } });
+ try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .r12 }) } });
try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]");
- try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
- .base = null,
- .scale_index = .{
- .index = .r11,
- .scale = 2,
- },
- .disp = 0,
- }) } });
+ try enc.encode(.call, .{
+ .op1 = .{ .mem = Memory.sib(.qword, .{
+ .base = null,
+ .scale_index = .{ .index = .r11, .scale = 2 },
+ }) },
+ });
try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]");
- try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
- .base = null,
- .scale_index = .{
- .index = .r12,
- .scale = 2,
- },
- .disp = 0,
- }) } });
+ try enc.encode(.call, .{
+ .op1 = .{ .mem = Memory.sib(.qword, .{
+ .base = null,
+ .scale_index = .{ .index = .r12, .scale = 2 },
+ }) },
+ });
try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]");
- try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
- .base = .gs,
- .disp = 0,
- }) } });
+ try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .gs }) } });
try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");
try enc.encode(.call, .{ .op1 = .{ .imm = Immediate.s(0) } });
try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
- try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.qword, .{
- .base = .rbp,
- .disp = 0,
- }) } });
+ try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .rbp }) } });
try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
- try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.word, .{
- .base = .rbp,
- .disp = 0,
- }) } });
+ try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.word, .{ .base = .rbp }) } });
try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
try enc.encode(.pop, .{ .op1 = .{ .mem = Memory.rip(.qword, 0) } });
@@ -1491,7 +1468,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void {
test "cannot encode" {
try cannotEncode(.@"test", .{
- .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12, .disp = 0 }) },
+ .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
.op2 = .{ .reg = .ah },
});
try cannotEncode(.@"test", .{
diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig
index 602718073d..23a125789b 100644
--- a/src/arch/x86_64/encodings.zig
+++ b/src/arch/x86_64/encodings.zig
@@ -89,6 +89,9 @@ pub const table = &[_]Entry{
.{ .bsr, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbd }, 0, .none },
.{ .bsr, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbd }, 0, .long },
+ .{ .bswap, .o, .r32, .none, .none, .none, &.{ 0x0f, 0xc8 }, 0, .none },
+ .{ .bswap, .o, .r64, .none, .none, .none, &.{ 0x0f, 0xc8 }, 0, .long },
+
.{ .bt, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none },
.{ .bt, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none },
.{ .bt, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xa3 }, 0, .long },
@@ -387,6 +390,13 @@ pub const table = &[_]Entry{
.{ .mov, .mi, .rm32, .imm32, .none, .none, &.{ 0xc7 }, 0, .none },
.{ .mov, .mi, .rm64, .imm32s, .none, .none, &.{ 0xc7 }, 0, .long },
+ .{ .movbe, .rm, .r16, .m16, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },
+ .{ .movbe, .rm, .r32, .m32, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .none },
+ .{ .movbe, .rm, .r64, .m64, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .long },
+ .{ .movbe, .mr, .m16, .r16, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },
+ .{ .movbe, .mr, .m32, .r32, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .none },
+ .{ .movbe, .mr, .m64, .r64, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .long },
+
.{ .movs, .np, .m8, .m8, .none, .none, &.{ 0xa4 }, 0, .none },
.{ .movs, .np, .m16, .m16, .none, .none, &.{ 0xa5 }, 0, .none },
.{ .movs, .np, .m32, .m32, .none, .none, &.{ 0xa5 }, 0, .none },
@@ -476,6 +486,70 @@ pub const table = &[_]Entry{
.{ .ret, .np, .none, .none, .none, .none, &.{ 0xc3 }, 0, .none },
+ .{ .rcl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 2, .none },
+ .{ .rcl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 2, .rex },
+ .{ .rcl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 2, .none },
+ .{ .rcl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 2, .rex },
+ .{ .rcl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 2, .none },
+ .{ .rcl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 2, .rex },
+ .{ .rcl, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 2, .none },
+ .{ .rcl, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 2, .none },
+ .{ .rcl, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 2, .none },
+ .{ .rcl, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 2, .none },
+ .{ .rcl, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 2, .long },
+ .{ .rcl, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 2, .none },
+ .{ .rcl, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 2, .long },
+ .{ .rcl, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 2, .none },
+ .{ .rcl, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 2, .long },
+
+ .{ .rcr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 3, .none },
+ .{ .rcr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 3, .rex },
+ .{ .rcr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 3, .none },
+ .{ .rcr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 3, .rex },
+ .{ .rcr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 3, .none },
+ .{ .rcr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 3, .rex },
+ .{ .rcr, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 3, .none },
+ .{ .rcr, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 3, .none },
+ .{ .rcr, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 3, .none },
+ .{ .rcr, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 3, .none },
+ .{ .rcr, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 3, .long },
+ .{ .rcr, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 3, .none },
+ .{ .rcr, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 3, .long },
+ .{ .rcr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 3, .none },
+ .{ .rcr, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 3, .long },
+
+ .{ .rol, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 0, .none },
+ .{ .rol, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 0, .rex },
+ .{ .rol, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 0, .none },
+ .{ .rol, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 0, .rex },
+ .{ .rol, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 0, .none },
+ .{ .rol, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 0, .rex },
+ .{ .rol, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 0, .none },
+ .{ .rol, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 0, .none },
+ .{ .rol, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 0, .none },
+ .{ .rol, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 0, .none },
+ .{ .rol, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 0, .long },
+ .{ .rol, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 0, .none },
+ .{ .rol, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 0, .long },
+ .{ .rol, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 0, .none },
+ .{ .rol, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 0, .long },
+
+ .{ .ror, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 1, .none },
+ .{ .ror, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 1, .rex },
+ .{ .ror, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 1, .none },
+ .{ .ror, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 1, .rex },
+ .{ .ror, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 1, .none },
+ .{ .ror, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 1, .rex },
+ .{ .ror, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 1, .none },
+ .{ .ror, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 1, .none },
+ .{ .ror, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 1, .none },
+ .{ .ror, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 1, .none },
+ .{ .ror, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 1, .long },
+ .{ .ror, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 1, .none },
+ .{ .ror, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 1, .long },
+ .{ .ror, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 1, .none },
+ .{ .ror, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 1, .long },
+
.{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none },
.{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex },
.{ .sal, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none },
From a88ffa7fa91e568fe234ac9ea2b15f005876cca6 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Tue, 21 Mar 2023 11:38:19 +0100
Subject: [PATCH 062/216] macho+zld: save locals from section atoms to symtab
too
---
src/link/MachO/zld.zig | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig
index 931352545e..17d122b30d 100644
--- a/src/link/MachO/zld.zig
+++ b/src/link/MachO/zld.zig
@@ -2456,6 +2456,17 @@ pub const Zld = struct {
try self.writeStrtab();
}
+ fn addLocalToSymtab(self: *Zld, sym_loc: SymbolWithLoc, locals: *std.ArrayList(macho.nlist_64)) !void {
+ const sym = self.getSymbol(sym_loc);
+ if (sym.n_strx == 0) return; // no name, skip
+ if (sym.ext()) return; // an export lands in its own symtab section, skip
+ if (self.symbolIsTemp(sym_loc)) return; // local temp symbol, skip
+
+ var out_sym = sym;
+ out_sym.n_strx = try self.strtab.insert(self.gpa, self.getSymbolName(sym_loc));
+ try locals.append(out_sym);
+ }
+
fn writeSymtab(self: *Zld) !SymtabCtx {
const gpa = self.gpa;
@@ -2466,14 +2477,12 @@ pub const Zld = struct {
for (object.atoms.items) |atom_index| {
const atom = self.getAtom(atom_index);
const sym_loc = atom.getSymbolWithLoc();
- const sym = self.getSymbol(sym_loc);
- if (sym.n_strx == 0) continue; // no name, skip
- if (sym.ext()) continue; // an export lands in its own symtab section, skip
- if (self.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip
+ try self.addLocalToSymtab(sym_loc, &locals);
- var out_sym = sym;
- out_sym.n_strx = try self.strtab.insert(gpa, self.getSymbolName(sym_loc));
- try locals.append(out_sym);
+ var it = Atom.getInnerSymbolsIterator(self, atom_index);
+ while (it.next()) |inner_sym_loc| {
+ try self.addLocalToSymtab(inner_sym_loc, &locals);
+ }
}
}
From 073f9a18a92fd233e07470e737e15e651618e47f Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Tue, 21 Mar 2023 11:38:49 +0100
Subject: [PATCH 063/216] macho+zld: return null rather than error on invalid
AbbrevKind
---
src/link/MachO/DwarfInfo.zig | 21 +++------------------
1 file changed, 3 insertions(+), 18 deletions(-)
diff --git a/src/link/MachO/DwarfInfo.zig b/src/link/MachO/DwarfInfo.zig
index 1ec4a79871..3218435734 100644
--- a/src/link/MachO/DwarfInfo.zig
+++ b/src/link/MachO/DwarfInfo.zig
@@ -27,7 +27,7 @@ const CompileUnitIterator = struct {
pub fn next(self: *CompileUnitIterator) !?CompileUnit {
if (self.pos >= self.ctx.debug_info.len) return null;
- var stream = std.io.fixedBufferStream(self.ctx.debug_info);
+ var stream = std.io.fixedBufferStream(self.ctx.debug_info[self.pos..]);
var creader = std.io.countingReader(stream.reader());
const reader = creader.reader();
@@ -37,7 +37,7 @@ const CompileUnitIterator = struct {
const cu = CompileUnit{
.cuh = cuh,
- .debug_info_off = offset,
+ .debug_info_off = self.pos + offset,
};
self.pos += (math.cast(usize, total_length) orelse return error.Overflow);
@@ -188,7 +188,7 @@ const AbbrevEntryIterator = struct {
return AbbrevEntry.null();
}
- const abbrev_pos = lookup.get(kind) orelse return error.MalformedDwarf;
+ const abbrev_pos = lookup.get(kind) orelse return null;
const len = try findAbbrevEntrySize(
self.ctx,
abbrev_pos.pos,
@@ -290,21 +290,6 @@ pub const Attribute = struct {
};
}
- pub fn getReference(self: Attribute, ctx: DwarfInfo) !?u64 {
- const debug_info = self.getDebugInfo(ctx);
- var stream = std.io.fixedBufferStream(debug_info);
- const reader = stream.reader();
-
- return switch (self.form) {
- dwarf.FORM.ref1 => debug_info[0],
- dwarf.FORM.ref2 => mem.readIntLittle(u16, debug_info[0..2]),
- dwarf.FORM.ref4 => mem.readIntLittle(u32, debug_info[0..4]),
- dwarf.FORM.ref8 => mem.readIntLittle(u64, debug_info[0..8]),
- dwarf.FORM.ref_udata => try leb.readULEB128(u64, reader),
- else => null,
- };
- }
-
pub fn getAddr(self: Attribute, ctx: DwarfInfo, cuh: CompileUnit.Header) ?u64 {
if (self.form != dwarf.FORM.addr) return null;
const debug_info = self.getDebugInfo(ctx);
From b73159f4f57dcdffab526bb2c944b37942d65fc8 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Tue, 21 Mar 2023 12:47:43 +0100
Subject: [PATCH 064/216] macho: use TOOL=0x5 to mean ZIG as the build tool
---
lib/std/macho.zig | 2 ++
src/link/MachO/load_commands.zig | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/lib/std/macho.zig b/lib/std/macho.zig
index 8f695b14b7..ff12e718f6 100644
--- a/lib/std/macho.zig
+++ b/lib/std/macho.zig
@@ -143,6 +143,8 @@ pub const TOOL = enum(u32) {
CLANG = 0x1,
SWIFT = 0x2,
LD = 0x3,
+ LLD = 0x4, // LLVM's stock LLD linker
+ ZIG = 0x5, // Unofficially Zig
_,
};
diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig
index a452551a0a..43469ac435 100644
--- a/src/link/MachO/load_commands.zig
+++ b/src/link/MachO/load_commands.zig
@@ -294,7 +294,7 @@ pub fn writeBuildVersionLC(options: *const link.Options, lc_writer: anytype) !vo
.ntools = 1,
});
try lc_writer.writeAll(mem.asBytes(&macho.build_tool_version{
- .tool = .LD,
+ .tool = .ZIG,
.version = 0x0,
}));
}
From 898e4473e8acf664d67474716bb9728ed601c5a0 Mon Sep 17 00:00:00 2001
From: Xavier Bouchoux
Date: Sun, 19 Mar 2023 12:56:37 +0000
Subject: [PATCH 065/216] CBE: implement aggregateInit() for array of array
case.
fixes `error(compilation): clang failed with stderr: error: array type 'uint32_t[10]' (aka 'unsigned int[10]') is not assignable`
---
src/codegen/c.zig | 40 +++++++++++++++++++++++++++++-----------
test/behavior/array.zig | 10 ++++++++++
2 files changed, 39 insertions(+), 11 deletions(-)
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 519b2b45d5..0c85f0f923 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -6852,17 +6852,35 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
switch (inst_ty.zigTypeTag()) {
.Array, .Vector => {
const elem_ty = inst_ty.childType();
- for (resolved_elements, 0..) |element, i| {
- try f.writeCValue(writer, local, .Other);
- try writer.print("[{d}] = ", .{i});
- try f.writeCValue(writer, element, .Other);
- try writer.writeAll(";\n");
- }
- if (inst_ty.sentinel()) |sentinel| {
- try f.writeCValue(writer, local, .Other);
- try writer.print("[{d}] = ", .{resolved_elements.len});
- try f.object.dg.renderValue(writer, elem_ty, sentinel, .Other);
- try writer.writeAll(";\n");
+
+ const is_array = lowersToArray(elem_ty, target);
+ const need_memcpy = is_array;
+ if (need_memcpy) {
+ for (resolved_elements, 0..) |element, i| {
+ try writer.writeAll("memcpy(");
+ try f.writeCValue(writer, local, .Other);
+ try writer.print("[{d}]", .{i});
+ try writer.writeAll(", ");
+ try f.writeCValue(writer, element, .Other);
+ try writer.writeAll(", sizeof(");
+ try f.renderType(writer, elem_ty);
+ try writer.writeAll("))");
+ try writer.writeAll(";\n");
+ }
+ assert(inst_ty.sentinel() == null);
+ } else {
+ for (resolved_elements, 0..) |element, i| {
+ try f.writeCValue(writer, local, .Other);
+ try writer.print("[{d}] = ", .{i});
+ try f.writeCValue(writer, element, .Other);
+ try writer.writeAll(";\n");
+ }
+ if (inst_ty.sentinel()) |sentinel| {
+ try f.writeCValue(writer, local, .Other);
+ try writer.print("[{d}] = ", .{resolved_elements.len});
+ try f.object.dg.renderValue(writer, elem_ty, sentinel, .Other);
+ try writer.writeAll(";\n");
+ }
}
},
.Struct => switch (inst_ty.containerLayout()) {
diff --git a/test/behavior/array.zig b/test/behavior/array.zig
index c78bf4ab85..484cab4722 100644
--- a/test/behavior/array.zig
+++ b/test/behavior/array.zig
@@ -669,3 +669,13 @@ test "runtime initialized sentinel-terminated array literal" {
try std.testing.expect(g[2] == 0x99);
try std.testing.expect(g[3] == 0x99);
}
+
+test "array of array agregate init" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+
+ var a = [1]u32{11} ** 10;
+ var b = [1][10]u32{a} ** 2;
+ try std.testing.expect(b[1][1] == 11);
+}
From 1e087d3a64e6b504524c32f72b22faffef78b41e Mon Sep 17 00:00:00 2001
From: Marcus Ramse
Date: Wed, 8 Mar 2023 16:04:57 +0100
Subject: [PATCH 066/216] std.json: support tuples
---
lib/std/json.zig | 48 +++++++++++++++++++++++++++++++++++------
lib/std/json/test.zig | 50 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 91 insertions(+), 7 deletions(-)
diff --git a/lib/std/json.zig b/lib/std/json.zig
index 590040efba..d2467fb2cd 100644
--- a/lib/std/json.zig
+++ b/lib/std/json.zig
@@ -1511,6 +1511,34 @@ fn parseInternal(
}
},
.Struct => |structInfo| {
+ if (structInfo.is_tuple) {
+ switch (token) {
+ .ArrayBegin => {},
+ else => return error.UnexpectedToken,
+ }
+ var r: T = undefined;
+ var child_options = options;
+ child_options.allow_trailing_data = true;
+ var fields_seen: usize = 0;
+ errdefer {
+ inline for (0..structInfo.fields.len) |i| {
+ if (i < fields_seen) {
+ parseFree(structInfo.fields[i].type, r[i], options);
+ }
+ }
+ }
+ inline for (0..structInfo.fields.len) |i| {
+ r[i] = try parse(structInfo.fields[i].type, tokens, child_options);
+ fields_seen = i + 1;
+ }
+ const tok = (try tokens.next()) orelse return error.UnexpectedEndOfJson;
+ switch (tok) {
+ .ArrayEnd => {},
+ else => return error.UnexpectedToken,
+ }
+ return r;
+ }
+
switch (token) {
.ObjectBegin => {},
else => return error.UnexpectedToken,
@@ -2290,7 +2318,7 @@ pub fn stringify(
return value.jsonStringify(options, out_stream);
}
- try out_stream.writeByte('{');
+ try out_stream.writeByte(if (S.is_tuple) '[' else '{');
var field_output = false;
var child_options = options;
if (child_options.whitespace) |*child_whitespace| {
@@ -2320,11 +2348,13 @@ pub fn stringify(
if (child_options.whitespace) |child_whitespace| {
try child_whitespace.outputIndent(out_stream);
}
- try encodeJsonString(Field.name, options, out_stream);
- try out_stream.writeByte(':');
- if (child_options.whitespace) |child_whitespace| {
- if (child_whitespace.separator) {
- try out_stream.writeByte(' ');
+ if (!S.is_tuple) {
+ try encodeJsonString(Field.name, options, out_stream);
+ try out_stream.writeByte(':');
+ if (child_options.whitespace) |child_whitespace| {
+ if (child_whitespace.separator) {
+ try out_stream.writeByte(' ');
+ }
}
}
try stringify(@field(value, Field.name), child_options, out_stream);
@@ -2335,7 +2365,7 @@ pub fn stringify(
try whitespace.outputIndent(out_stream);
}
}
- try out_stream.writeByte('}');
+ try out_stream.writeByte(if (S.is_tuple) ']' else '}');
return;
},
.ErrorSet => return stringify(@as([]const u8, @errorName(value)), options, out_stream),
@@ -2649,6 +2679,10 @@ test "stringify vector" {
try teststringify("[1,1]", @splat(2, @as(u32, 1)), StringifyOptions{});
}
+test "stringify tuple" {
+ try teststringify("[\"foo\",42]", std.meta.Tuple(&.{ []const u8, usize }){ "foo", 42 }, StringifyOptions{});
+}
+
fn teststringify(expected: []const u8, value: anytype, options: StringifyOptions) !void {
const ValidationWriter = struct {
const Self = @This();
diff --git a/lib/std/json/test.zig b/lib/std/json/test.zig
index 067bc2920b..ce4b4ea7e8 100644
--- a/lib/std/json/test.zig
+++ b/lib/std/json/test.zig
@@ -2459,6 +2459,56 @@ test "parse into struct ignoring unknown fields" {
try testing.expectEqualSlices(u8, "zig", r.language);
}
+test "parse into tuple" {
+ const options = ParseOptions{ .allocator = testing.allocator };
+ const Union = union(enum) {
+ char: u8,
+ float: f64,
+ string: []const u8,
+ };
+ const T = std.meta.Tuple(&.{
+ i64,
+ f64,
+ bool,
+ []const u8,
+ ?bool,
+ struct {
+ foo: i32,
+ bar: []const u8,
+ },
+ std.meta.Tuple(&.{ u8, []const u8, u8 }),
+ Union,
+ });
+ var ts = TokenStream.init(
+ \\[
+ \\ 420,
+ \\ 3.14,
+ \\ true,
+ \\ "zig",
+ \\ null,
+ \\ {
+ \\ "foo": 1,
+ \\ "bar": "zero"
+ \\ },
+ \\ [4, "två", 42],
+ \\ 12.34
+ \\]
+ );
+ const r = try parse(T, &ts, options);
+ defer parseFree(T, r, options);
+ try testing.expectEqual(@as(i64, 420), r[0]);
+ try testing.expectEqual(@as(f64, 3.14), r[1]);
+ try testing.expectEqual(true, r[2]);
+ try testing.expectEqualSlices(u8, "zig", r[3]);
+ try testing.expectEqual(@as(?bool, null), r[4]);
+ try testing.expectEqual(@as(i32, 1), r[5].foo);
+ try testing.expectEqualSlices(u8, "zero", r[5].bar);
+ try testing.expectEqual(@as(u8, 4), r[6][0]);
+ try testing.expectEqualSlices(u8, "två", r[6][1]);
+ try testing.expectEqual(@as(u8, 42), r[6][2]);
+ try testing.expectEqual(Union{ .float = 12.34 }, r[7]);
+}
+
const ParseIntoRecursiveUnionDefinitionValue = union(enum) {
integer: i64,
array: []const ParseIntoRecursiveUnionDefinitionValue,
From f9b5829508e4f9a7e2eee2f05f58a38c00318d91 Mon Sep 17 00:00:00 2001
From: mlugg
Date: Sat, 4 Mar 2023 13:21:11 +0000
Subject: [PATCH 067/216] Sema: implement @export for arbitrary values
---
src/Sema.zig | 18 +++++++++++++++++-
test/behavior/export.zig | 19 +++++++++++++++++++
2 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/src/Sema.zig b/src/Sema.zig
index 6d6a9a13e8..d01535cdaa 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -5668,7 +5668,15 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
};
const decl_index = switch (operand.val.tag()) {
.function => operand.val.castTag(.function).?.data.owner_decl,
- else => return sema.fail(block, operand_src, "TODO implement exporting arbitrary Value objects", .{}), // TODO put this Value into an anonymous Decl and then export it.
+ else => blk: {
+ var anon_decl = try block.startAnonDecl();
+ defer anon_decl.deinit();
+ break :blk try anon_decl.finish(
+ try operand.ty.copy(anon_decl.arena()),
+ try operand.val.copy(anon_decl.arena()),
+ 0,
+ );
+ },
};
try sema.analyzeExport(block, src, options, decl_index);
}
@@ -5704,6 +5712,14 @@ pub fn analyzeExport(
return sema.failWithOwnedErrorMsg(msg);
}
+ // TODO: some backends might support re-exporting extern decls
+ if (exported_decl.isExtern()) {
+ return sema.fail(block, src, "export target cannot be extern", .{});
+ }
+
+ // This decl is alive no matter what, since it's being exported
+ mod.markDeclAlive(exported_decl);
+
const gpa = mod.gpa;
try mod.decl_exports.ensureUnusedCapacity(gpa, 1);
diff --git a/test/behavior/export.zig b/test/behavior/export.zig
index fb35fc6fc6..6123aa593b 100644
--- a/test/behavior/export.zig
+++ b/test/behavior/export.zig
@@ -70,3 +70,22 @@ test "exporting using field access" {
_ = S.Inner.x;
}
+
+test "exporting comptime-known value" {
+ const x: u32 = 10;
+ @export(x, .{ .name = "exporting_comptime_known_value_foo" });
+ const S = struct {
+ extern const exporting_comptime_known_value_foo: u32;
+ };
+ try expect(S.exporting_comptime_known_value_foo == 10);
+}
+
+test "exporting comptime var" {
+ comptime var x: u32 = 5;
+ @export(x, .{ .name = "exporting_comptime_var_foo" });
+ x = 7; // modifying this now shouldn't change anything
+ const S = struct {
+ extern const exporting_comptime_var_foo: u32;
+ };
+ try expect(S.exporting_comptime_var_foo == 5);
+}
From 8642770eff4f1770aa5de88907946c60fe5ff0d8 Mon Sep 17 00:00:00 2001
From: r00ster91
Date: Fri, 3 Mar 2023 16:16:08 +0100
Subject: [PATCH 068/216] langref: add missing return types to builtin
functions
This should add all remaining missing return types to all builtin
functions.
For @clz, @ctz, and @popCount it uses anytype for the lack of a better
alternative. We already use this return type for other builtin functions in the langref
to indicate that the type is not always the same.
It is not possible to use anytype as the return type for regular
functions but builtin functions are special.
---
doc/langref.html.in | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 991fd0c3e6..be055c3179 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -7814,7 +7814,7 @@ comptime {
{#header_close#}
{#header_open|@breakpoint#}
- {#syntax#}@breakpoint(){#endsyntax#}
+ {#syntax#}@breakpoint() void{#endsyntax#}
This function inserts a platform-specific debug trap instruction which causes
debuggers to break there.
@@ -7933,7 +7933,7 @@ pub const CallModifier = enum {
{#header_close#}
{#header_open|@cDefine#}
-
{#syntax#}@cDefine(comptime name: []u8, value){#endsyntax#}
+ {#syntax#}@cDefine(comptime name: []u8, value) void{#endsyntax#}
This function can only occur inside {#syntax#}@cImport{#endsyntax#}.
@@ -7977,7 +7977,7 @@ pub const CallModifier = enum {
{#see_also|Import from C Header File|@cInclude|@cDefine|@cUndef#}
{#header_close#}
{#header_open|@cInclude#}
- {#syntax#}@cInclude(comptime path: []u8){#endsyntax#}
+ {#syntax#}@cInclude(comptime path: []u8) void{#endsyntax#}
This function can only occur inside {#syntax#}@cImport{#endsyntax#}.
@@ -7989,7 +7989,7 @@ pub const CallModifier = enum {
{#header_close#}
{#header_open|@clz#}
- {#syntax#}@clz(operand: anytype){#endsyntax#}
+ {#syntax#}@clz(operand: anytype) anytype{#endsyntax#}
{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.
{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.
@@ -8068,7 +8068,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
{#header_close#}
{#header_open|@compileError#}
-
{#syntax#}@compileError(comptime msg: []u8){#endsyntax#}
+ {#syntax#}@compileError(comptime msg: []u8) noreturn{#endsyntax#}
This function, when semantically analyzed, causes a compile error with the
message {#syntax#}msg{#endsyntax#}.
@@ -8081,7 +8081,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
{#header_close#}
{#header_open|@compileLog#}
-
{#syntax#}@compileLog(args: ...){#endsyntax#}
+ {#syntax#}@compileLog(args: ...) void{#endsyntax#}
This function prints the arguments passed to it at compile-time.
@@ -8139,7 +8139,7 @@ test "main" {
{#header_close#}
{#header_open|@ctz#}
- {#syntax#}@ctz(operand: anytype){#endsyntax#}
+ {#syntax#}@ctz(operand: anytype) anytype{#endsyntax#}
{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.
{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.
@@ -8159,7 +8159,7 @@ test "main" {
{#header_close#}
{#header_open|@cUndef#}
-
{#syntax#}@cUndef(comptime name: []u8){#endsyntax#}
+ {#syntax#}@cUndef(comptime name: []u8) void{#endsyntax#}
This function can only occur inside {#syntax#}@cImport{#endsyntax#}.
@@ -8370,7 +8370,7 @@ export fn @"A function name that is a complete sentence."() void {}
{#header_close#}
{#header_open|@fence#}
- {#syntax#}@fence(order: AtomicOrder){#endsyntax#}
+ {#syntax#}@fence(order: AtomicOrder) void{#endsyntax#}
The {#syntax#}fence{#endsyntax#} function is used to introduce happens-before edges between operations.
@@ -8622,7 +8622,7 @@ test "integer cast panic" {
{#header_close#}
{#header_open|@memcpy#}
- {#syntax#}@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize){#endsyntax#}
+ {#syntax#}@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize) void{#endsyntax#}
This function copies bytes from one region of memory to another. {#syntax#}dest{#endsyntax#} and
{#syntax#}source{#endsyntax#} are both pointers and must not overlap.
@@ -8641,7 +8641,7 @@ mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#}
{#header_close#}
{#header_open|@memset#}
-
{#syntax#}@memset(dest: [*]u8, c: u8, byte_count: usize){#endsyntax#}
+ {#syntax#}@memset(dest: [*]u8, c: u8, byte_count: usize) void{#endsyntax#}
This function sets a region of memory to {#syntax#}c{#endsyntax#}. {#syntax#}dest{#endsyntax#} is a pointer.
@@ -8753,7 +8753,7 @@ test "@wasmMemoryGrow" {
{#header_close#}
{#header_open|@popCount#}
- {#syntax#}@popCount(operand: anytype){#endsyntax#}
+ {#syntax#}@popCount(operand: anytype) anytype{#endsyntax#}
{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type.
{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.
Counts the number of bits set in an integer.
@@ -8767,7 +8767,7 @@ test "@wasmMemoryGrow" {
{#header_close#}
{#header_open|@prefetch#}
- {#syntax#}@prefetch(ptr: anytype, comptime options: std.builtin.PrefetchOptions){#endsyntax#}
+ {#syntax#}@prefetch(ptr: anytype, comptime options: std.builtin.PrefetchOptions) void{#endsyntax#}
This builtin tells the compiler to emit a prefetch instruction if supported by the
target CPU. If the target CPU does not support the requested prefetch instruction,
@@ -8881,21 +8881,21 @@ pub const PrefetchOptions = struct {
{#header_close#}
{#header_open|@setAlignStack#}
-
{#syntax#}@setAlignStack(comptime alignment: u29){#endsyntax#}
+ {#syntax#}@setAlignStack(comptime alignment: u29) void{#endsyntax#}
Ensures that a function will have a stack alignment of at least {#syntax#}alignment{#endsyntax#} bytes.
{#header_close#}
{#header_open|@setCold#}
- {#syntax#}@setCold(comptime is_cold: bool){#endsyntax#}
+ {#syntax#}@setCold(comptime is_cold: bool) void{#endsyntax#}
Tells the optimizer that a function is rarely called.
{#header_close#}
{#header_open|@setEvalBranchQuota#}
- {#syntax#}@setEvalBranchQuota(comptime new_quota: u32){#endsyntax#}
+ {#syntax#}@setEvalBranchQuota(comptime new_quota: u32) void{#endsyntax#}
Changes the maximum number of backwards branches that compile-time code
execution can use before giving up and making a compile error.
@@ -8930,7 +8930,7 @@ test "foo" {
{#header_close#}
{#header_open|@setFloatMode#}
-
{#syntax#}@setFloatMode(comptime mode: @import("std").builtin.FloatMode){#endsyntax#}
+ {#syntax#}@setFloatMode(comptime mode: @import("std").builtin.FloatMode) void{#endsyntax#}
Sets the floating point mode of the current scope. Possible values are:
From ec445fb6b8bb3f3d423cafa4f3a7860da65ca233 Mon Sep 17 00:00:00 2001
From: John Schmidt
Date: Sat, 25 Feb 2023 20:44:53 +0100
Subject: [PATCH 069/216] Improve error messages for break type coercion
---
src/AstGen.zig | 169 ++++++++++++++----
src/Module.zig | 2 +-
src/Sema.zig | 75 +++++---
src/Zir.zig | 9 +-
src/print_zir.zig | 3 +-
.../incompatible sub-byte fields.zig | 2 +
.../compile_errors/missing_else_clause.zig | 2 +
.../missing_result_type_for_phi_node.zig | 2 +
.../unused_value_in_switch_in_loop.zig | 2 +
9 files changed, 199 insertions(+), 67 deletions(-)
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 182a28084f..c91303cdb1 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -1280,7 +1280,7 @@ fn fnProtoExpr(
defer param_gz.unstack();
const param_type = try expr(¶m_gz, scope, coerced_type_ri, param_type_node);
const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);
- _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type);
+ _ = try param_gz.addBreakWithSrcNode(.break_inline, param_inst_expected, param_type, param_type_node);
const main_tokens = tree.nodes.items(.main_token);
const name_token = param.name_token orelse main_tokens[param_type_node];
const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
@@ -1991,7 +1991,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
switch (block_gz.break_result_info.rl) {
.block_ptr => {
- const br = try parent_gz.addBreak(break_tag, block_inst, operand);
+ const br = try parent_gz.addBreakWithSrcNode(break_tag, block_inst, operand, rhs);
try block_gz.labeled_breaks.append(astgen.gpa, .{ .br = br, .search = search_index });
},
.ptr => {
@@ -2003,7 +2003,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
_ = try parent_gz.addBreak(break_tag, block_inst, .void_value);
},
else => {
- _ = try parent_gz.addBreak(break_tag, block_inst, operand);
+ _ = try parent_gz.addBreakWithSrcNode(break_tag, block_inst, operand, rhs);
},
}
return Zir.Inst.Ref.unreachable_value;
@@ -3754,7 +3754,7 @@ fn fnDecl(
defer param_gz.unstack();
const param_type = try expr(¶m_gz, params_scope, coerced_type_ri, param_type_node);
const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);
- _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type);
+ _ = try param_gz.addBreakWithSrcNode(.break_inline, param_inst_expected, param_type, param_type_node);
const main_tokens = tree.nodes.items(.main_token);
const name_token = param.name_token orelse main_tokens[param_type_node];
@@ -4114,7 +4114,7 @@ fn globalVarDecl(
};
// We do this at the end so that the instruction index marks the end
// range of a top level declaration.
- _ = try block_scope.addBreak(.break_inline, block_inst, var_inst);
+ _ = try block_scope.addBreakWithSrcNode(.break_inline, block_inst, var_inst, node);
try block_scope.setBlockBody(block_inst);
{
@@ -5456,7 +5456,9 @@ fn orelseCatchExpr(
condbr,
cond,
then_result,
+ node,
else_result,
+ rhs,
block,
block,
break_tag,
@@ -5475,7 +5477,9 @@ fn finishThenElseBlock(
condbr: Zir.Inst.Index,
cond: Zir.Inst.Ref,
then_result: Zir.Inst.Ref,
+ then_src_node: Ast.Node.Index,
else_result: Zir.Inst.Ref,
+ else_src_node: Ast.Node.Index,
main_block: Zir.Inst.Index,
then_break_block: Zir.Inst.Index,
break_tag: Zir.Inst.Tag,
@@ -5498,11 +5502,11 @@ fn finishThenElseBlock(
return indexToRef(main_block);
},
.break_operand => {
- const then_break = if (!then_no_return) try then_scope.makeBreak(break_tag, then_break_block, then_result) else 0;
+ const then_break = if (!then_no_return) try then_scope.makeBreakWithSrcNode(break_tag, then_break_block, then_result, then_src_node) else 0;
const else_break = if (else_result == .none)
try else_scope.makeBreak(break_tag, main_block, .void_value)
else if (!else_no_return)
- try else_scope.makeBreak(break_tag, main_block, else_result)
+ try else_scope.makeBreakWithSrcNode(break_tag, main_block, else_result, else_src_node)
else
0;
@@ -5683,7 +5687,7 @@ fn boolBinOp(
defer rhs_scope.unstack();
const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_ri, node_datas[node].rhs);
if (!gz.refIsNoReturn(rhs)) {
- _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);
+ _ = try rhs_scope.addBreakWithSrcNode(.break_inline, bool_br, rhs, node_datas[node].rhs);
}
try rhs_scope.setBoolBrBody(bool_br);
@@ -5758,6 +5762,7 @@ fn ifExpr(
var payload_val_scope: Scope.LocalVal = undefined;
try then_scope.addDbgBlockBegin();
+ const then_node = if_full.ast.then_expr;
const then_sub_scope = s: {
if (if_full.error_token != null) {
if (if_full.payload_token) |payload_token| {
@@ -5765,7 +5770,7 @@ fn ifExpr(
.err_union_payload_unsafe_ptr
else
.err_union_payload_unsafe;
- const payload_inst = try then_scope.addUnNode(tag, cond.inst, if_full.ast.then_expr);
+ const payload_inst = try then_scope.addUnNode(tag, cond.inst, then_node);
const token_name_index = payload_token + @boolToInt(payload_is_ref);
const ident_name = try astgen.identAsString(token_name_index);
const token_name_str = tree.tokenSlice(token_name_index);
@@ -5795,7 +5800,7 @@ fn ifExpr(
const ident_bytes = tree.tokenSlice(ident_token);
if (mem.eql(u8, "_", ident_bytes))
break :s &then_scope.base;
- const payload_inst = try then_scope.addUnNode(tag, cond.inst, if_full.ast.then_expr);
+ const payload_inst = try then_scope.addUnNode(tag, cond.inst, then_node);
const ident_name = try astgen.identAsString(ident_token);
try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes, .capture);
payload_val_scope = .{
@@ -5813,7 +5818,7 @@ fn ifExpr(
}
};
- const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_info, if_full.ast.then_expr);
+ const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_info, then_node);
if (!then_scope.endsWithNoReturn()) {
block_scope.break_count += 1;
}
@@ -5878,7 +5883,7 @@ fn ifExpr(
.result = e,
};
} else .{
- .src = if_full.ast.then_expr,
+ .src = then_node,
.result = switch (ri.rl) {
// Explicitly store void to ptr result loc if there is no else branch
.ptr, .block_ptr => try rvalue(&else_scope, ri, .void_value, node),
@@ -5897,7 +5902,9 @@ fn ifExpr(
condbr,
cond.bool_bit,
then_result,
+ then_node,
else_info.result,
+ else_info.src,
block,
block,
break_tag,
@@ -6185,6 +6192,7 @@ fn whileExpr(
then_scope.instructions_top = then_scope.instructions.items.len;
try then_scope.addDbgBlockBegin();
+ const then_node = while_full.ast.then_expr;
if (payload_inst != 0) try then_scope.instructions.append(astgen.gpa, payload_inst);
if (dbg_var_name) |name| try then_scope.addDbgVar(.dbg_var_val, name, dbg_var_inst);
try then_scope.instructions.append(astgen.gpa, continue_block);
@@ -6198,7 +6206,7 @@ fn whileExpr(
try then_scope.addDbgBlockEnd();
continue_scope.instructions_top = continue_scope.instructions.items.len;
- _ = try unusedResultExpr(&continue_scope, &continue_scope.base, while_full.ast.then_expr);
+ _ = try unusedResultExpr(&continue_scope, &continue_scope.base, then_node);
try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
if (!continue_scope.endsWithNoReturn()) {
@@ -6261,7 +6269,7 @@ fn whileExpr(
.result = else_result,
};
} else .{
- .src = while_full.ast.then_expr,
+ .src = then_node,
.result = .none,
};
@@ -6280,7 +6288,9 @@ fn whileExpr(
condbr,
cond.bool_bit,
.void_value,
+ then_node,
else_info.result,
+ else_info.src,
loop_block,
cond_block,
break_tag,
@@ -6468,6 +6478,7 @@ fn forExpr(
});
}
+ var then_node = for_full.ast.then_expr;
var then_scope = parent_gz.makeSubBlock(&cond_scope.base);
defer then_scope.unstack();
@@ -6535,8 +6546,8 @@ fn forExpr(
break :blk capture_sub_scope;
};
- const then_result = try expr(&then_scope, then_sub_scope, .{ .rl = .none }, for_full.ast.then_expr);
- _ = try addEnsureResult(&then_scope, then_result, for_full.ast.then_expr);
+ const then_result = try expr(&then_scope, then_sub_scope, .{ .rl = .none }, then_node);
+ _ = try addEnsureResult(&then_scope, then_result, then_node);
try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
try then_scope.addDbgBlockEnd();
@@ -6567,7 +6578,7 @@ fn forExpr(
.result = else_result,
};
} else .{
- .src = for_full.ast.then_expr,
+ .src = then_node,
.result = .none,
};
@@ -6587,7 +6598,9 @@ fn forExpr(
condbr,
cond,
then_result,
+ then_node,
else_info.result,
+ else_info.src,
loop_block,
cond_block,
break_tag,
@@ -6949,12 +6962,13 @@ fn switchExpr(
if (dbg_var_tag_name) |some| {
try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_tag_inst);
}
- const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_info, case.ast.target_expr);
+ const target_expr_node = case.ast.target_expr;
+ const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_info, target_expr_node);
try checkUsed(parent_gz, &case_scope.base, sub_scope);
try case_scope.addDbgBlockEnd();
if (!parent_gz.refIsNoReturn(case_result)) {
block_scope.break_count += 1;
- _ = try case_scope.addBreak(.@"break", switch_block, case_result);
+ _ = try case_scope.addBreakWithSrcNode(.@"break", switch_block, case_result, target_expr_node);
}
const case_slice = case_scope.instructionsSlice();
@@ -7057,10 +7071,12 @@ fn switchExpr(
.break_void => {
assert(!strat.elide_store_to_block_ptr_instructions);
const last_inst = payloads.items[end_index - 1];
- if (zir_tags[last_inst] == .@"break" and
- zir_datas[last_inst].@"break".block_inst == switch_block)
- {
- zir_datas[last_inst].@"break".operand = .void_value;
+ if (zir_tags[last_inst] == .@"break") {
+ const inst_data = zir_datas[last_inst].@"break";
+ const block_inst = astgen.extra.items[inst_data.payload_index];
+ if (block_inst == switch_block) {
+ zir_datas[last_inst].@"break".operand = .void_value;
+ }
}
},
}
@@ -8856,7 +8872,7 @@ fn callExpr(
// `call_inst` is reused to provide the param type.
arg_block.rl_ty_inst = call_inst;
const arg_ref = try expr(&arg_block, &arg_block.base, .{ .rl = .{ .coerced_ty = call_inst }, .ctx = .fn_arg }, param_node);
- _ = try arg_block.addBreak(.break_inline, call_index, arg_ref);
+ _ = try arg_block.addBreakWithSrcNode(.break_inline, call_index, arg_ref, param_node);
const body = arg_block.instructionsSlice();
try astgen.scratch.ensureUnusedCapacity(astgen.gpa, countBodyLenAfterFixups(astgen, body));
@@ -11262,35 +11278,40 @@ const GenZir = struct {
if (align_body.len != 0) {
astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, align_body));
astgen.appendBodyWithFixups(align_body);
- zir_datas[align_body[align_body.len - 1]].@"break".block_inst = new_index;
+ const inst_data = zir_datas[align_body[align_body.len - 1]].@"break";
+ astgen.extra.items[inst_data.payload_index] = new_index;
} else if (args.align_ref != .none) {
astgen.extra.appendAssumeCapacity(@enumToInt(args.align_ref));
}
if (addrspace_body.len != 0) {
astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, addrspace_body));
astgen.appendBodyWithFixups(addrspace_body);
- zir_datas[addrspace_body[addrspace_body.len - 1]].@"break".block_inst = new_index;
+ const inst_data = zir_datas[addrspace_body[addrspace_body.len - 1]].@"break";
+ astgen.extra.items[inst_data.payload_index] = new_index;
} else if (args.addrspace_ref != .none) {
astgen.extra.appendAssumeCapacity(@enumToInt(args.addrspace_ref));
}
if (section_body.len != 0) {
astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, section_body));
astgen.appendBodyWithFixups(section_body);
- zir_datas[section_body[section_body.len - 1]].@"break".block_inst = new_index;
+ const inst_data = zir_datas[section_body[section_body.len - 1]].@"break";
+ astgen.extra.items[inst_data.payload_index] = new_index;
} else if (args.section_ref != .none) {
astgen.extra.appendAssumeCapacity(@enumToInt(args.section_ref));
}
if (cc_body.len != 0) {
astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, cc_body));
astgen.appendBodyWithFixups(cc_body);
- zir_datas[cc_body[cc_body.len - 1]].@"break".block_inst = new_index;
+ const inst_data = zir_datas[cc_body[cc_body.len - 1]].@"break";
+ astgen.extra.items[inst_data.payload_index] = new_index;
} else if (args.cc_ref != .none) {
astgen.extra.appendAssumeCapacity(@enumToInt(args.cc_ref));
}
if (ret_body.len != 0) {
astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, ret_body));
astgen.appendBodyWithFixups(ret_body);
- zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index;
+ const inst_data = zir_datas[ret_body[ret_body.len - 1]].@"break";
+ astgen.extra.items[inst_data.payload_index] = new_index;
} else if (ret_ref != .none) {
astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref));
}
@@ -11344,7 +11365,9 @@ const GenZir = struct {
const zir_datas = astgen.instructions.items(.data);
if (ret_body.len != 0) {
astgen.appendBodyWithFixups(ret_body);
- zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index;
+
+ const inst_data = zir_datas[ret_body[ret_body.len - 1]].@"break";
+ astgen.extra.items[inst_data.payload_index] = new_index;
} else if (ret_ref != .none) {
astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref));
}
@@ -11790,30 +11813,104 @@ const GenZir = struct {
fn addBreak(
gz: *GenZir,
tag: Zir.Inst.Tag,
- break_block: Zir.Inst.Index,
+ block_inst: Zir.Inst.Index,
operand: Zir.Inst.Ref,
) !Zir.Inst.Index {
- return gz.addAsIndex(.{
+ const gpa = gz.astgen.gpa;
+ try gz.instructions.ensureUnusedCapacity(gpa, 1);
+ try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
+
+ const extra: Zir.Inst.Break = .{
+ .block_inst = block_inst,
+ .operand_src_node = Zir.Inst.Break.no_src_node,
+ };
+ const payload_index = try gz.astgen.addExtra(extra);
+ const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
+ gz.astgen.instructions.appendAssumeCapacity(.{
.tag = tag,
.data = .{ .@"break" = .{
- .block_inst = break_block,
.operand = operand,
+ .payload_index = payload_index,
} },
});
+ gz.instructions.appendAssumeCapacity(new_index);
+ return new_index;
}
fn makeBreak(
gz: *GenZir,
tag: Zir.Inst.Tag,
- break_block: Zir.Inst.Index,
+ block_inst: Zir.Inst.Index,
operand: Zir.Inst.Ref,
) !Zir.Inst.Index {
+ const gpa = gz.astgen.gpa;
+ try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
+
+ const extra: Zir.Inst.Break = .{
+ .block_inst = block_inst,
+ .operand_src_node = Zir.Inst.Break.no_src_node,
+ };
+ const payload_index = try gz.astgen.addExtra(extra);
const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
- try gz.astgen.instructions.append(gz.astgen.gpa, .{
+ gz.astgen.instructions.appendAssumeCapacity(.{
.tag = tag,
.data = .{ .@"break" = .{
- .block_inst = break_block,
.operand = operand,
+ .payload_index = payload_index,
+ } },
+ });
+ return new_index;
+ }
+
+ fn addBreakWithSrcNode(
+ gz: *GenZir,
+ tag: Zir.Inst.Tag,
+ block_inst: Zir.Inst.Index,
+ operand: Zir.Inst.Ref,
+ operand_src_node: Ast.Node.Index,
+ ) !Zir.Inst.Index {
+ const gpa = gz.astgen.gpa;
+ try gz.instructions.ensureUnusedCapacity(gpa, 1);
+ try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
+
+ const extra: Zir.Inst.Break = .{
+ .block_inst = block_inst,
+ .operand_src_node = gz.nodeIndexToRelative(operand_src_node),
+ };
+ const payload_index = try gz.astgen.addExtra(extra);
+ const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
+ gz.astgen.instructions.appendAssumeCapacity(.{
+ .tag = tag,
+ .data = .{ .@"break" = .{
+ .operand = operand,
+ .payload_index = payload_index,
+ } },
+ });
+ gz.instructions.appendAssumeCapacity(new_index);
+ return new_index;
+ }
+
+ fn makeBreakWithSrcNode(
+ gz: *GenZir,
+ tag: Zir.Inst.Tag,
+ block_inst: Zir.Inst.Index,
+ operand: Zir.Inst.Ref,
+ operand_src_node: Ast.Node.Index,
+ ) !Zir.Inst.Index {
+ const gpa = gz.astgen.gpa;
+ try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
+
+ const extra: Zir.Inst.Break = .{
+ .block_inst = block_inst,
+ .operand_src_node = gz.nodeIndexToRelative(operand_src_node),
+ };
+ const payload_index = try gz.astgen.addExtra(extra);
+ const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
+ gz.astgen.instructions.appendAssumeCapacity(.{
+ .tag = tag,
+ .data = .{ .@"break" = .{
+ .operand = operand,
+ .payload_index = payload_index,
} },
});
return new_index;
diff --git a/src/Module.zig b/src/Module.zig
index 17016865d1..906bde95c7 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -5949,7 +5949,7 @@ pub const PeerTypeCandidateSrc = union(enum) {
none: void,
/// When we want to know the the src of candidate i, look up at
/// index i in this slice
- override: []LazySrcLoc,
+ override: []?LazySrcLoc,
/// resolvePeerTypes originates from a @TypeOf(...) call
typeof_builtin_call_node_offset: i32,
diff --git a/src/Sema.zig b/src/Sema.zig
index d01535cdaa..13327657a8 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -349,6 +349,16 @@ pub const Block = struct {
/// if we need to add type coercion at the end of block analysis.
/// Same indexes, capacity, length as `results`.
br_list: std.ArrayListUnmanaged(Air.Inst.Index),
+ /// Keeps the source location of the rhs operand of the break instruction,
+ /// to enable more precise compile errors.
+ /// Same indexes, capacity, length as `results`.
+ src_locs: std.ArrayListUnmanaged(?LazySrcLoc),
+
+ pub fn deinit(merges: *@This(), allocator: mem.Allocator) void {
+ merges.results.deinit(allocator);
+ merges.br_list.deinit(allocator);
+ merges.src_locs.deinit(allocator);
+ }
};
/// For debugging purposes.
@@ -722,8 +732,7 @@ const LabeledBlock = struct {
fn destroy(lb: *LabeledBlock, gpa: Allocator) void {
lb.block.instructions.deinit(gpa);
- lb.label.merges.results.deinit(gpa);
- lb.label.merges.br_list.deinit(gpa);
+ lb.label.merges.deinit(gpa);
gpa.destroy(lb);
}
};
@@ -777,8 +786,9 @@ fn analyzeBodyRuntimeBreak(sema: *Sema, block: *Block, body: []const Zir.Inst.In
error.ComptimeBreak => {
const zir_datas = sema.code.instructions.items(.data);
const break_data = zir_datas[sema.comptime_break_inst].@"break";
+ const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data;
try sema.addRuntimeBreak(block, .{
- .block_inst = break_data.block_inst,
+ .block_inst = extra.block_inst,
.operand = break_data.operand,
.inst = sema.comptime_break_inst,
});
@@ -817,8 +827,9 @@ pub fn analyzeBodyBreak(
sema.typeOf(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])).isNoReturn())
return null;
const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
+ const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data;
return BreakData{
- .block_inst = break_data.block_inst,
+ .block_inst = extra.block_inst,
.operand = break_data.operand,
.inst = break_inst,
};
@@ -5238,6 +5249,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
var label: Block.Label = .{
.zir_block = inst,
.merges = .{
+ .src_locs = .{},
.results = .{},
.br_list = .{},
.block_inst = block_inst,
@@ -5251,8 +5263,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
const merges = &child_block.label.?.merges;
defer child_block.instructions.deinit(gpa);
- defer merges.results.deinit(gpa);
- defer merges.br_list.deinit(gpa);
+ defer merges.deinit(gpa);
var loop_block = child_block.makeSubBlock();
defer loop_block.instructions.deinit(gpa);
@@ -5422,6 +5433,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro
var label: Block.Label = .{
.zir_block = inst,
.merges = .{
+ .src_locs = .{},
.results = .{},
.br_list = .{},
.block_inst = block_inst,
@@ -5450,8 +5462,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro
};
defer child_block.instructions.deinit(gpa);
- defer label.merges.results.deinit(gpa);
- defer label.merges.br_list.deinit(gpa);
+ defer label.merges.deinit(gpa);
return sema.resolveBlockBody(parent_block, src, &child_block, body, inst, &label.merges);
}
@@ -5480,7 +5491,8 @@ fn resolveBlockBody(
const break_inst = sema.comptime_break_inst;
const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
- if (break_data.block_inst == body_inst) {
+ const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data;
+ if (extra.block_inst == body_inst) {
return try sema.resolveInst(break_data.operand);
} else {
return error.ComptimeBreak;
@@ -5533,7 +5545,7 @@ fn analyzeBlockBody(
// Need to set the type and emit the Block instruction. This allows machine code generation
// to emit a jump instruction to after the block when it encounters the break.
try parent_block.instructions.append(gpa, merges.block_inst);
- const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .none);
+ const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .{ .override = merges.src_locs.items });
// TODO add note "missing else causes void value"
const type_src = src; // TODO: better source location
@@ -5842,14 +5854,20 @@ fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[inst].@"break";
+ const extra = sema.code.extraData(Zir.Inst.Break, inst_data.payload_index).data;
const operand = try sema.resolveInst(inst_data.operand);
- const zir_block = inst_data.block_inst;
+ const zir_block = extra.block_inst;
var block = start_block;
while (true) {
if (block.label) |label| {
if (label.zir_block == zir_block) {
const br_ref = try start_block.addBr(label.merges.block_inst, operand);
+ const src_loc = if (extra.operand_src_node != Zir.Inst.Break.no_src_node)
+ LazySrcLoc.nodeOffset(extra.operand_src_node)
+ else
+ null;
+ try label.merges.src_locs.append(sema.gpa, src_loc);
try label.merges.results.append(sema.gpa, operand);
try label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?);
block.runtime_index.increment();
@@ -6643,6 +6661,7 @@ fn analyzeCall(
.func = null,
.comptime_result = undefined,
.merges = .{
+ .src_locs = .{},
.results = .{},
.br_list = .{},
.block_inst = block_inst,
@@ -6692,8 +6711,7 @@ fn analyzeCall(
const merges = &child_block.inlining.?.merges;
defer child_block.instructions.deinit(gpa);
- defer merges.results.deinit(gpa);
- defer merges.br_list.deinit(gpa);
+ defer merges.deinit(gpa);
// If it's a comptime function call, we need to memoize it as long as no external
// comptime memory is mutated.
@@ -10780,6 +10798,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
var label: Block.Label = .{
.zir_block = inst,
.merges = .{
+ .src_locs = .{},
.results = .{},
.br_list = .{},
.block_inst = block_inst,
@@ -10807,8 +10826,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
};
const merges = &child_block.label.?.merges;
defer child_block.instructions.deinit(gpa);
- defer merges.results.deinit(gpa);
- defer merges.br_list.deinit(gpa);
+ defer merges.deinit(gpa);
if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| {
var extra_index: usize = special.end;
@@ -12298,7 +12316,7 @@ fn zirBitwise(
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
- const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
+ const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } });
const scalar_type = resolved_type.scalarType();
const scalar_tag = scalar_type.zigTypeTag();
@@ -12502,7 +12520,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
try trash_block.addBitCast(rhs_info.elem_type, .void_value),
};
break :t try sema.resolvePeerTypes(block, src, &instructions, .{
- .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
+ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
};
@@ -13002,7 +13020,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
- .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
+ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
const is_vector = resolved_type.zigTypeTag() == .Vector;
@@ -13162,7 +13180,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
- .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
+ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
const is_vector = resolved_type.zigTypeTag() == .Vector;
@@ -13325,7 +13343,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
- .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
+ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
const is_vector = resolved_type.zigTypeTag() == .Vector;
@@ -13441,7 +13459,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
- .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
+ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
const is_vector = resolved_type.zigTypeTag() == .Vector;
@@ -13683,7 +13701,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
- .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
+ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
const is_vector = resolved_type.zigTypeTag() == .Vector;
@@ -13866,7 +13884,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
- .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
+ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
@@ -13968,7 +13986,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
- .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
+ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
@@ -14081,7 +14099,7 @@ fn zirOverflowArithmetic(
lhs_ty
else
try sema.resolvePeerTypes(block, src, instructions, .{
- .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
+ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
const rhs_dest_ty = if (zir_tag == .shl_with_overflow)
@@ -14312,7 +14330,7 @@ fn analyzeArithmetic(
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
- .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
+ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
const is_vector = resolved_type.zigTypeTag() == .Vector;
@@ -15200,7 +15218,7 @@ fn analyzeCmp(
return sema.cmpSelf(block, src, lhs, casted_rhs, op, lhs_src, rhs_src);
}
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
- const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
+ const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } });
if (!resolved_type.isSelfComparable(is_equality_cmp)) {
return sema.fail(block, src, "operator {s} not allowed for type '{}'", .{
compareOperatorName(op), resolved_type.fmt(sema.mod),
@@ -17024,6 +17042,7 @@ fn addRuntimeBreak(sema: *Sema, child_block: *Block, break_data: BreakData) !voi
.label = .{
.zir_block = break_data.block_inst,
.merges = .{
+ .src_locs = .{},
.results = .{},
.br_list = .{},
.block_inst = new_block_inst,
@@ -20605,7 +20624,7 @@ fn checkSimdBinOp(
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
var vec_len: ?usize = if (lhs_ty.zigTypeTag() == .Vector) lhs_ty.vectorLen() else null;
const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{
- .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
+ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
const lhs = try sema.coerce(block, result_ty, uncasted_lhs, lhs_src);
const rhs = try sema.coerce(block, result_ty, uncasted_rhs, rhs_src);
diff --git a/src/Zir.zig b/src/Zir.zig
index 001c4e8101..bc5202c8aa 100644
--- a/src/Zir.zig
+++ b/src/Zir.zig
@@ -2603,8 +2603,8 @@ pub const Inst = struct {
}
},
@"break": struct {
- block_inst: Index,
operand: Ref,
+ payload_index: u32,
},
switch_capture: struct {
switch_inst: Index,
@@ -2690,6 +2690,13 @@ pub const Inst = struct {
};
};
+ pub const Break = struct {
+ pub const no_src_node = std.math.maxInt(i32);
+
+ block_inst: Index,
+ operand_src_node: i32,
+ };
+
/// Trailing:
/// 0. Output for every outputs_len
/// 1. Input for every inputs_len
diff --git a/src/print_zir.zig b/src/print_zir.zig
index 5e7d0d45de..755107cd1a 100644
--- a/src/print_zir.zig
+++ b/src/print_zir.zig
@@ -2321,8 +2321,9 @@ const Writer = struct {
fn writeBreak(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[inst].@"break";
+ const extra = self.code.extraData(Zir.Inst.Break, inst_data.payload_index).data;
- try self.writeInstIndex(stream, inst_data.block_inst);
+ try self.writeInstIndex(stream, extra.block_inst);
try stream.writeAll(", ");
try self.writeInstRef(stream, inst_data.operand);
try stream.writeAll(")");
diff --git a/test/cases/compile_errors/incompatible sub-byte fields.zig b/test/cases/compile_errors/incompatible sub-byte fields.zig
index d765b7cf45..dc6f715c2f 100644
--- a/test/cases/compile_errors/incompatible sub-byte fields.zig
+++ b/test/cases/compile_errors/incompatible sub-byte fields.zig
@@ -25,3 +25,5 @@ export fn entry() void {
// target=native
//
// :14:17: error: incompatible types: '*align(1:0:1) u2' and '*align(2:8:2) u2'
+// :15:14: note: type '*align(1:0:1) u2' here
+// :16:14: note: type '*align(2:8:2) u2' here
diff --git a/test/cases/compile_errors/missing_else_clause.zig b/test/cases/compile_errors/missing_else_clause.zig
index 2e5fe9318f..a27408cb4c 100644
--- a/test/cases/compile_errors/missing_else_clause.zig
+++ b/test/cases/compile_errors/missing_else_clause.zig
@@ -31,7 +31,9 @@ export fn entry() void {
// target=native
//
// :2:21: error: incompatible types: 'i32' and 'void'
+// :6:25: note: type 'i32' here
// :6:15: error: incompatible types: 'i32' and 'void'
+// :2:31: note: type 'i32' here
// :12:16: error: expected type 'tmp.h.T', found 'void'
// :11:15: note: struct declared here
// :18:9: error: incompatible types: 'void' and 'tmp.k.T'
diff --git a/test/cases/compile_errors/missing_result_type_for_phi_node.zig b/test/cases/compile_errors/missing_result_type_for_phi_node.zig
index c4bd686b01..9e460ececb 100644
--- a/test/cases/compile_errors/missing_result_type_for_phi_node.zig
+++ b/test/cases/compile_errors/missing_result_type_for_phi_node.zig
@@ -10,3 +10,5 @@ export fn entry() void {
// target=native
//
// :5:11: error: incompatible types: 'void' and 'comptime_int'
+// :5:11: note: type 'void' here
+// :5:17: note: type 'comptime_int' here
diff --git a/test/cases/compile_errors/unused_value_in_switch_in_loop.zig b/test/cases/compile_errors/unused_value_in_switch_in_loop.zig
index 830262db4d..b74e016474 100644
--- a/test/cases/compile_errors/unused_value_in_switch_in_loop.zig
+++ b/test/cases/compile_errors/unused_value_in_switch_in_loop.zig
@@ -12,3 +12,5 @@ export fn entry() void {
// target=native
//
// :3:18: error: incompatible types: 'comptime_int' and 'void'
+// :4:14: note: type 'comptime_int' here
+// :5:16: note: type 'void' here
From 0787b11f19917ab4ae994cd12bc8ac5c96311683 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Roman=20Fro=C5=82ow?=
Date: Tue, 21 Mar 2023 14:12:13 +0100
Subject: [PATCH 070/216] naming: mid for index and mid_item for item
---
lib/std/sort.zig | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/lib/std/sort.zig b/lib/std/sort.zig
index 405ab658d1..d2b79db91b 100644
--- a/lib/std/sort.zig
+++ b/lib/std/sort.zig
@@ -9,7 +9,7 @@ pub fn binarySearch(
key: anytype,
items: []const T,
context: anytype,
- comptime compareFn: fn (context: @TypeOf(context), key: @TypeOf(key), mid: T) math.Order,
+ comptime compareFn: fn (context: @TypeOf(context), key: @TypeOf(key), mid_item: T) math.Order,
) ?usize {
var left: usize = 0;
var right: usize = items.len;
@@ -79,14 +79,14 @@ test "binarySearch" {
return @This(){ .b = b, .e = e };
}
- fn order(context: void, key: i32, mid: @This()) math.Order {
+ fn order(context: void, key: i32, mid_item: @This()) math.Order {
_ = context;
- if (key < mid.b) {
+ if (key < mid_item.b) {
return .lt;
}
- if (key > mid.e) {
+ if (key > mid_item.e) {
return .gt;
}
@@ -1069,8 +1069,8 @@ fn binaryFirst(
const offset = size % 2;
size /= 2;
- const mid = items[curr + size];
- if (lessThan(context, mid, value)) {
+ const mid_item = items[curr + size];
+ if (lessThan(context, mid_item, value)) {
curr += size + offset;
}
}
@@ -1092,8 +1092,8 @@ fn binaryLast(
const offset = size % 2;
size /= 2;
- const mid = items[curr + size];
- if (!lessThan(context, value, mid)) {
+ const mid_item = items[curr + size];
+ if (!lessThan(context, value, mid_item)) {
curr += size + offset;
}
}
From 83352678d433c9ffbda23b88066f628ab9d1c76d Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Tue, 21 Mar 2023 14:30:30 +0100
Subject: [PATCH 071/216] macho+zld: put __TEXT bound sections in __TEXT
segment
---
src/link/MachO/zld.zig | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig
index 17d122b30d..7a15782ae6 100644
--- a/src/link/MachO/zld.zig
+++ b/src/link/MachO/zld.zig
@@ -477,9 +477,9 @@ pub const Zld = struct {
mem.eql(u8, sectname, "__gosymtab") or
mem.eql(u8, sectname, "__gopclntab"))
{
- break :blk self.getSectionByName("__DATA_CONST", "__const") orelse try self.initSection(
- "__DATA_CONST",
- "__const",
+ break :blk self.getSectionByName("__TEXT", sectname) orelse try self.initSection(
+ "__TEXT",
+ sectname,
.{},
);
}
@@ -490,15 +490,13 @@ pub const Zld = struct {
mem.eql(u8, sectname, "__objc_classlist") or
mem.eql(u8, sectname, "__objc_imageinfo"))
{
- break :blk self.getSectionByName("__DATA_CONST", sectname) orelse
- try self.initSection(
+ break :blk self.getSectionByName("__DATA_CONST", sectname) orelse try self.initSection(
"__DATA_CONST",
sectname,
.{},
);
} else if (mem.eql(u8, sectname, "__data")) {
- break :blk self.getSectionByName("__DATA", "__data") orelse
- try self.initSection(
+ break :blk self.getSectionByName("__DATA", "__data") orelse try self.initSection(
"__DATA",
"__data",
.{},
From cb34d6f4362c8f5d806c0d0b328ea29e877d5c5f Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Tue, 21 Mar 2023 14:43:02 +0100
Subject: [PATCH 072/216] macho+zld: put locals and globals in function-starts
section
---
src/link/MachO/zld.zig | 29 +++++++++++++++++++----------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig
index 7a15782ae6..845a12276f 100644
--- a/src/link/MachO/zld.zig
+++ b/src/link/MachO/zld.zig
@@ -2298,9 +2298,16 @@ pub const Zld = struct {
const asc_u64 = std.sort.asc(u64);
+ fn addSymbolToFunctionStarts(self: *Zld, sym_loc: SymbolWithLoc, addresses: *std.ArrayList(u64)) !void {
+ const sym = self.getSymbol(sym_loc);
+ if (sym.n_strx == 0) return;
+ if (sym.n_desc == N_DEAD) return;
+ if (self.symbolIsTemp(sym_loc)) return;
+ try addresses.append(sym.n_value);
+ }
+
fn writeFunctionStarts(self: *Zld) !void {
const text_seg_index = self.getSegmentByName("__TEXT") orelse return;
- const text_sect_index = self.getSectionByName("__TEXT", "__text") orelse return;
const text_seg = self.segments.items[text_seg_index];
const gpa = self.gpa;
@@ -2308,17 +2315,18 @@ pub const Zld = struct {
// We need to sort by address first
var addresses = std.ArrayList(u64).init(gpa);
defer addresses.deinit();
- try addresses.ensureTotalCapacityPrecise(self.globals.items.len);
- for (self.globals.items) |global| {
- const sym = self.getSymbol(global);
- if (sym.undf()) continue;
- if (sym.n_desc == N_DEAD) continue;
+ for (self.objects.items) |object| {
+ for (object.exec_atoms.items) |atom_index| {
+ const atom = self.getAtom(atom_index);
+ const sym_loc = atom.getSymbolWithLoc();
+ try self.addSymbolToFunctionStarts(sym_loc, &addresses);
- const sect_id = sym.n_sect - 1;
- if (sect_id != text_sect_index) continue;
-
- addresses.appendAssumeCapacity(sym.n_value);
+ var it = Atom.getInnerSymbolsIterator(self, atom_index);
+ while (it.next()) |inner_sym_loc| {
+ try self.addSymbolToFunctionStarts(inner_sym_loc, &addresses);
+ }
+ }
}
std.sort.sort(u64, addresses.items, {}, asc_u64);
@@ -2457,6 +2465,7 @@ pub const Zld = struct {
fn addLocalToSymtab(self: *Zld, sym_loc: SymbolWithLoc, locals: *std.ArrayList(macho.nlist_64)) !void {
const sym = self.getSymbol(sym_loc);
if (sym.n_strx == 0) return; // no name, skip
+ if (sym.n_desc == N_DEAD) return; // garbage-collected, skip
if (sym.ext()) return; // an export lands in its own symtab section, skip
if (self.symbolIsTemp(sym_loc)) return; // local temp symbol, skip
From dc98009e36a344f8d0330af6b9e9226a2ba6a474 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Tue, 21 Mar 2023 16:12:25 +0100
Subject: [PATCH 073/216] macho+zld: save all defined globals in the export
trie
---
src/link/MachO/zld.zig | 39 +++++++++++----------------------------
1 file changed, 11 insertions(+), 28 deletions(-)
diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig
index 845a12276f..fe0ab16c92 100644
--- a/src/link/MachO/zld.zig
+++ b/src/link/MachO/zld.zig
@@ -2141,35 +2141,18 @@ pub const Zld = struct {
const exec_segment = self.segments.items[segment_index];
const base_address = exec_segment.vmaddr;
- if (self.options.output_mode == .Exe) {
- for (&[_]SymbolWithLoc{
- self.getEntryPoint(),
- self.globals.items[self.mh_execute_header_index.?],
- }) |global| {
- const sym = self.getSymbol(global);
- const sym_name = self.getSymbolName(global);
- log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
- try trie.put(gpa, .{
- .name = sym_name,
- .vmaddr_offset = sym.n_value - base_address,
- .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
- });
- }
- } else {
- assert(self.options.output_mode == .Lib);
- for (self.globals.items) |global| {
- const sym = self.getSymbol(global);
- if (sym.undf()) continue;
- if (sym.n_desc == N_DEAD) continue;
+ for (self.globals.items) |global| {
+ const sym = self.getSymbol(global);
+ if (sym.undf()) continue;
+ if (sym.n_desc == N_DEAD) continue;
- const sym_name = self.getSymbolName(global);
- log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
- try trie.put(gpa, .{
- .name = sym_name,
- .vmaddr_offset = sym.n_value - base_address,
- .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
- });
- }
+ const sym_name = self.getSymbolName(global);
+ log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
+ try trie.put(gpa, .{
+ .name = sym_name,
+ .vmaddr_offset = sym.n_value - base_address,
+ .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
+ });
}
try trie.finalize(gpa);
From 87e07d8671b469431340c615dcdd5a5332d198ec Mon Sep 17 00:00:00 2001
From: Veikka Tuominen
Date: Tue, 21 Mar 2023 20:57:14 +0200
Subject: [PATCH 074/216] fix broken test cases exposed by
ec445fb6b8bb3f3d423cafa4f3a7860da65ca233
shoulda rebased
---
test/cases/compile_errors/for_loop_break_value_ignored.zig | 1 +
test/cases/compile_errors/missing_else_clause.zig | 4 ++--
test/cases/compile_errors/while_loop_break_value_ignored.zig | 2 ++
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/test/cases/compile_errors/for_loop_break_value_ignored.zig b/test/cases/compile_errors/for_loop_break_value_ignored.zig
index a1119ec651..76a8c091f5 100644
--- a/test/cases/compile_errors/for_loop_break_value_ignored.zig
+++ b/test/cases/compile_errors/for_loop_break_value_ignored.zig
@@ -13,3 +13,4 @@ export fn f1() void {
// target=native
//
// :6:5: error: incompatible types: 'usize' and 'void'
+// :7:22: note: type 'usize' here
diff --git a/test/cases/compile_errors/missing_else_clause.zig b/test/cases/compile_errors/missing_else_clause.zig
index a27408cb4c..e96363b9cd 100644
--- a/test/cases/compile_errors/missing_else_clause.zig
+++ b/test/cases/compile_errors/missing_else_clause.zig
@@ -31,9 +31,9 @@ export fn entry() void {
// target=native
//
// :2:21: error: incompatible types: 'i32' and 'void'
-// :6:25: note: type 'i32' here
-// :6:15: error: incompatible types: 'i32' and 'void'
// :2:31: note: type 'i32' here
+// :6:15: error: incompatible types: 'i32' and 'void'
+// :6:25: note: type 'i32' here
// :12:16: error: expected type 'tmp.h.T', found 'void'
// :11:15: note: struct declared here
// :18:9: error: incompatible types: 'void' and 'tmp.k.T'
diff --git a/test/cases/compile_errors/while_loop_break_value_ignored.zig b/test/cases/compile_errors/while_loop_break_value_ignored.zig
index 2d14693fe5..e2f81d2b5f 100644
--- a/test/cases/compile_errors/while_loop_break_value_ignored.zig
+++ b/test/cases/compile_errors/while_loop_break_value_ignored.zig
@@ -23,4 +23,6 @@ export fn f2() void {
// target=native
//
// :7:5: error: incompatible types: 'usize' and 'void'
+// :8:22: note: type 'usize' here
// :14:12: error: incompatible types: 'usize' and 'void'
+// :16:33: note: type 'usize' here
From 1be86218153ae77109d785aafb29430f787adefd Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Tue, 21 Mar 2023 21:27:17 +0100
Subject: [PATCH 075/216] macho+zld: when finding by address, note the end of
section symbols too
Previously, if we were looking for the very last symbol by address in some
section, and the next symbol happened to also have the same address value
but would reside in a different section, we would keep going finding the
wrong symbol in the wrong section.
This mechanism turns out vital for correct linking of Go binaries
where the runtime looks for specially crafted synthetic symbols
which mark the beginning and end of each section. In this case,
we had an unfortunate clash between the end of PC marked machine code
section (`_runtime.etext`) and beginning of read-only data (`_runtime.rodata`).
---
src/link/MachO/Object.zig | 66 +++++++++++++++++++++-----------------
src/link/MachO/ZldAtom.zig | 3 +-
2 files changed, 39 insertions(+), 30 deletions(-)
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig
index fdcdb47224..a3e322179d 100644
--- a/src/link/MachO/Object.zig
+++ b/src/link/MachO/Object.zig
@@ -50,7 +50,7 @@ reverse_symtab_lookup: []u32 = undefined,
/// Can be undefined as set together with in_symtab.
source_address_lookup: []i64 = undefined,
/// Can be undefined as set together with in_symtab.
-source_section_index_lookup: []i64 = undefined,
+source_section_index_lookup: []Entry = undefined,
/// Can be undefined as set together with in_symtab.
strtab_lookup: []u32 = undefined,
/// Can be undefined as set together with in_symtab.
@@ -58,7 +58,7 @@ atom_by_index_table: []AtomIndex = undefined,
/// Can be undefined as set together with in_symtab.
globals_lookup: []i64 = undefined,
/// Can be undefined as set together with in_symtab.
-relocs_lookup: []RelocEntry = undefined,
+relocs_lookup: []Entry = undefined,
/// All relocations sorted and flatened, sorted by address descending
/// per section.
@@ -81,11 +81,14 @@ unwind_info_sect_id: ?u8 = null,
unwind_relocs_lookup: []Record = undefined,
unwind_records_lookup: std.AutoHashMapUnmanaged(AtomIndex, u32) = .{},
-const RelocEntry = struct { start: u32, len: u32 };
+const Entry = struct {
+ start: u32 = 0,
+ len: u32 = 0,
+};
const Record = struct {
dead: bool,
- reloc: RelocEntry,
+ reloc: Entry,
};
pub fn deinit(self: *Object, gpa: Allocator) void {
@@ -170,11 +173,11 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
self.strtab_lookup = try allocator.alloc(u32, self.in_symtab.?.len);
self.globals_lookup = try allocator.alloc(i64, self.in_symtab.?.len);
self.atom_by_index_table = try allocator.alloc(AtomIndex, self.in_symtab.?.len + nsects);
- self.relocs_lookup = try allocator.alloc(RelocEntry, self.in_symtab.?.len + nsects);
+ self.relocs_lookup = try allocator.alloc(Entry, self.in_symtab.?.len + nsects);
// This is wasteful but we need to be able to lookup source symbol address after stripping and
// allocating of sections.
self.source_address_lookup = try allocator.alloc(i64, self.in_symtab.?.len);
- self.source_section_index_lookup = try allocator.alloc(i64, nsects);
+ self.source_section_index_lookup = try allocator.alloc(Entry, nsects);
for (self.symtab) |*sym| {
sym.* = .{
@@ -188,11 +191,8 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
mem.set(i64, self.globals_lookup, -1);
mem.set(AtomIndex, self.atom_by_index_table, 0);
- mem.set(i64, self.source_section_index_lookup, -1);
- mem.set(RelocEntry, self.relocs_lookup, .{
- .start = 0,
- .len = 0,
- });
+ mem.set(Entry, self.source_section_index_lookup, .{});
+ mem.set(Entry, self.relocs_lookup, .{});
// You would expect that the symbol table is at least pre-sorted based on symbol's type:
// local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance,
@@ -211,12 +211,24 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
// is kind enough to specify the symbols in the correct order.
sort.sort(SymbolAtIndex, sorted_all_syms.items, self, SymbolAtIndex.lessThan);
+ var prev_sect_id: u8 = 0;
+ var section_index_lookup: ?Entry = null;
for (sorted_all_syms.items, 0..) |sym_id, i| {
const sym = sym_id.getSymbol(self);
- if (sym.sect() and self.source_section_index_lookup[sym.n_sect - 1] == -1) {
- self.source_section_index_lookup[sym.n_sect - 1] = @intCast(i64, i);
+ if (section_index_lookup) |*lookup| {
+ if (sym.n_sect != prev_sect_id or sym.undf()) {
+ self.source_section_index_lookup[prev_sect_id - 1] = lookup.*;
+ section_index_lookup = null;
+ } else {
+ lookup.len += 1;
+ }
}
+ if (sym.sect() and section_index_lookup == null) {
+ section_index_lookup = .{ .start = @intCast(u32, i), .len = 1 };
+ }
+
+ prev_sect_id = sym.n_sect;
self.symtab[i] = sym;
self.source_symtab_lookup[i] = sym_id.index;
@@ -234,13 +246,7 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
self.unwind_info_sect_id = self.getSourceSectionIndexByName("__LD", "__compact_unwind");
if (self.hasUnwindRecords()) {
self.unwind_relocs_lookup = try allocator.alloc(Record, self.getUnwindRecords().len);
- mem.set(Record, self.unwind_relocs_lookup, .{
- .dead = true,
- .reloc = .{
- .start = 0,
- .len = 0,
- },
- });
+ mem.set(Record, self.unwind_relocs_lookup, .{ .dead = true, .reloc = .{} });
}
}
@@ -620,7 +626,7 @@ fn filterRelocs(
relocs: []align(1) const macho.relocation_info,
start_addr: u64,
end_addr: u64,
-) RelocEntry {
+) Entry {
const Predicate = struct {
addr: u64,
@@ -712,9 +718,9 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
while (try it.next()) |record| {
const offset = it.pos - record.getSize();
- const rel_pos = switch (cpu_arch) {
+ const rel_pos: Entry = switch (cpu_arch) {
.aarch64 => filterRelocs(relocs, offset, offset + record.getSize()),
- .x86_64 => RelocEntry{ .start = 0, .len = 0 },
+ .x86_64 => .{},
else => unreachable,
};
self.eh_frame_relocs_lookup.putAssumeCapacityNoClobber(offset, .{
@@ -990,13 +996,15 @@ pub fn getSymbolByAddress(self: Object, addr: u64, sect_hint: ?u8) u32 {
};
if (sect_hint) |sect_id| {
- if (self.source_section_index_lookup[sect_id] > -1) {
- const first_sym_index = @intCast(usize, self.source_section_index_lookup[sect_id]);
- const target_sym_index = @import("zld.zig").lsearch(i64, self.source_address_lookup[first_sym_index..], Predicate{
- .addr = @intCast(i64, addr),
- });
+ if (self.source_section_index_lookup[sect_id].len > 0) {
+ const lookup = self.source_section_index_lookup[sect_id];
+ const target_sym_index = @import("zld.zig").lsearch(
+ i64,
+ self.source_address_lookup[lookup.start..][0..lookup.len],
+ Predicate{ .addr = @intCast(i64, addr) },
+ );
if (target_sym_index > 0) {
- return @intCast(u32, first_sym_index + target_sym_index - 1);
+ return @intCast(u32, lookup.start + target_sym_index - 1);
}
}
return self.getSectionAliasSymbolIndex(sect_id);
diff --git a/src/link/MachO/ZldAtom.zig b/src/link/MachO/ZldAtom.zig
index e3d5f62a12..eb5e1c6ded 100644
--- a/src/link/MachO/ZldAtom.zig
+++ b/src/link/MachO/ZldAtom.zig
@@ -790,10 +790,11 @@ fn resolveRelocsX86(
const target = parseRelocTarget(zld, atom_index, rel);
const rel_offset = @intCast(u32, rel.r_address - context.base_offset);
- log.debug(" RELA({s}) @ {x} => %{d} in object({?})", .{
+ log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{
@tagName(rel_type),
rel.r_address,
target.sym_index,
+ zld.getSymbolName(target),
target.getFile(),
});
From 8bffe87e9eeaf602d06eec60dffc955a86228fbd Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Tue, 21 Mar 2023 21:31:24 +0100
Subject: [PATCH 076/216] macho: collect all exports into the export trie
---
src/link/MachO.zig | 39 +++++++++++----------------------------
src/link/MachO/zld.zig | 4 +---
2 files changed, 12 insertions(+), 31 deletions(-)
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 151b947141..2f594d1fda 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -3340,36 +3340,19 @@ fn collectExportData(self: *MachO, trie: *Trie) !void {
const exec_segment = self.segments.items[self.header_segment_cmd_index.?];
const base_address = exec_segment.vmaddr;
- if (self.base.options.output_mode == .Exe) {
- for (&[_]SymbolWithLoc{
- try self.getEntryPoint(),
- self.getGlobal("__mh_execute_header").?,
- }) |global| {
- const sym = self.getSymbol(global);
- const sym_name = self.getSymbolName(global);
- log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
- try trie.put(gpa, .{
- .name = sym_name,
- .vmaddr_offset = sym.n_value - base_address,
- .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
- });
- }
- } else {
- assert(self.base.options.output_mode == .Lib);
- for (self.globals.items) |global| {
- const sym = self.getSymbol(global);
+ for (self.globals.items) |global| {
+ const sym = self.getSymbol(global);
- if (sym.undf()) continue;
- if (!sym.ext()) continue;
+ if (sym.undf()) continue;
+ if (!sym.ext()) continue;
- const sym_name = self.getSymbolName(global);
- log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
- try trie.put(gpa, .{
- .name = sym_name,
- .vmaddr_offset = sym.n_value - base_address,
- .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
- });
- }
+ const sym_name = self.getSymbolName(global);
+ log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
+ try trie.put(gpa, .{
+ .name = sym_name,
+ .vmaddr_offset = sym.n_value - base_address,
+ .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
+ });
}
try trie.finalize(gpa);
diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig
index fe0ab16c92..27a0fa5579 100644
--- a/src/link/MachO/zld.zig
+++ b/src/link/MachO/zld.zig
@@ -2158,9 +2158,7 @@ pub const Zld = struct {
try trie.finalize(gpa);
}
- fn writeDyldInfoData(
- self: *Zld,
- ) !void {
+ fn writeDyldInfoData(self: *Zld) !void {
const gpa = self.gpa;
var rebase = Rebase{};
From 84b89d7cfe452f91fa22f2646ef53a3a7e990456 Mon Sep 17 00:00:00 2001
From: Frank Denis <124872+jedisct1@users.noreply.github.com>
Date: Wed, 22 Mar 2023 07:17:52 +0100
Subject: [PATCH 077/216] crypto.hmac: set the recommended key size to the
block size (#15031)
HMAC supports arbitrary key sizes, and there are no practical reasons
to use more than 256 bit keys.
It still makes sense to match the security level, though, especially
since a distinction between the block size and the key size can be
confusing.
Using HMAC.key_size instead of HMAC.mac_size caused our TLS
implementation to compute wrong shared secrets when SHA-384 was
used. So, fix it directly in `crypto.hmac` in order to prevent
other misuses.
---
lib/std/crypto/hmac.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/std/crypto/hmac.zig b/lib/std/crypto/hmac.zig
index 457cc5ec18..f279132ee8 100644
--- a/lib/std/crypto/hmac.zig
+++ b/lib/std/crypto/hmac.zig
@@ -18,7 +18,7 @@ pub fn Hmac(comptime Hash: type) type {
const Self = @This();
pub const mac_length = Hash.digest_length;
pub const key_length_min = 0;
- pub const key_length = 32; // recommended key length
+ pub const key_length = mac_length; // recommended key length
o_key_pad: [Hash.block_length]u8,
hash: Hash,
From cc44183787adde8b83f9373dd53250f154058dc4 Mon Sep 17 00:00:00 2001
From: xEgoist
Date: Tue, 21 Mar 2023 09:03:50 -0500
Subject: [PATCH 078/216] Implemented getMaxRss for Windows
In Windows, the equivalent to maxrss is PeakWorkingSetSize which is
found in PROCESS_MEMORY_COUNTERS in bytes.
Currently, this is done by calling `GetProcessMemoryInfo` in kernel32.
---
lib/std/child_process.zig | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig
index 3748ca6877..72d7be4451 100644
--- a/lib/std/child_process.zig
+++ b/lib/std/child_process.zig
@@ -99,12 +99,20 @@ pub const ChildProcess = struct {
return null;
}
},
+ .windows => {
+ if (rus.rusage) |ru| {
+ return ru.PeakWorkingSetSize;
+ } else {
+ return null;
+ }
+ },
else => return null,
}
}
const rusage_init = switch (builtin.os.tag) {
.linux => @as(?std.os.rusage, null),
+ .windows => @as(?windows.PROCESS_MEMORY_COUNTERS, null),
else => {},
};
};
@@ -364,6 +372,13 @@ pub const ChildProcess = struct {
}
});
+ if (self.request_resource_usage_statistics) {
+ var pmc: windows.PROCESS_MEMORY_COUNTERS = undefined;
+ if (windows.kernel32.K32GetProcessMemoryInfo(self.id, &pmc, @sizeOf(windows.PROCESS_MEMORY_COUNTERS)) != 0) {
+ self.resource_usage_statistics.rusage = pmc;
+ }
+ }
+
os.close(self.id);
os.close(self.thread_handle);
self.cleanupStreams();
From 70469d428dd94693295b320a975b1ddf904dda3b Mon Sep 17 00:00:00 2001
From: xEgoist
Date: Wed, 22 Mar 2023 05:57:14 -0500
Subject: [PATCH 079/216] Implemented Zig wrapper for `GetProcessMemoryInfo`
`GetProcessMemoryInfo` is implemented using `NtQueryInformationProcess`
with `ProcessVmCounters` to obtain `VM_COUNTERS`. The structs, enum
definitions are found in `winternl.h` or `ntddk.h` in the latest WDK.
This should give the same results as using `K32GetProcessMemoryInfo`
---
lib/std/child_process.zig | 6 ++--
lib/std/os/windows.zig | 45 ++++++++++++++++++++++++++
lib/std/os/windows/ntdll.zig | 63 ++++++++++++++++++++++++++++++++++++
3 files changed, 111 insertions(+), 3 deletions(-)
diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig
index 72d7be4451..13fd40d982 100644
--- a/lib/std/child_process.zig
+++ b/lib/std/child_process.zig
@@ -137,6 +137,7 @@ pub const ChildProcess = struct {
os.SetIdError ||
os.ChangeCurDirError ||
windows.CreateProcessError ||
+ windows.GetProcessMemoryInfoError ||
windows.WaitForSingleObjectError;
pub const Term = union(enum) {
@@ -374,9 +375,8 @@ pub const ChildProcess = struct {
if (self.request_resource_usage_statistics) {
var pmc: windows.PROCESS_MEMORY_COUNTERS = undefined;
- if (windows.kernel32.K32GetProcessMemoryInfo(self.id, &pmc, @sizeOf(windows.PROCESS_MEMORY_COUNTERS)) != 0) {
- self.resource_usage_statistics.rusage = pmc;
- }
+ try windows.GetProcessMemoryInfo(self.id, &pmc);
+ self.resource_usage_statistics.rusage = pmc;
}
os.close(self.id);
diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig
index b385f68194..27f2ddb316 100644
--- a/lib/std/os/windows.zig
+++ b/lib/std/os/windows.zig
@@ -3947,6 +3947,20 @@ pub const PSAPI_WS_WATCH_INFORMATION = extern struct {
FaultingVa: LPVOID,
};
+pub const VM_COUNTERS = extern struct {
+ PeakVirtualSize: SIZE_T,
+ VirtualSize: SIZE_T,
+ PageFaultCount: ULONG,
+ PeakWorkingSetSize: SIZE_T,
+ WorkingSetSize: SIZE_T,
+ QuotaPeakPagedPoolUsage: SIZE_T,
+ QuotaPagedPoolUsage: SIZE_T,
+ QuotaPeakNonPagedPoolUsage: SIZE_T,
+ QuotaNonPagedPoolUsage: SIZE_T,
+ PagefileUsage: SIZE_T,
+ PeakPagefileUsage: SIZE_T,
+};
+
pub const PROCESS_MEMORY_COUNTERS = extern struct {
cb: DWORD,
PageFaultCount: DWORD,
@@ -3974,6 +3988,37 @@ pub const PROCESS_MEMORY_COUNTERS_EX = extern struct {
PrivateUsage: SIZE_T,
};
+pub const GetProcessMemoryInfoError = error{
+ AccessDenied,
+ InvalidHandle,
+ Unexpected,
+};
+
+pub fn GetProcessMemoryInfo(hProcess: HANDLE, out: *PROCESS_MEMORY_COUNTERS) GetProcessMemoryInfoError!void {
+ var vmc: VM_COUNTERS = undefined;
+ const rc = ntdll.NtQueryInformationProcess(hProcess, .ProcessVmCounters, &vmc, @sizeOf(VM_COUNTERS), null);
+ switch (rc) {
+ .SUCCESS => {
+ out.* = PROCESS_MEMORY_COUNTERS{
+ .cb = @sizeOf(PROCESS_MEMORY_COUNTERS),
+ .PageFaultCount = vmc.PageFaultCount,
+ .PeakWorkingSetSize = vmc.PeakWorkingSetSize,
+ .WorkingSetSize = vmc.WorkingSetSize,
+ .QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage,
+ .QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage,
+ .QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage,
+ .QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage,
+ .PagefileUsage = vmc.PagefileUsage,
+ .PeakPagefileUsage = vmc.PeakPagefileUsage,
+ };
+ },
+ .ACCESS_DENIED => return error.AccessDenied,
+ .INVALID_HANDLE => return error.InvalidHandle,
+ .INVALID_PARAMETER => unreachable,
+ else => return unexpectedStatus(rc),
+ }
+}
+
pub const PERFORMANCE_INFORMATION = extern struct {
cb: DWORD,
CommitTotal: SIZE_T,
diff --git a/lib/std/os/windows/ntdll.zig b/lib/std/os/windows/ntdll.zig
index 58cba356a2..3916e7d178 100644
--- a/lib/std/os/windows/ntdll.zig
+++ b/lib/std/os/windows/ntdll.zig
@@ -32,6 +32,69 @@ const RUNTIME_FUNCTION = windows.RUNTIME_FUNCTION;
const KNONVOLATILE_CONTEXT_POINTERS = windows.KNONVOLATILE_CONTEXT_POINTERS;
const EXCEPTION_ROUTINE = windows.EXCEPTION_ROUTINE;
+pub const PROCESSINFOCLASS = enum(c_int) {
+ ProcessBasicInformation,
+ ProcessQuotaLimits,
+ ProcessIoCounters,
+ ProcessVmCounters,
+ ProcessTimes,
+ ProcessBasePriority,
+ ProcessRaisePriority,
+ ProcessDebugPort,
+ ProcessExceptionPort,
+ ProcessAccessToken,
+ ProcessLdtInformation,
+ ProcessLdtSize,
+ ProcessDefaultHardErrorMode,
+ ProcessIoPortHandlers,
+ ProcessPooledUsageAndLimits,
+ ProcessWorkingSetWatch,
+ ProcessUserModeIOPL,
+ ProcessEnableAlignmentFaultFixup,
+ ProcessPriorityClass,
+ ProcessWx86Information,
+ ProcessHandleCount,
+ ProcessAffinityMask,
+ ProcessPriorityBoost,
+ ProcessDeviceMap,
+ ProcessSessionInformation,
+ ProcessForegroundInformation,
+ ProcessWow64Information,
+ ProcessImageFileName,
+ ProcessLUIDDeviceMapsEnabled,
+ ProcessBreakOnTermination,
+ ProcessDebugObjectHandle,
+ ProcessDebugFlags,
+ ProcessHandleTracing,
+ ProcessIoPriority,
+ ProcessExecuteFlags,
+ ProcessTlsInformation,
+ ProcessCookie,
+ ProcessImageInformation,
+ ProcessCycleTime,
+ ProcessPagePriority,
+ ProcessInstrumentationCallback,
+ ProcessThreadStackAllocation,
+ ProcessWorkingSetWatchEx,
+ ProcessImageFileNameWin32,
+ ProcessImageFileMapping,
+ ProcessAffinityUpdateMode,
+ ProcessMemoryAllocationMode,
+ ProcessGroupInformation,
+ ProcessTokenVirtualizationEnabled,
+ ProcessConsoleHostProcess,
+ ProcessWindowInformation,
+ MaxProcessInfoClass
+};
+
+pub extern "ntdll" fn NtQueryInformationProcess(
+ ProcessHandle: HANDLE,
+ ProcessInformationClass: PROCESSINFOCLASS,
+ ProcessInformation: *anyopaque,
+ ProcessInformationLength: ULONG,
+ ReturnLength: ?*ULONG,
+) callconv(WINAPI) NTSTATUS;
+
pub const THREADINFOCLASS = enum(c_int) {
ThreadBasicInformation,
ThreadTimes,
From c984201ddb10d2977290c6f1d6857e78573a2dff Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Wed, 22 Mar 2023 13:57:43 +0100
Subject: [PATCH 080/216] macho+zld: refactor parsing of relocation target
---
src/link/MachO/Object.zig | 26 ++++-----
src/link/MachO/UnwindInfo.zig | 74 ++++++-----------------
src/link/MachO/ZldAtom.zig | 107 +++++++++++++++++++++++-----------
src/link/MachO/dead_strip.zig | 77 ++++++++++++++++--------
src/link/MachO/eh_frame.zig | 26 ++++-----
src/link/MachO/thunks.zig | 11 +++-
src/link/MachO/zld.zig | 37 ++++++------
7 files changed, 198 insertions(+), 160 deletions(-)
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig
index a3e322179d..c6b86cce63 100644
--- a/src/link/MachO/Object.zig
+++ b/src/link/MachO/Object.zig
@@ -735,13 +735,12 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
assert(rel_pos.len > 0); // TODO convert to an error as the FDE eh frame is malformed
// Find function symbol that this record describes
const rel = relocs[rel_pos.start..][rel_pos.len - 1];
- const target = UnwindInfo.parseRelocTarget(
- zld,
- object_id,
- rel,
- it.data[offset..],
- @intCast(i32, offset),
- );
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = object_id,
+ .rel = rel,
+ .code = it.data[offset..],
+ .base_offset = @intCast(i32, offset),
+ });
break :blk target;
},
.x86_64 => {
@@ -825,13 +824,12 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
// Find function symbol that this record describes
const rel = relocs[rel_pos.start..][rel_pos.len - 1];
- const target = UnwindInfo.parseRelocTarget(
- zld,
- object_id,
- rel,
- mem.asBytes(&record),
- @intCast(i32, offset),
- );
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = object_id,
+ .rel = rel,
+ .code = mem.asBytes(&record),
+ .base_offset = @intCast(i32, offset),
+ });
log.debug("unwind record {d} tracks {s}", .{ record_id, zld.getSymbolName(target) });
if (target.getFile() != object_id) {
self.unwind_relocs_lookup[record_id].dead = true;
diff --git a/src/link/MachO/UnwindInfo.zig b/src/link/MachO/UnwindInfo.zig
index c64e617a35..e59f5fe250 100644
--- a/src/link/MachO/UnwindInfo.zig
+++ b/src/link/MachO/UnwindInfo.zig
@@ -218,13 +218,12 @@ pub fn scanRelocs(zld: *Zld) !void {
record_id,
)) |rel| {
// Personality function; add GOT pointer.
- const target = parseRelocTarget(
- zld,
- @intCast(u32, object_id),
- rel,
- mem.asBytes(&record),
- @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
- );
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = @intCast(u32, object_id),
+ .rel = rel,
+ .code = mem.asBytes(&record),
+ .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
+ });
try Atom.addGotEntry(zld, target);
}
}
@@ -266,13 +265,12 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
@intCast(u32, object_id),
record_id,
)) |rel| {
- const target = parseRelocTarget(
- zld,
- @intCast(u32, object_id),
- rel,
- mem.asBytes(&record),
- @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
- );
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = @intCast(u32, object_id),
+ .rel = rel,
+ .code = mem.asBytes(&record),
+ .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
+ });
const personality_index = info.getPersonalityFunction(target) orelse inner: {
const personality_index = info.personalities_count;
info.personalities[personality_index] = target;
@@ -285,13 +283,12 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
}
if (getLsdaReloc(zld, @intCast(u32, object_id), record_id)) |rel| {
- const target = parseRelocTarget(
- zld,
- @intCast(u32, object_id),
- rel,
- mem.asBytes(&record),
- @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
- );
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = @intCast(u32, object_id),
+ .rel = rel,
+ .code = mem.asBytes(&record),
+ .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
+ });
record.lsda = @bitCast(u64, target);
}
}
@@ -668,41 +665,6 @@ pub fn write(info: *UnwindInfo, zld: *Zld) !void {
try zld.file.pwriteAll(buffer.items, sect.offset);
}
-pub fn parseRelocTarget(
- zld: *Zld,
- object_id: u32,
- rel: macho.relocation_info,
- code: []const u8,
- base_offset: i32,
-) SymbolWithLoc {
- const tracy = trace(@src());
- defer tracy.end();
-
- const object = &zld.objects.items[object_id];
-
- const sym_index = if (rel.r_extern == 0) blk: {
- const sect_id = @intCast(u8, rel.r_symbolnum - 1);
- const rel_offset = @intCast(u32, rel.r_address - base_offset);
- assert(rel.r_pcrel == 0 and rel.r_length == 3);
- const address_in_section = mem.readIntLittle(u64, code[rel_offset..][0..8]);
- const sym_index = object.getSymbolByAddress(address_in_section, sect_id);
- break :blk sym_index;
- } else object.reverse_symtab_lookup[rel.r_symbolnum];
-
- const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id + 1 };
- const sym = zld.getSymbol(sym_loc);
-
- if (sym.sect() and !sym.ext()) {
- // Make sure we are not dealing with a local alias.
- const atom_index = object.getAtomIndexForSymbol(sym_index) orelse
- return sym_loc;
- const atom = zld.getAtom(atom_index);
- return atom.getSymbolWithLoc();
- } else if (object.getGlobal(sym_index)) |global_index| {
- return zld.globals.items[global_index];
- } else return sym_loc;
-}
-
fn getRelocs(zld: *Zld, object_id: u32, record_id: usize) []const macho.relocation_info {
const object = &zld.objects.items[object_id];
assert(object.hasUnwindRecords());
diff --git a/src/link/MachO/ZldAtom.zig b/src/link/MachO/ZldAtom.zig
index eb5e1c6ded..c47bce7c17 100644
--- a/src/link/MachO/ZldAtom.zig
+++ b/src/link/MachO/ZldAtom.zig
@@ -15,6 +15,7 @@ const macho = std.macho;
const math = std.math;
const mem = std.mem;
const meta = std.meta;
+const trace = @import("../../tracy.zig").trace;
const Allocator = mem.Allocator;
const Arch = std.Target.Cpu.Arch;
@@ -163,7 +164,7 @@ pub fn scanAtomRelocs(zld: *Zld, atom_index: AtomIndex, relocs: []align(1) const
}
const RelocContext = struct {
- base_addr: u64 = 0,
+ base_addr: i64 = 0,
base_offset: i32 = 0,
};
@@ -175,7 +176,7 @@ pub fn getRelocContext(zld: *Zld, atom_index: AtomIndex) RelocContext {
if (object.getSourceSymbol(atom.sym_index)) |source_sym| {
const source_sect = object.getSourceSection(source_sym.n_sect - 1);
return .{
- .base_addr = source_sect.addr,
+ .base_addr = @intCast(i64, source_sect.addr),
.base_offset = @intCast(i32, source_sym.n_value - source_sect.addr),
};
}
@@ -183,55 +184,71 @@ pub fn getRelocContext(zld: *Zld, atom_index: AtomIndex) RelocContext {
const sect_id = @intCast(u8, atom.sym_index - nbase);
const source_sect = object.getSourceSection(sect_id);
return .{
- .base_addr = source_sect.addr,
+ .base_addr = @intCast(i64, source_sect.addr),
.base_offset = 0,
};
}
-pub fn parseRelocTarget(zld: *Zld, atom_index: AtomIndex, rel: macho.relocation_info) SymbolWithLoc {
- const atom = zld.getAtom(atom_index);
- const object = &zld.objects.items[atom.getFile().?];
+pub fn parseRelocTarget(zld: *Zld, ctx: struct {
+ object_id: u32,
+ rel: macho.relocation_info,
+ code: []const u8,
+ base_addr: i64 = 0,
+ base_offset: i32 = 0,
+}) SymbolWithLoc {
+ const tracy = trace(@src());
+ defer tracy.end();
- const sym_index = if (rel.r_extern == 0) sym_index: {
- const sect_id = @intCast(u8, rel.r_symbolnum - 1);
- const ctx = getRelocContext(zld, atom_index);
- const atom_code = getAtomCode(zld, atom_index);
- const rel_offset = @intCast(u32, rel.r_address - ctx.base_offset);
+ const object = &zld.objects.items[ctx.object_id];
+ log.debug("parsing reloc target in object({d}) '{s}' ", .{ ctx.object_id, object.name });
- const address_in_section = if (rel.r_pcrel == 0) blk: {
- break :blk if (rel.r_length == 3)
- mem.readIntLittle(u64, atom_code[rel_offset..][0..8])
+ const sym_index = if (ctx.rel.r_extern == 0) sym_index: {
+ const sect_id = @intCast(u8, ctx.rel.r_symbolnum - 1);
+ const rel_offset = @intCast(u32, ctx.rel.r_address - ctx.base_offset);
+
+ const address_in_section = if (ctx.rel.r_pcrel == 0) blk: {
+ break :blk if (ctx.rel.r_length == 3)
+ mem.readIntLittle(u64, ctx.code[rel_offset..][0..8])
else
- mem.readIntLittle(u32, atom_code[rel_offset..][0..4]);
+ mem.readIntLittle(u32, ctx.code[rel_offset..][0..4]);
} else blk: {
- const correction: u3 = switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) {
+ assert(zld.options.target.cpu.arch == .x86_64);
+ const correction: u3 = switch (@intToEnum(macho.reloc_type_x86_64, ctx.rel.r_type)) {
.X86_64_RELOC_SIGNED => 0,
.X86_64_RELOC_SIGNED_1 => 1,
.X86_64_RELOC_SIGNED_2 => 2,
.X86_64_RELOC_SIGNED_4 => 4,
else => unreachable,
};
- const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
- const target_address = @intCast(i64, ctx.base_addr) + rel.r_address + 4 + correction + addend;
+ const addend = mem.readIntLittle(i32, ctx.code[rel_offset..][0..4]);
+ const target_address = @intCast(i64, ctx.base_addr) + ctx.rel.r_address + 4 + correction + addend;
break :blk @intCast(u64, target_address);
};
// Find containing atom
+ log.debug(" | locating symbol by address @{x} in section {d}", .{ address_in_section, sect_id });
const sym_index = object.getSymbolByAddress(address_in_section, sect_id);
break :sym_index sym_index;
- } else object.reverse_symtab_lookup[rel.r_symbolnum];
+ } else object.reverse_symtab_lookup[ctx.rel.r_symbolnum];
- const sym_loc = SymbolWithLoc{
- .sym_index = sym_index,
- .file = atom.file,
- };
+ const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = ctx.object_id + 1 };
const sym = zld.getSymbol(sym_loc);
-
- if (sym.sect() and !sym.ext()) {
- return sym_loc;
- } else if (object.getGlobal(sym_index)) |global_index| {
- return zld.globals.items[global_index];
- } else return sym_loc;
+ const target = target: {
+ if (sym.sect() and !sym.ext()) {
+ // Make sure we are not dealing with a local alias.
+ const atom_index = object.getAtomIndexForSymbol(sym_index) orelse break :target sym_loc;
+ const atom = zld.getAtom(atom_index);
+ break :target atom.getSymbolWithLoc();
+ } else if (object.getGlobal(sym_index)) |global_index| {
+ break :target zld.globals.items[global_index];
+ } else break :target sym_loc;
+ };
+ log.debug(" | target %{d} ('{s}') in object({?d})", .{
+ target.sym_index,
+ zld.getSymbolName(target),
+ target.getFile(),
+ });
+ return target;
}
pub fn getRelocTargetAtomIndex(zld: *Zld, target: SymbolWithLoc, is_via_got: bool) ?AtomIndex {
@@ -499,13 +516,25 @@ fn resolveRelocsArm64(
atom.getFile(),
});
- subtractor = parseRelocTarget(zld, atom_index, rel);
+ subtractor = parseRelocTarget(zld, .{
+ .object_id = atom.getFile().?,
+ .rel = rel,
+ .code = atom_code,
+ .base_addr = context.base_addr,
+ .base_offset = context.base_offset,
+ });
continue;
},
else => {},
}
- const target = parseRelocTarget(zld, atom_index, rel);
+ const target = parseRelocTarget(zld, .{
+ .object_id = atom.getFile().?,
+ .rel = rel,
+ .code = atom_code,
+ .base_addr = context.base_addr,
+ .base_offset = context.base_offset,
+ });
const rel_offset = @intCast(u32, rel.r_address - context.base_offset);
log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{
@@ -781,13 +810,25 @@ fn resolveRelocsX86(
atom.getFile(),
});
- subtractor = parseRelocTarget(zld, atom_index, rel);
+ subtractor = parseRelocTarget(zld, .{
+ .object_id = atom.getFile().?,
+ .rel = rel,
+ .code = atom_code,
+ .base_addr = context.base_addr,
+ .base_offset = context.base_offset,
+ });
continue;
},
else => {},
}
- const target = parseRelocTarget(zld, atom_index, rel);
+ const target = parseRelocTarget(zld, .{
+ .object_id = atom.getFile().?,
+ .rel = rel,
+ .code = atom_code,
+ .base_addr = context.base_addr,
+ .base_offset = context.base_offset,
+ });
const rel_offset = @intCast(u32, rel.r_address - context.base_offset);
log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{
diff --git a/src/link/MachO/dead_strip.zig b/src/link/MachO/dead_strip.zig
index a132ecb2de..cd64e72170 100644
--- a/src/link/MachO/dead_strip.zig
+++ b/src/link/MachO/dead_strip.zig
@@ -130,14 +130,29 @@ fn markLive(zld: *Zld, atom_index: AtomIndex, alive: *AtomTable) void {
const header = zld.sections.items(.header)[sym.n_sect - 1];
if (header.isZerofill()) return;
+ const code = Atom.getAtomCode(zld, atom_index);
const relocs = Atom.getAtomRelocs(zld, atom_index);
+ const ctx = Atom.getRelocContext(zld, atom_index);
+
for (relocs) |rel| {
const target = switch (cpu_arch) {
.aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {
.ARM64_RELOC_ADDEND => continue,
- else => Atom.parseRelocTarget(zld, atom_index, rel),
+ else => Atom.parseRelocTarget(zld, .{
+ .object_id = atom.getFile().?,
+ .rel = rel,
+ .code = code,
+ .base_offset = ctx.base_offset,
+ .base_addr = ctx.base_addr,
+ }),
},
- .x86_64 => Atom.parseRelocTarget(zld, atom_index, rel),
+ .x86_64 => Atom.parseRelocTarget(zld, .{
+ .object_id = atom.getFile().?,
+ .rel = rel,
+ .code = code,
+ .base_offset = ctx.base_offset,
+ .base_addr = ctx.base_addr,
+ }),
else => unreachable,
};
const target_sym = zld.getSymbol(target);
@@ -175,14 +190,29 @@ fn refersLive(zld: *Zld, atom_index: AtomIndex, alive: AtomTable) bool {
const header = zld.sections.items(.header)[sym.n_sect - 1];
assert(!header.isZerofill());
+ const code = Atom.getAtomCode(zld, atom_index);
const relocs = Atom.getAtomRelocs(zld, atom_index);
+ const ctx = Atom.getRelocContext(zld, atom_index);
+
for (relocs) |rel| {
const target = switch (cpu_arch) {
.aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {
.ARM64_RELOC_ADDEND => continue,
- else => Atom.parseRelocTarget(zld, atom_index, rel),
+ else => Atom.parseRelocTarget(zld, .{
+ .object_id = atom.getFile().?,
+ .rel = rel,
+ .code = code,
+ .base_offset = ctx.base_offset,
+ .base_addr = ctx.base_addr,
+ }),
},
- .x86_64 => Atom.parseRelocTarget(zld, atom_index, rel),
+ .x86_64 => Atom.parseRelocTarget(zld, .{
+ .object_id = atom.getFile().?,
+ .rel = rel,
+ .code = code,
+ .base_offset = ctx.base_offset,
+ .base_addr = ctx.base_addr,
+ }),
else => unreachable,
};
@@ -283,13 +313,12 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void {
try markEhFrameRecord(zld, object_id, atom_index, alive);
} else {
if (UnwindInfo.getPersonalityFunctionReloc(zld, object_id, record_id)) |rel| {
- const target = UnwindInfo.parseRelocTarget(
- zld,
- object_id,
- rel,
- mem.asBytes(&record),
- @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
- );
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = object_id,
+ .rel = rel,
+ .code = mem.asBytes(&record),
+ .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
+ });
const target_sym = zld.getSymbol(target);
if (!target_sym.undf()) {
const target_object = zld.objects.items[target.getFile().?];
@@ -299,13 +328,12 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void {
}
if (UnwindInfo.getLsdaReloc(zld, object_id, record_id)) |rel| {
- const target = UnwindInfo.parseRelocTarget(
- zld,
- object_id,
- rel,
- mem.asBytes(&record),
- @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
- );
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = object_id,
+ .rel = rel,
+ .code = mem.asBytes(&record),
+ .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
+ });
const target_object = zld.objects.items[target.getFile().?];
const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?;
markLive(zld, target_atom_index, alive);
@@ -333,13 +361,12 @@ fn markEhFrameRecord(zld: *Zld, object_id: u32, atom_index: AtomIndex, alive: *A
// Mark FDE references which should include any referenced LSDA record
const relocs = eh_frame.getRelocs(zld, object_id, fde_offset);
for (relocs) |rel| {
- const target = UnwindInfo.parseRelocTarget(
- zld,
- object_id,
- rel,
- fde.data,
- @intCast(i32, fde_offset) + 4,
- );
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = object_id,
+ .rel = rel,
+ .code = fde.data,
+ .base_offset = @intCast(i32, fde_offset) + 4,
+ });
const target_sym = zld.getSymbol(target);
if (!target_sym.undf()) blk: {
const target_object = zld.objects.items[target.getFile().?];
diff --git a/src/link/MachO/eh_frame.zig b/src/link/MachO/eh_frame.zig
index 5420bf6c29..7c5c5b7c25 100644
--- a/src/link/MachO/eh_frame.zig
+++ b/src/link/MachO/eh_frame.zig
@@ -308,13 +308,12 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
},
else => unreachable,
}
- const target = UnwindInfo.parseRelocTarget(
- zld,
- object_id,
- rel,
- rec.data,
- @intCast(i32, source_offset) + 4,
- );
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = object_id,
+ .rel = rel,
+ .code = rec.data,
+ .base_offset = @intCast(i32, source_offset) + 4,
+ });
return target;
}
return null;
@@ -331,13 +330,12 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
const relocs = getRelocs(zld, object_id, ctx.source_offset);
for (relocs) |rel| {
- const target = UnwindInfo.parseRelocTarget(
- zld,
- object_id,
- rel,
- rec.data,
- @intCast(i32, ctx.source_offset) + 4,
- );
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = object_id,
+ .rel = rel,
+ .code = rec.data,
+ .base_offset = @intCast(i32, ctx.source_offset) + 4,
+ });
const rel_offset = @intCast(u32, rel.r_address - @intCast(i32, ctx.source_offset) - 4);
const source_addr = ctx.sect_addr + rel_offset + ctx.out_offset + 4;
diff --git a/src/link/MachO/thunks.zig b/src/link/MachO/thunks.zig
index ce3fda0b1f..afea08750c 100644
--- a/src/link/MachO/thunks.zig
+++ b/src/link/MachO/thunks.zig
@@ -225,11 +225,20 @@ fn scanRelocs(
break :blk @intCast(i32, source_sym.n_value - source_sect.addr);
} else 0;
+ const code = Atom.getAtomCode(zld, atom_index);
const relocs = Atom.getAtomRelocs(zld, atom_index);
+ const ctx = Atom.getRelocContext(zld, atom_index);
+
for (relocs) |rel| {
if (!relocNeedsThunk(rel)) continue;
- const target = Atom.parseRelocTarget(zld, atom_index, rel);
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = atom.getFile().?,
+ .rel = rel,
+ .code = code,
+ .base_offset = ctx.base_offset,
+ .base_addr = ctx.base_addr,
+ });
if (isReachable(zld, atom_index, rel, base_offset, target, allocated)) continue;
log.debug("{x}: source = {s}@{x}, target = {s}@{x} unreachable", .{
diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig
index 27a0fa5579..07241b54cd 100644
--- a/src/link/MachO/zld.zig
+++ b/src/link/MachO/zld.zig
@@ -1884,13 +1884,9 @@ pub const Zld = struct {
if (should_rebase) {
log.debug(" ATOM({d}, %{d}, '{s}')", .{ atom_index, atom.sym_index, self.getSymbolName(atom.getSymbolWithLoc()) });
- const object = self.objects.items[atom.getFile().?];
- const base_rel_offset: i32 = blk: {
- const source_sym = object.getSourceSymbol(atom.sym_index) orelse break :blk 0;
- const source_sect = object.getSourceSection(source_sym.n_sect - 1);
- break :blk @intCast(i32, source_sym.n_value - source_sect.addr);
- };
+ const code = Atom.getAtomCode(self, atom_index);
const relocs = Atom.getAtomRelocs(self, atom_index);
+ const ctx = Atom.getRelocContext(self, atom_index);
for (relocs) |rel| {
switch (cpu_arch) {
@@ -1906,12 +1902,18 @@ pub const Zld = struct {
},
else => unreachable,
}
- const target = Atom.parseRelocTarget(self, atom_index, rel);
+ const target = Atom.parseRelocTarget(self, .{
+ .object_id = atom.getFile().?,
+ .rel = rel,
+ .code = code,
+ .base_offset = ctx.base_offset,
+ .base_addr = ctx.base_addr,
+ });
const target_sym = self.getSymbol(target);
if (target_sym.undf()) continue;
const base_offset = @intCast(i32, sym.n_value - segment.vmaddr);
- const rel_offset = rel.r_address - base_rel_offset;
+ const rel_offset = rel.r_address - ctx.base_offset;
const offset = @intCast(u64, base_offset + rel_offset);
log.debug(" | rebase at {x}", .{offset});
@@ -2021,13 +2023,9 @@ pub const Zld = struct {
};
if (should_bind) {
- const object = self.objects.items[atom.getFile().?];
- const base_rel_offset: i32 = blk: {
- const source_sym = object.getSourceSymbol(atom.sym_index) orelse break :blk 0;
- const source_sect = object.getSourceSection(source_sym.n_sect - 1);
- break :blk @intCast(i32, source_sym.n_value - source_sect.addr);
- };
+ const code = Atom.getAtomCode(self, atom_index);
const relocs = Atom.getAtomRelocs(self, atom_index);
+ const ctx = Atom.getRelocContext(self, atom_index);
for (relocs) |rel| {
switch (cpu_arch) {
@@ -2044,15 +2042,20 @@ pub const Zld = struct {
else => unreachable,
}
- const global = Atom.parseRelocTarget(self, atom_index, rel);
+ const global = Atom.parseRelocTarget(self, .{
+ .object_id = atom.getFile().?,
+ .rel = rel,
+ .code = code,
+ .base_offset = ctx.base_offset,
+ .base_addr = ctx.base_addr,
+ });
const bind_sym_name = self.getSymbolName(global);
const bind_sym = self.getSymbol(global);
if (!bind_sym.undf()) continue;
const base_offset = sym.n_value - segment.vmaddr;
- const rel_offset = @intCast(u32, rel.r_address - base_rel_offset);
+ const rel_offset = @intCast(u32, rel.r_address - ctx.base_offset);
const offset = @intCast(u64, base_offset + rel_offset);
- const code = Atom.getAtomCode(self, atom_index);
const addend = mem.readIntLittle(i64, code[rel_offset..][0..8]);
const dylib_ordinal = @divTrunc(@bitCast(i16, bind_sym.n_desc), macho.N_SYMBOL_RESOLVER);
From 1eb4264b7aa9e9e2b8ec46a95b508dfa7a7ab0f7 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Wed, 22 Mar 2023 15:13:52 +0100
Subject: [PATCH 081/216] macho+zld: make sure we populate source section index
lookup if no undefs
---
src/link/MachO/Object.zig | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig
index c6b86cce63..e407457e03 100644
--- a/src/link/MachO/Object.zig
+++ b/src/link/MachO/Object.zig
@@ -239,6 +239,12 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
self.strtab_lookup[i] = @intCast(u32, sym_name_len);
}
+ // If there were no undefined symbols, make sure we populate the
+ // source section index lookup for the last scanned section.
+ if (section_index_lookup) |lookup| {
+ self.source_section_index_lookup[prev_sect_id - 1] = lookup;
+ }
+
// Parse __TEXT,__eh_frame header if one exists
self.eh_frame_sect_id = self.getSourceSectionIndexByName("__TEXT", "__eh_frame");
From d61ac0db8c62f706ea65b70d2772cbb8c4efb416 Mon Sep 17 00:00:00 2001
From: Frank Denis <124872+jedisct1@users.noreply.github.com>
Date: Wed, 22 Mar 2023 17:58:24 +0100
Subject: [PATCH 082/216] TLS: Favor ChaCha over AES-based ciphers on CPUs
without AES support (#15034)
On CPUs without AES support, ChaCha is always faster and safer than
software AES.
Add `crypto.core.aes.has_hardware_support` to represent whether
AES acceleration is available or not, and in `tls.Client`, favor
AES-based ciphers only if hardware support is available.
This matches what BoringSSL is doing.
---
lib/std/crypto/aes.zig | 6 ++++++
lib/std/crypto/tls/Client.zig | 23 ++++++++++++++++-------
2 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/lib/std/crypto/aes.zig b/lib/std/crypto/aes.zig
index e2efa5bb90..f5d96a5fe8 100644
--- a/lib/std/crypto/aes.zig
+++ b/lib/std/crypto/aes.zig
@@ -14,6 +14,12 @@ impl: {
break :impl @import("aes/soft.zig");
};
+/// `true` if AES is backed by hardware (AES-NI on x86_64, ARM Crypto Extensions on AArch64).
+/// Software implementations are much slower, and should be avoided if possible.
+pub const has_hardware_support =
+ (builtin.cpu.arch == .x86_64 and has_aesni and has_avx) or
+ (builtin.cpu.arch == .aarch64 and has_armaes);
+
pub const Block = impl.Block;
pub const AesEncryptCtx = impl.AesEncryptCtx;
pub const AesDecryptCtx = impl.AesDecryptCtx;
diff --git a/lib/std/crypto/tls/Client.zig b/lib/std/crypto/tls/Client.zig
index 2b62d592ba..7c97a2ead0 100644
--- a/lib/std/crypto/tls/Client.zig
+++ b/lib/std/crypto/tls/Client.zig
@@ -1363,13 +1363,22 @@ fn limitVecs(iovecs: []std.os.iovec, len: usize) []std.os.iovec {
/// aegis-256: 461 MiB/s
/// aes128-gcm: 138 MiB/s
/// aes256-gcm: 120 MiB/s
-const cipher_suites = enum_array(tls.CipherSuite, &.{
- .AEGIS_128L_SHA256,
- .AEGIS_256_SHA384,
- .AES_128_GCM_SHA256,
- .AES_256_GCM_SHA384,
- .CHACHA20_POLY1305_SHA256,
-});
+const cipher_suites = if (crypto.core.aes.has_hardware_support)
+ enum_array(tls.CipherSuite, &.{
+ .AEGIS_128L_SHA256,
+ .AEGIS_256_SHA384,
+ .AES_128_GCM_SHA256,
+ .AES_256_GCM_SHA384,
+ .CHACHA20_POLY1305_SHA256,
+ })
+else
+ enum_array(tls.CipherSuite, &.{
+ .CHACHA20_POLY1305_SHA256,
+ .AEGIS_128L_SHA256,
+ .AEGIS_256_SHA384,
+ .AES_128_GCM_SHA256,
+ .AES_256_GCM_SHA384,
+ });
test {
_ = StreamInterface;
From 9fedecf4ab6035dca596648cd31ce85798ad69d5 Mon Sep 17 00:00:00 2001
From: Frank Denis <124872+jedisct1@users.noreply.github.com>
Date: Thu, 23 Mar 2023 10:05:58 +0100
Subject: [PATCH 083/216] http.Client: don't prematurely check
transfer_{encoding,compression} (#15040)
Common headers in a response are:
Content-Encoding: gzip
Transfer-Encoding: chunked
We used to return `HttpHeadersInvalid` if a `Transfer-Encoding` header
was received while the compression was already set.
However, Transfer-Encoding may not include compression. We should
only return an error if we are setting a value that was already set.
Fixes compatibility with a bunch of websites.
---
lib/std/http/Client/Response.zig | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/std/http/Client/Response.zig b/lib/std/http/Client/Response.zig
index 8b2a9a4918..f1a3b07dd8 100644
--- a/lib/std/http/Client/Response.zig
+++ b/lib/std/http/Client/Response.zig
@@ -74,8 +74,6 @@ pub const Headers = struct {
if (headers.content_length != null) return error.HttpHeadersInvalid;
headers.content_length = try std.fmt.parseInt(u64, header_value, 10);
} else if (std.ascii.eqlIgnoreCase(header_name, "transfer-encoding")) {
- if (headers.transfer_encoding != null or headers.transfer_compression != null) return error.HttpHeadersInvalid;
-
// Transfer-Encoding: second, first
// Transfer-Encoding: deflate, chunked
var iter = std.mem.splitBackwards(u8, header_value, ",");
@@ -84,8 +82,10 @@ pub const Headers = struct {
const trimmed = std.mem.trim(u8, first, " ");
if (std.meta.stringToEnum(http.TransferEncoding, trimmed)) |te| {
+ if (headers.transfer_encoding != null) return error.HttpHeadersInvalid;
headers.transfer_encoding = te;
} else if (std.meta.stringToEnum(http.ContentEncoding, trimmed)) |ce| {
+ if (headers.transfer_compression != null) return error.HttpHeadersInvalid;
headers.transfer_compression = ce;
} else {
return error.HttpTransferEncodingUnsupported;
From 38ee46dda31101f349ea9eee762908f924fd384c Mon Sep 17 00:00:00 2001
From: Phil Eaton
Date: Thu, 23 Mar 2023 05:06:46 -0400
Subject: [PATCH 084/216] Two more examples of possible syntax when dealing
with errors (#15042)
Add an example of if with try without else switch; add example of catch with block returning value
---
doc/langref.html.in | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index be055c3179..907464867e 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -5452,6 +5452,22 @@ fn doAThing(str: []u8) void {
a default value of 13. The type of the right hand side of the binary {#syntax#}catch{#endsyntax#} operator must
match the unwrapped error union type, or be of type {#syntax#}noreturn{#endsyntax#}.
+
+ If you want to provide a default value with
+ {#syntax#}catch{#endsyntax#} after performing some logic, you
+ can combine {#syntax#}catch{#endsyntax#} with named {#link|Blocks#}:
+
+ {#code_begin|syntax|handle_error_with_catch_block.zig#}
+const parseU64 = @import("error_union_parsing_u64.zig").parseU64;
+
+fn doAThing(str: []u8) void {
+ const number = parseU64(str, 10) catch blk: {
+ // do things
+ break :blk 13;
+ };
+ _ = number; // number is now initialized
+}
+ {#code_end#}
{#header_close#}
{#header_open|try#}
Let's say you wanted to return the error if you got one, otherwise continue with the
@@ -5509,6 +5525,20 @@ fn doAThing(str: []u8) void {
// we promise that InvalidChar won't happen (or crash in debug mode if it does)
error.InvalidChar => unreachable,
}
+}
+ {#end_syntax_block#}
+
+ You must use the variable capture syntax. If you don't need the
+ variable, you can capture with {#syntax#}_{#endsyntax#} and avoid the
+ {#syntax#}switch{#endsyntax#}.
+
+ {#syntax_block|zig|handle_no_error_scenarios.zig#}
+fn doADifferentThing(str: []u8) void {
+ if (parseU64(str, 10)) |number| {
+ doSomethingWithNumber(number);
+ } else |_| {
+ // do as you'd like
+ }
}
{#end_syntax_block#}
{#header_open|errdefer#}
From 2f5af6c9721a125f3308b55f5a8059d62e5d2ec7 Mon Sep 17 00:00:00 2001
From: xEgoist
Date: Thu, 23 Mar 2023 06:13:26 -0500
Subject: [PATCH 085/216] Refactored GetProcessMemoryInfo to return
`VM_COUNTERS`
This change allows the function to return the process memory info
directly instead of copying the result of the underlying Nt function.
---
lib/std/child_process.zig | 6 ++----
lib/std/os/windows.zig | 17 ++---------------
2 files changed, 4 insertions(+), 19 deletions(-)
diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig
index 13fd40d982..ca447b068d 100644
--- a/lib/std/child_process.zig
+++ b/lib/std/child_process.zig
@@ -112,7 +112,7 @@ pub const ChildProcess = struct {
const rusage_init = switch (builtin.os.tag) {
.linux => @as(?std.os.rusage, null),
- .windows => @as(?windows.PROCESS_MEMORY_COUNTERS, null),
+ .windows => @as(?windows.VM_COUNTERS, null),
else => {},
};
};
@@ -374,9 +374,7 @@ pub const ChildProcess = struct {
});
if (self.request_resource_usage_statistics) {
- var pmc: windows.PROCESS_MEMORY_COUNTERS = undefined;
- try windows.GetProcessMemoryInfo(self.id, &pmc);
- self.resource_usage_statistics.rusage = pmc;
+ self.resource_usage_statistics.rusage = try windows.GetProcessMemoryInfo(self.id);
}
os.close(self.id);
diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig
index 27f2ddb316..fe0a68a13a 100644
--- a/lib/std/os/windows.zig
+++ b/lib/std/os/windows.zig
@@ -3994,24 +3994,11 @@ pub const GetProcessMemoryInfoError = error{
Unexpected,
};
-pub fn GetProcessMemoryInfo(hProcess: HANDLE, out: *PROCESS_MEMORY_COUNTERS) GetProcessMemoryInfoError!void {
+pub fn GetProcessMemoryInfo(hProcess: HANDLE) GetProcessMemoryInfoError!VM_COUNTERS {
var vmc: VM_COUNTERS = undefined;
const rc = ntdll.NtQueryInformationProcess(hProcess, .ProcessVmCounters, &vmc, @sizeOf(VM_COUNTERS), null);
switch (rc) {
- .SUCCESS => {
- out.* = PROCESS_MEMORY_COUNTERS{
- .cb = @sizeOf(PROCESS_MEMORY_COUNTERS),
- .PageFaultCount = vmc.PageFaultCount,
- .PeakWorkingSetSize = vmc.PeakWorkingSetSize,
- .WorkingSetSize = vmc.WorkingSetSize,
- .QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage,
- .QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage,
- .QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage,
- .QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage,
- .PagefileUsage = vmc.PagefileUsage,
- .PeakPagefileUsage = vmc.PeakPagefileUsage,
- };
- },
+ .SUCCESS => return vmc,
.ACCESS_DENIED => return error.AccessDenied,
.INVALID_HANDLE => return error.InvalidHandle,
.INVALID_PARAMETER => unreachable,
From 8f4548dd69de3a1c1f5c14cdf6b2e7052ea5079f Mon Sep 17 00:00:00 2001
From: xEgoist
Date: Thu, 23 Mar 2023 06:17:05 -0500
Subject: [PATCH 086/216] fmt: lib/std/os/windows/ntdll.zig
---
lib/std/os/windows/ntdll.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/std/os/windows/ntdll.zig b/lib/std/os/windows/ntdll.zig
index 3916e7d178..429b36039e 100644
--- a/lib/std/os/windows/ntdll.zig
+++ b/lib/std/os/windows/ntdll.zig
@@ -84,7 +84,7 @@ pub const PROCESSINFOCLASS = enum(c_int) {
ProcessTokenVirtualizationEnabled,
ProcessConsoleHostProcess,
ProcessWindowInformation,
- MaxProcessInfoClass
+ MaxProcessInfoClass,
};
pub extern "ntdll" fn NtQueryInformationProcess(
From 4d31e3c917a05541394c544708f0047cfb53331a Mon Sep 17 00:00:00 2001
From: Mateusz Poliwczak
Date: Thu, 23 Mar 2023 18:01:21 +0100
Subject: [PATCH 087/216] std.base64: don't overflow dest with padding
---
lib/std/base64.zig | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/lib/std/base64.zig b/lib/std/base64.zig
index 83f07b9c18..d9bf7d4a07 100644
--- a/lib/std/base64.zig
+++ b/lib/std/base64.zig
@@ -117,7 +117,7 @@ pub const Base64Encoder = struct {
out_idx += 1;
}
if (encoder.pad_char) |pad_char| {
- for (dest[out_idx..]) |*pad| {
+ for (dest[out_idx..out_len]) |*pad| {
pad.* = pad_char;
}
}
@@ -305,6 +305,20 @@ test "base64" {
comptime try testAllApis(standard, "comptime", "Y29tcHRpbWU=");
}
+test "base64 padding dest overflow" {
+ const input = "foo";
+
+ var expect: [128]u8 = undefined;
+ std.mem.set(u8, &expect, 0);
+ _ = url_safe.Encoder.encode(expect[0..url_safe.Encoder.calcSize(input.len)], input);
+
+ var got: [128]u8 = undefined;
+ std.mem.set(u8, &got, 0);
+ _ = url_safe.Encoder.encode(&got, input);
+
+ try std.testing.expectEqualSlices(u8, &expect, &got);
+}
+
test "base64 url_safe_no_pad" {
@setEvalBranchQuota(8000);
try testBase64UrlSafeNoPad();
From dcdb878360045ec50fc0cc6fda0f970150567182 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Thu, 23 Mar 2023 19:10:30 +0100
Subject: [PATCH 088/216] macho+zld: only check for alias symbols for
non-extern relocations
---
src/link/MachO/ZldAtom.zig | 29 ++++++++++++++---------------
1 file changed, 14 insertions(+), 15 deletions(-)
diff --git a/src/link/MachO/ZldAtom.zig b/src/link/MachO/ZldAtom.zig
index c47bce7c17..e701ee2a13 100644
--- a/src/link/MachO/ZldAtom.zig
+++ b/src/link/MachO/ZldAtom.zig
@@ -227,22 +227,21 @@ pub fn parseRelocTarget(zld: *Zld, ctx: struct {
// Find containing atom
log.debug(" | locating symbol by address @{x} in section {d}", .{ address_in_section, sect_id });
- const sym_index = object.getSymbolByAddress(address_in_section, sect_id);
- break :sym_index sym_index;
+ const candidate = object.getSymbolByAddress(address_in_section, sect_id);
+ // Make sure we are not dealing with a local alias.
+ const atom_index = object.getAtomIndexForSymbol(candidate) orelse break :sym_index candidate;
+ const atom = zld.getAtom(atom_index);
+ break :sym_index atom.sym_index;
} else object.reverse_symtab_lookup[ctx.rel.r_symbolnum];
const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = ctx.object_id + 1 };
const sym = zld.getSymbol(sym_loc);
- const target = target: {
- if (sym.sect() and !sym.ext()) {
- // Make sure we are not dealing with a local alias.
- const atom_index = object.getAtomIndexForSymbol(sym_index) orelse break :target sym_loc;
- const atom = zld.getAtom(atom_index);
- break :target atom.getSymbolWithLoc();
- } else if (object.getGlobal(sym_index)) |global_index| {
- break :target zld.globals.items[global_index];
- } else break :target sym_loc;
- };
+ const target = if (sym.sect() and !sym.ext())
+ sym_loc
+ else if (object.getGlobal(sym_index)) |global_index|
+ zld.globals.items[global_index]
+ else
+ sym_loc;
log.debug(" | target %{d} ('{s}') in object({?d})", .{
target.sym_index,
zld.getSymbolName(target),
@@ -752,7 +751,7 @@ fn resolveRelocsArm64(
mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
if (rel.r_extern == 0) {
- const base_addr = if (target.sym_index > object.source_address_lookup.len)
+ const base_addr = if (target.sym_index >= object.source_address_lookup.len)
@intCast(i64, object.getSourceSection(@intCast(u8, rel.r_symbolnum - 1)).addr)
else
object.source_address_lookup[target.sym_index];
@@ -902,7 +901,7 @@ fn resolveRelocsX86(
var addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]) + correction;
if (rel.r_extern == 0) {
- const base_addr = if (target.sym_index > object.source_address_lookup.len)
+ const base_addr = if (target.sym_index >= object.source_address_lookup.len)
@intCast(i64, object.getSourceSection(@intCast(u8, rel.r_symbolnum - 1)).addr)
else
object.source_address_lookup[target.sym_index];
@@ -925,7 +924,7 @@ fn resolveRelocsX86(
mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
if (rel.r_extern == 0) {
- const base_addr = if (target.sym_index > object.source_address_lookup.len)
+ const base_addr = if (target.sym_index >= object.source_address_lookup.len)
@intCast(i64, object.getSourceSection(@intCast(u8, rel.r_symbolnum - 1)).addr)
else
object.source_address_lookup[target.sym_index];
From 5d2892740a842378fd03ced7af1c1ce6d1411539 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Thu, 23 Mar 2023 22:34:31 +0100
Subject: [PATCH 089/216] build: when parsing rpaths, do not expand special
runtime paths on Darwin
Special runtime paths on Darwin are: `@executable_path` and `@loader_path`.
---
lib/std/Build/CompileStep.zig | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/lib/std/Build/CompileStep.zig b/lib/std/Build/CompileStep.zig
index 72855f360e..2747f56af2 100644
--- a/lib/std/Build/CompileStep.zig
+++ b/lib/std/Build/CompileStep.zig
@@ -1725,6 +1725,22 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
try zig_args.ensureUnusedCapacity(2 * self.rpaths.items.len);
for (self.rpaths.items) |rpath| {
zig_args.appendAssumeCapacity("-rpath");
+
+ if (self.target_info.target.isDarwin()) switch (rpath) {
+ .path => |path| {
+ // On Darwin, we should not try to expand special runtime paths such as
+ // * @executable_path
+ // * @loader_path
+ if (mem.startsWith(u8, path, "@executable_path") or
+ mem.startsWith(u8, path, "@loader_path"))
+ {
+ zig_args.appendAssumeCapacity(path);
+ continue;
+ }
+ },
+ .generated => {},
+ };
+
zig_args.appendAssumeCapacity(rpath.getPath2(b, step));
}
From 145f93ba961fb9eea66a39b60e93c2aa5e26ee40 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Thu, 23 Mar 2023 23:46:49 +0100
Subject: [PATCH 090/216] build: allow for deferred FileSource matching in
CheckObjectStep
Re-enable all of functionality of MachO dylib test.
---
lib/std/Build/CheckObjectStep.zig | 83 ++++++++++++++++++++-----------
test/link/macho/dylib/build.zig | 5 +-
2 files changed, 56 insertions(+), 32 deletions(-)
diff --git a/lib/std/Build/CheckObjectStep.zig b/lib/std/Build/CheckObjectStep.zig
index 7cac2d04ec..fbeb87baee 100644
--- a/lib/std/Build/CheckObjectStep.zig
+++ b/lib/std/Build/CheckObjectStep.zig
@@ -58,6 +58,16 @@ pub fn runAndCompare(self: *CheckObjectStep) *std.Build.RunStep {
return run;
}
+const SearchPhrase = struct {
+ string: []const u8,
+ file_source: ?std.Build.FileSource = null,
+
+ fn resolve(phrase: SearchPhrase, b: *std.Build, step: *Step) []const u8 {
+ const file_source = phrase.file_source orelse return phrase.string;
+ return b.fmt("{s} {s}", .{ phrase.string, file_source.getPath2(b, step) });
+ }
+};
+
/// There two types of actions currently suported:
/// * `.match` - is the main building block of standard matchers with optional eat-all token `{*}`
/// and extractors by name such as `{n_value}`. Please note this action is very simplistic in nature
@@ -72,7 +82,7 @@ pub fn runAndCompare(self: *CheckObjectStep) *std.Build.RunStep {
/// they could then be added with this simple program `vmaddr entryoff +`.
const Action = struct {
tag: enum { match, not_present, compute_cmp },
- phrase: []const u8,
+ phrase: SearchPhrase,
expected: ?ComputeCompareExpected = null,
/// Will return true if the `phrase` was found in the `haystack`.
@@ -83,12 +93,18 @@ const Action = struct {
/// and save under `vmaddr` global name (see `global_vars` param)
/// name {*}libobjc{*}.dylib => will match `name` followed by a token which contains `libobjc` and `.dylib`
/// in that order with other letters in between
- fn match(act: Action, haystack: []const u8, global_vars: anytype) !bool {
+ fn match(
+ act: Action,
+ b: *std.Build,
+ step: *Step,
+ haystack: []const u8,
+ global_vars: anytype,
+ ) !bool {
assert(act.tag == .match or act.tag == .not_present);
-
+ const phrase = act.phrase.resolve(b, step);
var candidate_var: ?struct { name: []const u8, value: u64 } = null;
var hay_it = mem.tokenize(u8, mem.trim(u8, haystack, " "), " ");
- var needle_it = mem.tokenize(u8, mem.trim(u8, act.phrase, " "), " ");
+ var needle_it = mem.tokenize(u8, mem.trim(u8, phrase, " "), " ");
while (needle_it.next()) |needle_tok| {
const hay_tok = hay_it.next() orelse return false;
@@ -133,12 +149,13 @@ const Action = struct {
/// Will return true if the `phrase` is correctly parsed into an RPN program and
/// its reduced, computed value compares using `op` with the expected value, either
/// a literal or another extracted variable.
- fn computeCmp(act: Action, step: *Step, global_vars: anytype) !bool {
+ fn computeCmp(act: Action, b: *std.Build, step: *Step, global_vars: anytype) !bool {
const gpa = step.owner.allocator;
+ const phrase = act.phrase.resolve(b, step);
var op_stack = std.ArrayList(enum { add, sub, mod, mul }).init(gpa);
var values = std.ArrayList(u64).init(gpa);
- var it = mem.tokenize(u8, act.phrase, " ");
+ var it = mem.tokenize(u8, phrase, " ");
while (it.next()) |next| {
if (mem.eql(u8, next, "+")) {
try op_stack.append(.add);
@@ -225,34 +242,32 @@ const ComputeCompareExpected = struct {
};
const Check = struct {
- builder: *std.Build,
actions: std.ArrayList(Action),
- fn create(b: *std.Build) Check {
+ fn create(allocator: Allocator) Check {
return .{
- .builder = b,
- .actions = std.ArrayList(Action).init(b.allocator),
+ .actions = std.ArrayList(Action).init(allocator),
};
}
- fn match(self: *Check, phrase: []const u8) void {
+ fn match(self: *Check, phrase: SearchPhrase) void {
self.actions.append(.{
.tag = .match,
- .phrase = self.builder.dupe(phrase),
+ .phrase = phrase,
}) catch @panic("OOM");
}
- fn notPresent(self: *Check, phrase: []const u8) void {
+ fn notPresent(self: *Check, phrase: SearchPhrase) void {
self.actions.append(.{
.tag = .not_present,
- .phrase = self.builder.dupe(phrase),
+ .phrase = phrase,
}) catch @panic("OOM");
}
- fn computeCmp(self: *Check, phrase: []const u8, expected: ComputeCompareExpected) void {
+ fn computeCmp(self: *Check, phrase: SearchPhrase, expected: ComputeCompareExpected) void {
self.actions.append(.{
.tag = .compute_cmp,
- .phrase = self.builder.dupe(phrase),
+ .phrase = phrase,
.expected = expected,
}) catch @panic("OOM");
}
@@ -260,8 +275,8 @@ const Check = struct {
/// Creates a new sequence of actions with `phrase` as the first anchor searched phrase.
pub fn checkStart(self: *CheckObjectStep, phrase: []const u8) void {
- var new_check = Check.create(self.step.owner);
- new_check.match(phrase);
+ var new_check = Check.create(self.step.owner.allocator);
+ new_check.match(.{ .string = self.step.owner.dupe(phrase) });
self.checks.append(new_check) catch @panic("OOM");
}
@@ -270,7 +285,19 @@ pub fn checkStart(self: *CheckObjectStep, phrase: []const u8) void {
pub fn checkNext(self: *CheckObjectStep, phrase: []const u8) void {
assert(self.checks.items.len > 0);
const last = &self.checks.items[self.checks.items.len - 1];
- last.match(phrase);
+ last.match(.{ .string = self.step.owner.dupe(phrase) });
+}
+
+/// Like `checkNext()` but takes an additional argument `FileSource` which will be
+/// resolved to a full search query in `make()`.
+pub fn checkNextFileSource(
+ self: *CheckObjectStep,
+ phrase: []const u8,
+ file_source: std.Build.FileSource,
+) void {
+ assert(self.checks.items.len > 0);
+ const last = &self.checks.items[self.checks.items.len - 1];
+ last.match(.{ .string = self.step.owner.dupe(phrase), .file_source = file_source });
}
/// Adds another searched phrase to the latest created Check with `CheckObjectStep.checkStart(...)`
@@ -279,7 +306,7 @@ pub fn checkNext(self: *CheckObjectStep, phrase: []const u8) void {
pub fn checkNotPresent(self: *CheckObjectStep, phrase: []const u8) void {
assert(self.checks.items.len > 0);
const last = &self.checks.items[self.checks.items.len - 1];
- last.notPresent(phrase);
+ last.notPresent(.{ .string = self.step.owner.dupe(phrase) });
}
/// Creates a new check checking specifically symbol table parsed and dumped from the object
@@ -302,8 +329,8 @@ pub fn checkComputeCompare(
program: []const u8,
expected: ComputeCompareExpected,
) void {
- var new_check = Check.create(self.step.owner);
- new_check.computeCmp(program, expected);
+ var new_check = Check.create(self.step.owner.allocator);
+ new_check.computeCmp(.{ .string = self.step.owner.dupe(program) }, expected);
self.checks.append(new_check) catch @panic("OOM");
}
@@ -343,7 +370,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
switch (act.tag) {
.match => {
while (it.next()) |line| {
- if (try act.match(line, &vars)) break;
+ if (try act.match(b, step, line, &vars)) break;
} else {
return step.fail(
\\
@@ -352,12 +379,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
\\========= but parsed file does not contain it: =======
\\{s}
\\======================================================
- , .{ act.phrase, output });
+ , .{ act.phrase.resolve(b, step), output });
}
},
.not_present => {
while (it.next()) |line| {
- if (try act.match(line, &vars)) {
+ if (try act.match(b, step, line, &vars)) {
return step.fail(
\\
\\========= expected not to find: ===================
@@ -365,12 +392,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
\\========= but parsed file does contain it: ========
\\{s}
\\===================================================
- , .{ act.phrase, output });
+ , .{ act.phrase.resolve(b, step), output });
}
}
},
.compute_cmp => {
- const res = act.computeCmp(step, vars) catch |err| switch (err) {
+ const res = act.computeCmp(b, step, vars) catch |err| switch (err) {
error.UnknownVariable => {
return step.fail(
\\========= from parsed file: =====================
@@ -388,7 +415,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
\\========= from parsed file: =======================
\\{s}
\\===================================================
- , .{ act.phrase, act.expected.?, output });
+ , .{ act.phrase.resolve(b, step), act.expected.?, output });
}
},
}
diff --git a/test/link/macho/dylib/build.zig b/test/link/macho/dylib/build.zig
index 2d775aa23f..a4085b51e6 100644
--- a/test/link/macho/dylib/build.zig
+++ b/test/link/macho/dylib/build.zig
@@ -52,10 +52,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
check_exe.checkNext("compatibility version 10000");
check_exe.checkStart("cmd RPATH");
- // TODO check this (perhaps with `checkNextFileSource(dylib.getOutputDirectorySource())`)
- //check_exe.checkNext(std.fmt.allocPrint(b.allocator, "path {s}", .{
- // b.pathFromRoot("zig-out/lib"),
- //}) catch unreachable);
+ check_exe.checkNextFileSource("path", dylib.getOutputDirectorySource());
const run = check_exe.runAndCompare();
run.expectStdOutEqual("Hello world");
From dbe1b4a7e5731e4fb17d42b754faf1052aa78f32 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Thu, 23 Mar 2023 00:27:25 -0400
Subject: [PATCH 091/216] x86_64: fix value tracking bugs
---
src/arch/x86_64/CodeGen.zig | 310 ++++++++++++++++++++---------------
src/arch/x86_64/abi.zig | 2 +-
src/register_manager.zig | 8 +-
test/behavior/array.zig | 1 +
test/behavior/bugs/10970.zig | 1 -
test/behavior/for.zig | 1 +
test/behavior/if.zig | 1 -
test/behavior/union.zig | 1 -
8 files changed, 182 insertions(+), 143 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index f30be0e378..9dfa4f0502 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -265,12 +265,15 @@ pub fn generate(
const fn_type = fn_owner_decl.ty;
var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);
+ try branch_stack.ensureUnusedCapacity(2);
+ // The outermost branch is used for constants only.
+ branch_stack.appendAssumeCapacity(.{});
+ branch_stack.appendAssumeCapacity(.{});
defer {
- assert(branch_stack.items.len == 1);
- branch_stack.items[0].deinit(bin_file.allocator);
+ assert(branch_stack.items.len == 2);
+ for (branch_stack.items) |*branch| branch.deinit(bin_file.allocator);
branch_stack.deinit();
}
- try branch_stack.append(.{});
var function = Self{
.gpa = bin_file.allocator,
@@ -1070,20 +1073,29 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
if (self.air_bookkeeping < old_air_bookkeeping + 1) {
std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, air_tags[inst] });
}
+
+ { // check consistency of tracked registers
+ var it = self.register_manager.free_registers.iterator(.{ .kind = .unset });
+ while (it.next()) |index| {
+ const tracked_inst = self.register_manager.registers[index];
+ switch (air_tags[tracked_inst]) {
+ .block => {},
+ else => assert(RegisterManager.indexOfRegIntoTracked(
+ switch (self.getResolvedInstValue(tracked_inst).?) {
+ .register => |reg| reg,
+ .register_overflow => |ro| ro.reg,
+ else => unreachable,
+ },
+ ).? == index),
+ }
+ }
+ }
}
}
}
-/// Asserts there is already capacity to insert into top branch inst_table.
-fn processDeath(self: *Self, inst: Air.Inst.Index) void {
- const air_tags = self.air.instructions.items(.tag);
- if (air_tags[inst] == .constant) return; // Constants are immortal.
- const prev_value = self.getResolvedInstValue(inst) orelse return;
- log.debug("%{d} => {}", .{ inst, MCValue.dead });
- // When editing this function, note that the logic must synchronize with `reuseOperand`.
- const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
- branch.inst_table.putAssumeCapacity(inst, .dead);
- switch (prev_value) {
+fn freeValue(self: *Self, value: MCValue) void {
+ switch (value) {
.register => |reg| {
self.register_manager.freeReg(reg);
},
@@ -1098,6 +1110,18 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
}
}
+/// Asserts there is already capacity to insert into top branch inst_table.
+fn processDeath(self: *Self, inst: Air.Inst.Index) void {
+ const air_tags = self.air.instructions.items(.tag);
+ if (air_tags[inst] == .constant) return; // Constants are immortal.
+ const prev_value = self.getResolvedInstValue(inst) orelse return;
+ log.debug("%{d} => {}", .{ inst, MCValue.dead });
+ // When editing this function, note that the logic must synchronize with `reuseOperand`.
+ const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
+ branch.inst_table.putAssumeCapacity(inst, .dead);
+ self.freeValue(prev_value);
+}
+
/// Called when there are no operands, and the instruction is always unreferenced.
fn finishAirBookkeeping(self: *Self) void {
if (std.debug.runtime_safety) {
@@ -1140,13 +1164,17 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
},
else => {},
}
+ } else switch (result) {
+ .none, .dead, .unreach => {},
+ else => unreachable, // Why didn't the result die?
}
self.finishAirBookkeeping();
}
fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
+ // In addition to the caller's needs, we need enough space to spill every register and eflags.
const table = &self.branch_stack.items[self.branch_stack.items.len - 1].inst_table;
- try table.ensureUnusedCapacity(self.gpa, additional_count);
+ try table.ensureUnusedCapacity(self.gpa, additional_count + self.register_manager.registers.len + 1);
}
fn allocMem(self: *Self, inst: ?Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {
@@ -1252,12 +1280,15 @@ fn captureState(self: *Self) !State {
};
}
-fn revertState(self: *Self, state: State) void {
+fn revertState(self: *Self, state: State) !void {
+ var stack = try state.stack.clone(self.gpa);
+ errdefer stack.deinit(self.gpa);
+
self.register_manager.registers = state.registers;
self.eflags_inst = state.eflags_inst;
self.stack.deinit(self.gpa);
- self.stack = state.stack;
+ self.stack = stack;
self.next_stack_offset = state.next_stack_offset;
self.register_manager.free_registers = state.free_registers;
@@ -1277,7 +1308,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
else => {},
}
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
- try branch.inst_table.put(self.gpa, inst, stack_mcv);
+ branch.inst_table.putAssumeCapacity(inst, stack_mcv);
try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{});
}
@@ -1294,7 +1325,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {
log.debug("spilling %{d} to mcv {any}", .{ inst_to_save, new_mcv });
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
- try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);
+ branch.inst_table.putAssumeCapacity(inst_to_save, new_mcv);
self.eflags_inst = null;
@@ -1347,13 +1378,23 @@ fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Ty
}
fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {
- const stack_offset = try self.allocMemPtr(inst);
- return self.finishAir(inst, .{ .ptr_stack_offset = @intCast(i32, stack_offset) }, .{ .none, .none, .none });
+ const result: MCValue = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const stack_offset = try self.allocMemPtr(inst);
+ break :result .{ .ptr_stack_offset = @intCast(i32, stack_offset) };
+ };
+ return self.finishAir(inst, result, .{ .none, .none, .none });
}
fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {
- const stack_offset = try self.allocMemPtr(inst);
- return self.finishAir(inst, .{ .ptr_stack_offset = @intCast(i32, stack_offset) }, .{ .none, .none, .none });
+ const result: MCValue = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
+ const stack_offset = try self.allocMemPtr(inst);
+ break :result .{ .ptr_stack_offset = @intCast(i32, stack_offset) };
+ };
+ return self.finishAir(inst, result, .{ .none, .none, .none });
}
fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
@@ -1992,11 +2033,6 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
},
.register => |reg| {
// TODO reuse operand
- self.register_manager.getRegAssumeFree(.rcx, null);
- const rcx_lock =
- if (err_off > 0) self.register_manager.lockRegAssumeUnused(.rcx) else null;
- defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
-
const eu_lock = self.register_manager.lockReg(reg);
defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
@@ -2047,11 +2083,6 @@ fn genUnwrapErrorUnionPayloadMir(
},
.register => |reg| {
// TODO reuse operand
- self.register_manager.getRegAssumeFree(.rcx, null);
- const rcx_lock =
- if (payload_off > 0) self.register_manager.lockRegAssumeUnused(.rcx) else null;
- defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
-
const eu_lock = self.register_manager.lockReg(reg);
defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
@@ -2877,17 +2908,18 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
const imm_0000_1111 = Immediate.u(mask / 0b0001_0001);
const imm_0000_0001 = Immediate.u(mask / 0b1111_1111);
- const tmp_reg = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
- src_mcv.register
+ const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ src_mcv
else
- try self.copyToTmpRegister(src_ty, src_mcv);
- const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
- defer self.register_manager.unlockReg(tmp_lock);
-
- const dst_reg = try self.register_manager.allocReg(inst, gp);
+ try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv);
+ const dst_reg = dst_mcv.register;
const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
defer self.register_manager.unlockReg(dst_lock);
+ const tmp_reg = try self.register_manager.allocReg(null, gp);
+ const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
+ defer self.register_manager.unlockReg(tmp_lock);
+
{
const dst = registerAlias(dst_reg, src_abi_size);
const tmp = registerAlias(tmp_reg, src_abi_size);
@@ -2896,9 +2928,9 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
else
undefined;
- // tmp = operand
- try self.asmRegisterRegister(.mov, dst, tmp);
// dst = operand
+ try self.asmRegisterRegister(.mov, tmp, dst);
+ // tmp = operand
try self.asmRegisterImmediate(.shr, tmp, Immediate.u(1));
// tmp = operand >> 1
if (src_abi_size > 4) {
@@ -2948,7 +2980,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
}
// dst = (temp3 * 0x01...01) >> (bits - 8)
}
- break :result .{ .register = dst_reg };
+ break :result dst_mcv;
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
@@ -3796,8 +3828,6 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
/// Clobbers .rcx for non-immediate shift value.
fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shift: MCValue) !void {
- assert(reg.to64() != .rcx);
-
switch (tag) {
.sal, .sar, .shl, .shr => {},
else => unreachable,
@@ -4612,23 +4642,24 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
const src_index = self.air.instructions.items(.data)[inst].arg.src_index;
const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index);
- if (self.liveness.isUnused(inst))
- return self.finishAirBookkeeping();
+ const result: MCValue = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
- const dst_mcv: MCValue = switch (mcv) {
- .register => |reg| blk: {
- self.register_manager.getRegAssumeFree(reg.to64(), inst);
- break :blk MCValue{ .register = reg };
- },
- .stack_offset => |off| blk: {
- const offset = @intCast(i32, self.max_end_stack) - off + 16;
- break :blk MCValue{ .stack_offset = -offset };
- },
- else => return self.fail("TODO implement arg for {}", .{mcv}),
+ const dst_mcv: MCValue = switch (mcv) {
+ .register => |reg| blk: {
+ self.register_manager.getRegAssumeFree(reg.to64(), inst);
+ break :blk MCValue{ .register = reg };
+ },
+ .stack_offset => |off| blk: {
+ const offset = @intCast(i32, self.max_end_stack) - off + 16;
+ break :blk MCValue{ .stack_offset = -offset };
+ },
+ else => return self.fail("TODO implement arg for {}", .{mcv}),
+ };
+ try self.genArgDbgInfo(ty, name, dst_mcv);
+ break :result dst_mcv;
};
- try self.genArgDbgInfo(ty, name, dst_mcv);
-
- return self.finishAir(inst, dst_mcv, .{ .none, .none, .none });
+ return self.finishAir(inst, result, .{ .none, .none, .none });
}
fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
@@ -4924,6 +4955,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
}
const result: MCValue = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
+
switch (info.return_value) {
.register => {
// Save function return value in a new register
@@ -5137,7 +5170,10 @@ fn genTry(
const reloc = try self.genCondBrMir(Type.anyerror, is_err_mcv);
try self.genBody(body);
try self.performReloc(reloc);
- const result = try self.genUnwrapErrorUnionPayloadMir(inst, err_union_ty, err_union);
+ const result = if (self.liveness.isUnused(inst))
+ .dead
+ else
+ try self.genUnwrapErrorUnionPayloadMir(inst, err_union_ty, err_union);
return result;
}
@@ -5234,7 +5270,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
}
// Capture the state of register and stack allocation state so that we can revert to it.
- const saved_state = try self.captureState();
+ var saved_state = try self.captureState();
+ defer saved_state.deinit(self.gpa);
{
try self.branch_stack.append(.{});
@@ -5252,7 +5289,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
var then_branch = self.branch_stack.pop();
defer then_branch.deinit(self.gpa);
- self.revertState(saved_state);
+ try self.revertState(saved_state);
try self.performReloc(reloc);
@@ -5286,9 +5323,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
log.debug("Then branch: {}", .{then_branch.fmtDebug()});
log.debug("Else branch: {}", .{else_branch.fmtDebug()});
-
- const parent_branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
- try self.canonicaliseBranches(parent_branch, &then_branch, &else_branch);
+ try self.canonicaliseBranches(true, &then_branch, &else_branch);
// We already took care of pl_op.operand earlier, so we're going
// to pass .none here
@@ -5423,10 +5458,6 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !
try self.genBinOpMir(.cmp, Type.anyerror, .{ .stack_offset = offset }, .{ .immediate = 0 });
},
.register => |reg| {
- self.register_manager.getRegAssumeFree(.rcx, null);
- const rcx_lock = if (err_off > 0) self.register_manager.lockRegAssumeUnused(.rcx) else null;
- defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
-
const eu_lock = self.register_manager.lockReg(reg);
defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
@@ -5606,7 +5637,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
// break instruction will choose a MCValue for the block result and overwrite
// this field. Following break instructions will use that MCValue to put their
// block results.
- .mcv = .none,
+ .mcv = if (self.liveness.isUnused(inst)) .dead else .none,
});
defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa);
@@ -5646,21 +5677,29 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
}
}
- var branch_stack = std.ArrayList(Branch).init(self.gpa);
- defer {
- for (branch_stack.items) |*bs| {
- bs.deinit(self.gpa);
- }
- branch_stack.deinit();
+ log.debug("airSwitch: %{d}", .{inst});
+ log.debug("Upper branches:", .{});
+ for (self.branch_stack.items) |bs| {
+ log.debug("{}", .{bs.fmtDebug()});
}
- try branch_stack.ensureTotalCapacityPrecise(switch_br.data.cases_len + 1);
+ var prev_branch: ?Branch = null;
+ defer if (prev_branch) |*branch| branch.deinit(self.gpa);
+
+ // Capture the state of register and stack allocation state so that we can revert to it.
+ var saved_state = try self.captureState();
+ defer saved_state.deinit(self.gpa);
+
+ const cases_len = switch_br.data.cases_len + @boolToInt(switch_br.data.else_body_len > 0);
while (case_i < switch_br.data.cases_len) : (case_i += 1) {
const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
const items = @ptrCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);
const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
extra_index = case.end + items.len + case_body.len;
+ // Revert to the previous register and stack allocation state.
+ if (prev_branch) |_| try self.revertState(saved_state);
+
var relocs = try self.gpa.alloc(u32, items.len);
defer self.gpa.free(relocs);
@@ -5671,12 +5710,9 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
reloc.* = try self.asmJccReloc(undefined, .ne);
}
- // Capture the state of register and stack allocation state so that we can revert to it.
- const saved_state = try self.captureState();
-
{
- try self.branch_stack.append(.{});
- errdefer _ = self.branch_stack.pop();
+ if (cases_len > 1) try self.branch_stack.append(.{});
+ errdefer _ = if (cases_len > 1) self.branch_stack.pop();
try self.ensureProcessDeathCapacity(liveness.deaths[case_i].len);
for (liveness.deaths[case_i]) |operand| {
@@ -5686,25 +5722,31 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
try self.genBody(case_body);
}
- branch_stack.appendAssumeCapacity(self.branch_stack.pop());
+ // Consolidate returned MCValues between prongs like we do in airCondBr.
+ if (cases_len > 1) {
+ var case_branch = self.branch_stack.pop();
+ errdefer case_branch.deinit(self.gpa);
- // Revert to the previous register and stack allocation state.
- self.revertState(saved_state);
-
- for (relocs) |reloc| {
- try self.performReloc(reloc);
+ log.debug("Case-{d} branch: {}", .{ case_i, case_branch.fmtDebug() });
+ if (prev_branch) |*canon_branch| {
+ try self.canonicaliseBranches(case_i == cases_len - 1, canon_branch, &case_branch);
+ canon_branch.deinit(self.gpa);
+ }
+ prev_branch = case_branch;
}
+
+ for (relocs) |reloc| try self.performReloc(reloc);
}
if (switch_br.data.else_body_len > 0) {
const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
- // Capture the state of register and stack allocation state so that we can revert to it.
- const saved_state = try self.captureState();
+ // Revert to the previous register and stack allocation state.
+ if (prev_branch) |_| try self.revertState(saved_state);
{
- try self.branch_stack.append(.{});
- errdefer _ = self.branch_stack.pop();
+ if (cases_len > 1) try self.branch_stack.append(.{});
+ errdefer _ = if (cases_len > 1) self.branch_stack.pop();
const else_deaths = liveness.deaths.len - 1;
try self.ensureProcessDeathCapacity(liveness.deaths[else_deaths].len);
@@ -5715,53 +5757,48 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
try self.genBody(else_body);
}
- branch_stack.appendAssumeCapacity(self.branch_stack.pop());
+ // Consolidate returned MCValues between a prong and the else branch like we do in airCondBr.
+ if (cases_len > 1) {
+ var else_branch = self.branch_stack.pop();
+ errdefer else_branch.deinit(self.gpa);
- // Revert to the previous register and stack allocation state.
- self.revertState(saved_state);
+ log.debug("Else branch: {}", .{else_branch.fmtDebug()});
+ if (prev_branch) |*canon_branch| {
+ try self.canonicaliseBranches(true, canon_branch, &else_branch);
+ canon_branch.deinit(self.gpa);
+ }
+ prev_branch = else_branch;
+ }
}
- // Consolidate returned MCValues between prongs and else branch like we do
- // in airCondBr.
- log.debug("airSwitch: %{d}", .{inst});
- log.debug("Upper branches:", .{});
- for (self.branch_stack.items) |bs| {
- log.debug("{}", .{bs.fmtDebug()});
- }
- for (branch_stack.items, 0..) |bs, i| {
- log.debug("Case-{d} branch: {}", .{ i, bs.fmtDebug() });
- }
-
- // TODO: can we reduce the complexity of this algorithm?
- const parent_branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
- var i: usize = branch_stack.items.len;
- while (i > 1) : (i -= 1) {
- const canon_branch = &branch_stack.items[i - 2];
- const target_branch = &branch_stack.items[i - 1];
- try self.canonicaliseBranches(parent_branch, canon_branch, target_branch);
- }
-
- // We already took care of pl_op.operand earlier, so we're going
- // to pass .none here
+ // We already took care of pl_op.operand earlier, so we're going to pass .none here
return self.finishAir(inst, .unreach, .{ .none, .none, .none });
}
-fn canonicaliseBranches(self: *Self, parent_branch: *Branch, canon_branch: *Branch, target_branch: *Branch) !void {
- try parent_branch.inst_table.ensureUnusedCapacity(self.gpa, target_branch.inst_table.count());
+fn canonicaliseBranches(
+ self: *Self,
+ update_parent: bool,
+ canon_branch: *Branch,
+ target_branch: *const Branch,
+) !void {
+ const parent_branch =
+ if (update_parent) &self.branch_stack.items[self.branch_stack.items.len - 1] else undefined;
+ if (update_parent) try self.ensureProcessDeathCapacity(target_branch.inst_table.count());
const target_slice = target_branch.inst_table.entries.slice();
for (target_slice.items(.key), target_slice.items(.value)) |target_key, target_value| {
const canon_mcv = if (canon_branch.inst_table.fetchSwapRemove(target_key)) |canon_entry| blk: {
// The instruction's MCValue is overridden in both branches.
- parent_branch.inst_table.putAssumeCapacity(target_key, canon_entry.value);
+ if (update_parent) {
+ parent_branch.inst_table.putAssumeCapacity(target_key, canon_entry.value);
+ }
if (target_value == .dead) {
assert(canon_entry.value == .dead);
continue;
}
break :blk canon_entry.value;
} else blk: {
- if (target_value == .dead)
- continue;
+ if (target_value == .dead) continue;
// The instruction is only overridden in the else branch.
// If integer overflows occurs, the question is: why wasn't the instruction marked dead?
break :blk self.getResolvedInstValue(target_key).?;
@@ -5770,22 +5807,25 @@ fn canonicaliseBranches(self: *Self, parent_branch: *Branch, canon_branch: *Bran
// TODO make sure the destination stack offset / register does not already have something
// going on there.
try self.setRegOrMem(self.air.typeOfIndex(target_key), canon_mcv, target_value);
+ self.freeValue(target_value);
// TODO track the new register / stack allocation
}
- try parent_branch.inst_table.ensureUnusedCapacity(self.gpa, canon_branch.inst_table.count());
+ if (update_parent) try self.ensureProcessDeathCapacity(canon_branch.inst_table.count());
const canon_slice = canon_branch.inst_table.entries.slice();
for (canon_slice.items(.key), canon_slice.items(.value)) |canon_key, canon_value| {
// We already deleted the items from this table that matched the target_branch.
// So these are all instructions that are only overridden in the canon branch.
- parent_branch.inst_table.putAssumeCapacity(canon_key, canon_value);
- log.debug("canon_value = {}", .{canon_value});
- if (canon_value == .dead)
- continue;
- const parent_mcv = self.getResolvedInstValue(canon_key).?;
+ const parent_mcv =
+ if (canon_value != .dead) self.getResolvedInstValue(canon_key).? else undefined;
+ if (update_parent) {
+ parent_branch.inst_table.putAssumeCapacity(canon_key, canon_value);
+ }
+ if (canon_value == .dead) continue;
log.debug("consolidating canon_entry {d} {}=>{}", .{ canon_key, parent_mcv, canon_value });
// TODO make sure the destination stack offset / register does not already have something
// going on there.
- try self.setRegOrMem(self.air.typeOfIndex(canon_key), parent_mcv, canon_value);
+ try self.setRegOrMem(self.air.typeOfIndex(canon_key), canon_value, parent_mcv);
+ self.freeValue(parent_mcv);
// TODO track the new register / stack allocation
}
}
@@ -5811,11 +5851,9 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
const block_data = self.blocks.getPtr(block).?;
-
- if (self.air.typeOf(operand).hasRuntimeBits()) {
+ if (block_data.mcv != .dead and self.air.typeOf(operand).hasRuntimeBits()) {
const operand_mcv = try self.resolveInst(operand);
- const block_mcv = block_data.mcv;
- if (block_mcv == .none) {
+ if (block_data.mcv == .none) {
block_data.mcv = switch (operand_mcv) {
.none, .dead, .unreach => unreachable,
.register, .stack_offset, .memory => operand_mcv,
@@ -5827,7 +5865,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}),
};
} else {
- try self.setRegOrMem(self.air.typeOfIndex(block), block_mcv, operand_mcv);
+ try self.setRegOrMem(self.air.typeOfIndex(block), block_data.mcv, operand_mcv);
}
}
return self.brVoid(block);
@@ -6916,7 +6954,8 @@ fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data;
- const dst_reg = try self.register_manager.allocReg(inst, gp);
+ const unused = self.liveness.isUnused(inst);
+ const dst_reg = try self.register_manager.allocReg(if (unused) null else inst, gp);
const ptr_ty = self.air.typeOf(pl_op.operand);
const ptr_mcv = try self.resolveInst(pl_op.operand);
@@ -6924,7 +6963,6 @@ fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {
const val_ty = self.air.typeOf(extra.operand);
const val_mcv = try self.resolveInst(extra.operand);
- const unused = self.liveness.isUnused(inst);
try self.atomicOp(dst_reg, ptr_mcv, val_mcv, ptr_ty, val_ty, unused, extra.op(), extra.ordering());
const result: MCValue = if (unused) .dead else .{ .register = dst_reg };
return self.finishAir(inst, result, .{ pl_op.operand, extra.operand, .none });
diff --git a/src/arch/x86_64/abi.zig b/src/arch/x86_64/abi.zig
index 193efa6dc4..e9da09b999 100644
--- a/src/arch/x86_64/abi.zig
+++ b/src/arch/x86_64/abi.zig
@@ -523,7 +523,7 @@ pub fn getCAbiIntReturnRegs(target: Target) []const Register {
}
const gp_regs = [_]Register{
- .rbx, .r12, .r13, .r14, .r15, .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11,
+ .rax, .rcx, .rdx, .rbx, .rsi, .rdi, .r8, .r9, .r10, .r11, .r12, .r13, .r14, .r15,
};
const sse_avx_regs = [_]Register{
.ymm0, .ymm1, .ymm2, .ymm3, .ymm4, .ymm5, .ymm6, .ymm7,
diff --git a/src/register_manager.zig b/src/register_manager.zig
index 713b669b06..1a5d2fd501 100644
--- a/src/register_manager.zig
+++ b/src/register_manager.zig
@@ -210,13 +210,14 @@ pub fn RegisterManager(
}
assert(i == count);
- for (regs, 0..) |reg, j| {
+ for (regs, insts) |reg, inst| {
+ log.debug("tryAllocReg {} for inst {?}", .{ reg, inst });
self.markRegAllocated(reg);
- if (insts[j]) |inst| {
+ if (inst) |tracked_inst| {
// Track the register
const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null
- self.registers[index] = inst;
+ self.registers[index] = tracked_inst;
self.markRegUsed(reg);
}
}
@@ -258,6 +259,7 @@ pub fn RegisterManager(
if (excludeRegister(reg, register_class)) break;
if (self.isRegLocked(reg)) continue;
+ log.debug("allocReg {} for inst {?}", .{ reg, insts[i] });
regs[i] = reg;
self.markRegAllocated(reg);
const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null
diff --git a/test/behavior/array.zig b/test/behavior/array.zig
index 484cab4722..96b1be1778 100644
--- a/test/behavior/array.zig
+++ b/test/behavior/array.zig
@@ -191,6 +191,7 @@ test "nested arrays of strings" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" };
for (array_of_strings, 0..) |s, i| {
diff --git a/test/behavior/bugs/10970.zig b/test/behavior/bugs/10970.zig
index e04680c443..539dfaff71 100644
--- a/test/behavior/bugs/10970.zig
+++ b/test/behavior/bugs/10970.zig
@@ -6,7 +6,6 @@ fn retOpt() ?u32 {
test "breaking from a loop in an if statement" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
var cond = true;
diff --git a/test/behavior/for.zig b/test/behavior/for.zig
index 98ffff85a3..8ab378c6d4 100644
--- a/test/behavior/for.zig
+++ b/test/behavior/for.zig
@@ -275,6 +275,7 @@ test "two counters" {
test "1-based counter and ptr to array" {
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_x86_64) return error.SkipZigTest;
var ok: usize = 0;
diff --git a/test/behavior/if.zig b/test/behavior/if.zig
index 948629038b..730c0713c6 100644
--- a/test/behavior/if.zig
+++ b/test/behavior/if.zig
@@ -112,7 +112,6 @@ test "if prongs cast to expected type instead of peer type resolution" {
}
test "if peer expressions inferred optional type" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/union.zig b/test/behavior/union.zig
index f247bf6fa2..b78bac5c3e 100644
--- a/test/behavior/union.zig
+++ b/test/behavior/union.zig
@@ -1514,7 +1514,6 @@ test "packed union with zero-bit field" {
}
test "reinterpreting enum value inside packed union" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
From 12c07fcf20aba9e986b5b2131515b33e3d27176a Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Thu, 23 Mar 2023 02:03:43 -0400
Subject: [PATCH 092/216] x86_64: fix more value tracking bugs
---
src/arch/x86_64/CodeGen.zig | 170 +++++++++++++++++-------------------
test/behavior/cast.zig | 7 +-
test/behavior/enum.zig | 1 +
test/behavior/if.zig | 1 +
test/behavior/switch.zig | 1 -
5 files changed, 85 insertions(+), 95 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 9dfa4f0502..852a8b47be 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -214,11 +214,6 @@ const StackAllocation = struct {
const BlockData = struct {
relocs: std.ArrayListUnmanaged(Mir.Inst.Index),
- /// The first break instruction encounters `null` here and chooses a
- /// machine code value for the block result, populating this field.
- /// Following break instructions encounter that value and use it for
- /// the location to store their block results.
- mcv: MCValue,
};
const BigTomb = struct {
@@ -1078,16 +1073,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
var it = self.register_manager.free_registers.iterator(.{ .kind = .unset });
while (it.next()) |index| {
const tracked_inst = self.register_manager.registers[index];
- switch (air_tags[tracked_inst]) {
- .block => {},
- else => assert(RegisterManager.indexOfRegIntoTracked(
- switch (self.getResolvedInstValue(tracked_inst).?) {
- .register => |reg| reg,
- .register_overflow => |ro| ro.reg,
- else => unreachable,
- },
- ).? == index),
- }
+ const tracked_mcv = self.getResolvedInstValue(tracked_inst).?.*;
+ assert(RegisterManager.indexOfRegIntoTracked(switch (tracked_mcv) {
+ .register => |reg| reg,
+ .register_overflow => |ro| ro.reg,
+ else => unreachable,
+ }).? == index);
}
}
}
@@ -1114,7 +1105,7 @@ fn freeValue(self: *Self, value: MCValue) void {
fn processDeath(self: *Self, inst: Air.Inst.Index) void {
const air_tags = self.air.instructions.items(.tag);
if (air_tags[inst] == .constant) return; // Constants are immortal.
- const prev_value = self.getResolvedInstValue(inst) orelse return;
+ const prev_value = (self.getResolvedInstValue(inst) orelse return).*;
log.debug("%{d} => {}", .{ inst, MCValue.dead });
// When editing this function, note that the logic must synchronize with `reuseOperand`.
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
@@ -1259,45 +1250,29 @@ fn allocRegOrMemAdvanced(self: *Self, elem_ty: Type, inst: ?Air.Inst.Index, reg_
}
const State = struct {
- next_stack_offset: u32,
registers: abi.RegisterManager.TrackedRegisters,
free_registers: abi.RegisterManager.RegisterBitSet,
eflags_inst: ?Air.Inst.Index,
- stack: std.AutoHashMapUnmanaged(u32, StackAllocation),
-
- fn deinit(state: *State, gpa: Allocator) void {
- state.stack.deinit(gpa);
- }
};
-fn captureState(self: *Self) !State {
+fn captureState(self: *Self) State {
return State{
- .next_stack_offset = self.next_stack_offset,
.registers = self.register_manager.registers,
.free_registers = self.register_manager.free_registers,
.eflags_inst = self.eflags_inst,
- .stack = try self.stack.clone(self.gpa),
};
}
-fn revertState(self: *Self, state: State) !void {
- var stack = try state.stack.clone(self.gpa);
- errdefer stack.deinit(self.gpa);
-
- self.register_manager.registers = state.registers;
+fn revertState(self: *Self, state: State) void {
self.eflags_inst = state.eflags_inst;
-
- self.stack.deinit(self.gpa);
- self.stack = stack;
-
- self.next_stack_offset = state.next_stack_offset;
self.register_manager.free_registers = state.free_registers;
+ self.register_manager.registers = state.registers;
}
pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
const stack_mcv = try self.allocRegOrMem(inst, false);
log.debug("spilling %{d} to stack mcv {any}", .{ inst, stack_mcv });
- const reg_mcv = self.getResolvedInstValue(inst).?;
+ const reg_mcv = self.getResolvedInstValue(inst).?.*;
switch (reg_mcv) {
.register => |other| {
assert(reg.to64() == other.to64());
@@ -1314,7 +1289,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
pub fn spillEflagsIfOccupied(self: *Self) !void {
if (self.eflags_inst) |inst_to_save| {
- const mcv = self.getResolvedInstValue(inst_to_save).?;
+ const mcv = self.getResolvedInstValue(inst_to_save).?.*;
const new_mcv = switch (mcv) {
.register_overflow => try self.allocRegOrMem(inst_to_save, false),
.eflags => try self.allocRegOrMem(inst_to_save, true),
@@ -2607,7 +2582,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
const index_ty = self.air.typeOf(bin_op.rhs);
const index = try self.resolveInst(bin_op.rhs);
const index_lock: ?RegisterLock = switch (index) {
- .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ .register => |reg| self.register_manager.lockReg(reg),
else => null,
};
defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
@@ -2656,7 +2631,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
const index_ty = self.air.typeOf(extra.rhs);
const index = try self.resolveInst(extra.rhs);
const index_lock: ?RegisterLock = switch (index) {
- .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ .register => |reg| self.register_manager.lockReg(reg),
else => null,
};
defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
@@ -3202,8 +3177,8 @@ fn reuseOperand(
.register => |reg| {
// If it's in the registers table, need to associate the register with the
// new instruction.
- if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
- if (!self.register_manager.isRegFree(reg)) {
+ if (!self.register_manager.isRegFree(reg)) {
+ if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
self.register_manager.registers[index] = inst;
}
}
@@ -3542,7 +3517,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
const value_ty = self.air.typeOf(bin_op.rhs);
log.debug("airStore(%{d}): {} <- {}", .{ inst, ptr, value });
try self.store(ptr, value, ptr_ty, value_ty);
- return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
+ return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
}
fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {
@@ -5270,8 +5245,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
}
// Capture the state of register and stack allocation state so that we can revert to it.
- var saved_state = try self.captureState();
- defer saved_state.deinit(self.gpa);
+ const saved_state = self.captureState();
{
try self.branch_stack.append(.{});
@@ -5289,7 +5263,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
var then_branch = self.branch_stack.pop();
defer then_branch.deinit(self.gpa);
- try self.revertState(saved_state);
+ self.revertState(saved_state);
try self.performReloc(reloc);
@@ -5632,24 +5606,28 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
try self.blocks.putNoClobber(self.gpa, inst, .{
// A block is a setup to be able to jump to the end.
.relocs = .{},
- // It also acts as a receptacle for break operands.
- // Here we use `MCValue.none` to represent a null value so that the first
- // break instruction will choose a MCValue for the block result and overwrite
- // this field. Following break instructions will use that MCValue to put their
- // block results.
- .mcv = if (self.liveness.isUnused(inst)) .dead else .none,
});
defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa);
+ {
+ // Here we use `.none` to represent a null value so that the first break
+ // instruction will choose a MCValue for the block result and overwrite
+ // this field. Following break instructions will use that MCValue to put
+ // their block results.
+ const ty = self.air.typeOfIndex(inst);
+ const result: MCValue =
+ if (!ty.hasRuntimeBitsIgnoreComptime() or self.liveness.isUnused(inst)) .dead else .none;
+ const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
+ branch.inst_table.putAssumeCapacityNoClobber(inst, result);
+ }
+
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
const body = self.air.extra[extra.end..][0..extra.data.body_len];
try self.genBody(body);
for (self.blocks.getPtr(inst).?.relocs.items) |reloc| try self.performReloc(reloc);
-
- const result = self.blocks.getPtr(inst).?.mcv;
- return self.finishAir(inst, result, .{ .none, .none, .none });
+ self.finishAirBookkeeping();
}
fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
@@ -5687,8 +5665,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
defer if (prev_branch) |*branch| branch.deinit(self.gpa);
// Capture the state of register and stack allocation state so that we can revert to it.
- var saved_state = try self.captureState();
- defer saved_state.deinit(self.gpa);
+ const saved_state = self.captureState();
const cases_len = switch_br.data.cases_len + @boolToInt(switch_br.data.else_body_len > 0);
while (case_i < switch_br.data.cases_len) : (case_i += 1) {
@@ -5698,7 +5675,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
extra_index = case.end + items.len + case_body.len;
// Revert to the previous register and stack allocation state.
- if (prev_branch) |_| try self.revertState(saved_state);
+ if (prev_branch) |_| self.revertState(saved_state);
var relocs = try self.gpa.alloc(u32, items.len);
defer self.gpa.free(relocs);
@@ -5742,7 +5719,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
// Revert to the previous register and stack allocation state.
- if (prev_branch) |_| try self.revertState(saved_state);
+ if (prev_branch) |_| self.revertState(saved_state);
{
if (cases_len > 1) try self.branch_stack.append(.{});
@@ -5801,7 +5778,7 @@ fn canonicaliseBranches(
if (target_value == .dead) continue;
// The instruction is only overridden in the else branch.
// If integer overflows occurs, the question is: why wasn't the instruction marked dead?
- break :blk self.getResolvedInstValue(target_key).?;
+ break :blk self.getResolvedInstValue(target_key).?.*;
};
log.debug("consolidating target_entry {d} {}=>{}", .{ target_key, target_value, canon_mcv });
// TODO make sure the destination stack offset / register does not already have something
@@ -5816,17 +5793,18 @@ fn canonicaliseBranches(
// We already deleted the items from this table that matched the target_branch.
// So these are all instructions that are only overridden in the canon branch.
const parent_mcv =
- if (canon_value != .dead) self.getResolvedInstValue(canon_key).? else undefined;
+ if (canon_value != .dead) self.getResolvedInstValue(canon_key).?.* else undefined;
+ if (canon_value != .dead) {
+ log.debug("consolidating canon_entry {d} {}=>{}", .{ canon_key, parent_mcv, canon_value });
+ // TODO make sure the destination stack offset / register does not already have something
+ // going on there.
+ try self.setRegOrMem(self.air.typeOfIndex(canon_key), canon_value, parent_mcv);
+ self.freeValue(parent_mcv);
+ // TODO track the new register / stack allocation
+ }
if (update_parent) {
parent_branch.inst_table.putAssumeCapacity(canon_key, canon_value);
}
- if (canon_value == .dead) continue;
- log.debug("consolidating canon_entry {d} {}=>{}", .{ canon_key, parent_mcv, canon_value });
- // TODO make sure the destination stack offset / register does not already have something
- // going on there.
- try self.setRegOrMem(self.air.typeOfIndex(canon_key), canon_value, parent_mcv);
- self.freeValue(parent_mcv);
- // TODO track the new register / stack allocation
}
}
@@ -5845,27 +5823,41 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
fn airBr(self: *Self, inst: Air.Inst.Index) !void {
const branch = self.air.instructions.items(.data)[inst].br;
- try self.br(branch.block_inst, branch.operand);
+ try self.br(inst, branch.block_inst, branch.operand);
return self.finishAir(inst, .dead, .{ branch.operand, .none, .none });
}
-fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
- const block_data = self.blocks.getPtr(block).?;
- if (block_data.mcv != .dead and self.air.typeOf(operand).hasRuntimeBits()) {
- const operand_mcv = try self.resolveInst(operand);
- if (block_data.mcv == .none) {
- block_data.mcv = switch (operand_mcv) {
- .none, .dead, .unreach => unreachable,
- .register, .stack_offset, .memory => operand_mcv,
- .eflags, .immediate, .ptr_stack_offset => blk: {
- const new_mcv = try self.allocRegOrMem(block, true);
- try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
- break :blk new_mcv;
- },
- else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}),
- };
- } else {
- try self.setRegOrMem(self.air.typeOfIndex(block), block_data.mcv, operand_mcv);
+fn br(self: *Self, inst: Air.Inst.Index, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
+ // The first break instruction encounters `.none` here and chooses a
+ // machine code value for the block result, populating this field.
+ // Following break instructions encounter that value and use it for
+ // the location to store their block results.
+ if (self.getResolvedInstValue(block)) |dst_mcv| {
+ const src_mcv = try self.resolveInst(operand);
+ switch (dst_mcv.*) {
+ .none => {
+ const result = result: {
+ if (!self.reuseOperand(inst, operand, 0, src_mcv)) {
+ const new_mcv = try self.allocRegOrMem(block, true);
+ try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, src_mcv);
+ break :result new_mcv;
+ }
+
+ // the value is actually tracked with block, not inst
+ switch (src_mcv) {
+ .register => |reg| if (!self.register_manager.isRegFree(reg)) {
+ if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
+ self.register_manager.registers[index] = block;
+ }
+ },
+ .stack_offset => {},
+ else => unreachable,
+ }
+ break :result src_mcv;
+ };
+ dst_mcv.* = result;
+ },
+ else => try self.setRegOrMem(self.air.typeOfIndex(block), dst_mcv.*, src_mcv),
}
}
return self.brVoid(block);
@@ -7243,17 +7235,17 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
return gop.value_ptr.*;
},
.const_ty => unreachable,
- else => return self.getResolvedInstValue(inst_index).?,
+ else => return self.getResolvedInstValue(inst_index).?.*,
}
}
-fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) ?MCValue {
+fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) ?*MCValue {
// Treat each stack item as a "layer" on top of the previous one.
var i: usize = self.branch_stack.items.len;
while (true) {
i -= 1;
- if (self.branch_stack.items[i].inst_table.get(inst)) |mcv| {
- return if (mcv != .dead) mcv else null;
+ if (self.branch_stack.items[i].inst_table.getPtr(inst)) |mcv| {
+ return if (mcv.* != .dead) mcv else null;
}
}
}
diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig
index 7d27138ded..978c75c92f 100644
--- a/test/behavior/cast.zig
+++ b/test/behavior/cast.zig
@@ -38,6 +38,8 @@ fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
}
test "resolve undefined with integer" {
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
try testResolveUndefWithInt(true, 1234);
comptime try testResolveUndefWithInt(true, 1234);
}
@@ -419,7 +421,6 @@ fn testCastIntToErr(err: anyerror) !void {
test "peer resolve array and const slice" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
try testPeerResolveArrayConstSlice(true);
@@ -818,7 +819,6 @@ test "peer type resolution: error union after non-error" {
test "peer cast *[0]T to E![]const T" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
var buffer: [5]u8 = "abcde".*;
@@ -833,7 +833,6 @@ test "peer cast *[0]T to E![]const T" {
test "peer cast *[0]T to []const T" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
var buffer: [5]u8 = "abcde".*;
@@ -855,7 +854,6 @@ test "peer cast *[N]T to [*]T" {
test "peer resolution of string literals" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const S = struct {
@@ -1360,7 +1358,6 @@ test "cast f128 to narrower types" {
test "peer type resolution: unreachable, null, slice" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const S = struct {
diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig
index 9076f9f9ac..72784d9abc 100644
--- a/test/behavior/enum.zig
+++ b/test/behavior/enum.zig
@@ -904,6 +904,7 @@ test "enum literal casting to tagged union" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const Arch = union(enum) {
x86_64,
diff --git a/test/behavior/if.zig b/test/behavior/if.zig
index 730c0713c6..223d73ac85 100644
--- a/test/behavior/if.zig
+++ b/test/behavior/if.zig
@@ -115,6 +115,7 @@ test "if peer expressions inferred optional type" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
var self: []const u8 = "abcdef";
var index: usize = 0;
diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig
index 1643a2f697..132cef5c1e 100644
--- a/test/behavior/switch.zig
+++ b/test/behavior/switch.zig
@@ -509,7 +509,6 @@ test "return result loc and then switch with range implicit casted to error unio
}
test "switch with null and T peer types and inferred result location type" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
From c604111e22cb2f41e3151b1062e19035f35a6dec Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Fri, 24 Mar 2023 00:03:39 -0400
Subject: [PATCH 093/216] x86_64: fix block result value tracking
---
src/arch/x86_64/CodeGen.zig | 64 +++++++++++++++----------------------
1 file changed, 26 insertions(+), 38 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 852a8b47be..45cb671e93 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -1085,6 +1085,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
}
}
+fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void {
+ const reg = switch (value) {
+ .register => |reg| reg,
+ .register_overflow => |ro| ro.reg,
+ else => return,
+ };
+ if (self.register_manager.isRegFree(reg)) {
+ self.register_manager.getRegAssumeFree(reg, inst);
+ }
+}
+
fn freeValue(self: *Self, value: MCValue) void {
switch (value) {
.register => |reg| {
@@ -1136,25 +1147,10 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
log.debug("%{d} => {}", .{ inst, result });
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
branch.inst_table.putAssumeCapacityNoClobber(inst, result);
-
- // In some cases (such as bitcast), an operand
- // may be the same MCValue as the result. If
- // that operand died and was a register, it
- // was freed by processDeath. We have to
- // "re-allocate" the register.
- switch (result) {
- .register => |reg| {
- if (self.register_manager.isRegFree(reg)) {
- self.register_manager.getRegAssumeFree(reg, inst);
- }
- },
- .register_overflow => |ro| {
- if (self.register_manager.isRegFree(ro.reg)) {
- self.register_manager.getRegAssumeFree(ro.reg, inst);
- }
- },
- else => {},
- }
+ // In some cases, an operand may be reused as the result.
+ // If that operand died and was a register, it was freed by
+ // processDeath, so we have to "re-allocate" the register.
+ self.getValue(result, inst);
} else switch (result) {
.none, .dead, .unreach => {},
else => unreachable, // Why didn't the result die?
@@ -5609,14 +5605,14 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
});
defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa);
+ const ty = self.air.typeOfIndex(inst);
+ const unused = !ty.hasRuntimeBitsIgnoreComptime() or self.liveness.isUnused(inst);
{
// Here we use `.none` to represent a null value so that the first break
// instruction will choose a MCValue for the block result and overwrite
// this field. Following break instructions will use that MCValue to put
// their block results.
- const ty = self.air.typeOfIndex(inst);
- const result: MCValue =
- if (!ty.hasRuntimeBitsIgnoreComptime() or self.liveness.isUnused(inst)) .dead else .none;
+ const result: MCValue = if (unused) .dead else .none;
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
branch.inst_table.putAssumeCapacityNoClobber(inst, result);
}
@@ -5627,6 +5623,9 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
try self.genBody(body);
for (self.blocks.getPtr(inst).?.relocs.items) |reloc| try self.performReloc(reloc);
+
+ const result = if (unused) .dead else self.getResolvedInstValue(inst).?.*;
+ self.getValue(result, inst);
self.finishAirBookkeeping();
}
@@ -5837,25 +5836,14 @@ fn br(self: *Self, inst: Air.Inst.Index, block: Air.Inst.Index, operand: Air.Ins
switch (dst_mcv.*) {
.none => {
const result = result: {
- if (!self.reuseOperand(inst, operand, 0, src_mcv)) {
- const new_mcv = try self.allocRegOrMem(block, true);
- try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, src_mcv);
- break :result new_mcv;
- }
+ if (self.reuseOperand(inst, operand, 0, src_mcv)) break :result src_mcv;
- // the value is actually tracked with block, not inst
- switch (src_mcv) {
- .register => |reg| if (!self.register_manager.isRegFree(reg)) {
- if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
- self.register_manager.registers[index] = block;
- }
- },
- .stack_offset => {},
- else => unreachable,
- }
- break :result src_mcv;
+ const new_mcv = try self.allocRegOrMem(block, true);
+ try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, src_mcv);
+ break :result new_mcv;
};
dst_mcv.* = result;
+ self.freeValue(result);
},
else => try self.setRegOrMem(self.air.typeOfIndex(block), dst_mcv.*, src_mcv),
}
From 935ec9ec6a571010ddc11a9212ff0c93f82d0d74 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Fri, 24 Mar 2023 04:40:45 -0400
Subject: [PATCH 094/216] x86_64: canonicalize each br of a block
---
src/arch/x86_64/CodeGen.zig | 139 ++++++++++++++++++++++++----------
test/behavior/cast.zig | 2 -
test/behavior/enum.zig | 1 -
test/behavior/if.zig | 1 -
tools/lldb_pretty_printers.py | 15 ++++
5 files changed, 114 insertions(+), 44 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 45cb671e93..b1efcca1ac 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -213,7 +213,15 @@ const StackAllocation = struct {
};
const BlockData = struct {
- relocs: std.ArrayListUnmanaged(Mir.Inst.Index),
+ relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},
+ branch: ?Branch = null,
+ branch_depth: u32,
+
+ fn deinit(self: *BlockData, gpa: Allocator) void {
+ if (self.branch) |*branch| branch.deinit(gpa);
+ self.relocs.deinit(gpa);
+ self.* = undefined;
+ }
};
const BigTomb = struct {
@@ -5233,11 +5241,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
// that death now instead of later as this has an effect on
// whether it needs to be spilled in the branches
if (self.liveness.operandDies(inst, 0)) {
- const op_int = @enumToInt(pl_op.operand);
- if (op_int >= Air.Inst.Ref.typed_value_map.len) {
- const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
- self.processDeath(op_index);
- }
+ if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);
}
// Capture the state of register and stack allocation state so that we can revert to it.
@@ -5290,10 +5294,10 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
for (self.branch_stack.items) |bs| {
log.debug("{}", .{bs.fmtDebug()});
}
-
log.debug("Then branch: {}", .{then_branch.fmtDebug()});
log.debug("Else branch: {}", .{else_branch.fmtDebug()});
- try self.canonicaliseBranches(true, &then_branch, &else_branch);
+
+ try self.canonicaliseBranches(true, &then_branch, &else_branch, true);
// We already took care of pl_op.operand earlier, so we're going
// to pass .none here
@@ -5599,11 +5603,16 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
}
fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
- try self.blocks.putNoClobber(self.gpa, inst, .{
- // A block is a setup to be able to jump to the end.
- .relocs = .{},
- });
- defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa);
+ // A block is a setup to be able to jump to the end.
+ const branch_depth = @intCast(u32, self.branch_stack.items.len);
+ try self.blocks.putNoClobber(self.gpa, inst, .{ .branch_depth = branch_depth });
+ defer {
+ var block_data = self.blocks.fetchRemove(inst).?.value;
+ block_data.deinit(self.gpa);
+ }
+
+ try self.branch_stack.append(.{});
+ defer _ = self.branch_stack.pop();
const ty = self.air.typeOfIndex(inst);
const unused = !ty.hasRuntimeBitsIgnoreComptime() or self.liveness.isUnused(inst);
@@ -5613,8 +5622,8 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
// this field. Following break instructions will use that MCValue to put
// their block results.
const result: MCValue = if (unused) .dead else .none;
- const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
- branch.inst_table.putAssumeCapacityNoClobber(inst, result);
+ const branch = &self.branch_stack.items[branch_depth];
+ try branch.inst_table.putNoClobber(self.gpa, inst, result);
}
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
@@ -5622,7 +5631,23 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
const body = self.air.extra[extra.end..][0..extra.data.body_len];
try self.genBody(body);
- for (self.blocks.getPtr(inst).?.relocs.items) |reloc| try self.performReloc(reloc);
+ const block_data = self.blocks.getPtr(inst).?;
+ {
+ const src_branch = block_data.branch orelse self.branch_stack.items[branch_depth];
+ const dst_branch = &self.branch_stack.items[branch_depth - 1];
+ try dst_branch.inst_table.ensureUnusedCapacity(self.gpa, src_branch.inst_table.count());
+ var it = src_branch.inst_table.iterator();
+ while (it.next()) |entry| {
+ const tracked_inst = entry.key_ptr.*;
+ const tracked_value = entry.value_ptr.*;
+ if (dst_branch.inst_table.fetchPutAssumeCapacity(tracked_inst, tracked_value)) |old_entry| {
+ self.freeValue(old_entry.value);
+ }
+ self.getValue(tracked_value, tracked_inst);
+ }
+ }
+
+ for (block_data.relocs.items) |reloc| try self.performReloc(reloc);
const result = if (unused) .dead else self.getResolvedInstValue(inst).?.*;
self.getValue(result, inst);
@@ -5647,11 +5672,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
// that death now instead of later as this has an effect on
// whether it needs to be spilled in the branches
if (self.liveness.operandDies(inst, 0)) {
- const op_int = @enumToInt(pl_op.operand);
- if (op_int >= Air.Inst.Ref.typed_value_map.len) {
- const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
- self.processDeath(op_index);
- }
+ if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);
}
log.debug("airSwitch: %{d}", .{inst});
@@ -5704,8 +5725,9 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
errdefer case_branch.deinit(self.gpa);
log.debug("Case-{d} branch: {}", .{ case_i, case_branch.fmtDebug() });
+ const final = case_i == cases_len - 1;
if (prev_branch) |*canon_branch| {
- try self.canonicaliseBranches(case_i == cases_len - 1, canon_branch, &case_branch);
+ try self.canonicaliseBranches(final, canon_branch, &case_branch, true);
canon_branch.deinit(self.gpa);
}
prev_branch = case_branch;
@@ -5740,7 +5762,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
log.debug("Else branch: {}", .{else_branch.fmtDebug()});
if (prev_branch) |*canon_branch| {
- try self.canonicaliseBranches(true, canon_branch, &else_branch);
+ try self.canonicaliseBranches(true, canon_branch, &else_branch, true);
canon_branch.deinit(self.gpa);
}
prev_branch = else_branch;
@@ -5756,27 +5778,30 @@ fn canonicaliseBranches(
update_parent: bool,
canon_branch: *Branch,
target_branch: *const Branch,
+ comptime assert_same_deaths: bool,
) !void {
const parent_branch =
if (update_parent) &self.branch_stack.items[self.branch_stack.items.len - 1] else undefined;
- if (update_parent) try self.ensureProcessDeathCapacity(target_branch.inst_table.count());
- const target_slice = target_branch.inst_table.entries.slice();
- for (target_slice.items(.key), target_slice.items(.value)) |target_key, target_value| {
+ if (update_parent) try self.ensureProcessDeathCapacity(target_branch.inst_table.count());
+ var target_it = target_branch.inst_table.iterator();
+ while (target_it.next()) |target_entry| {
+ const target_key = target_entry.key_ptr.*;
+ const target_value = target_entry.value_ptr.*;
const canon_mcv = if (canon_branch.inst_table.fetchSwapRemove(target_key)) |canon_entry| blk: {
// The instruction's MCValue is overridden in both branches.
if (update_parent) {
parent_branch.inst_table.putAssumeCapacity(target_key, canon_entry.value);
}
if (target_value == .dead) {
- assert(canon_entry.value == .dead);
+ if (assert_same_deaths) assert(canon_entry.value == .dead);
continue;
}
break :blk canon_entry.value;
} else blk: {
if (target_value == .dead) continue;
// The instruction is only overridden in the else branch.
- // If integer overflows occurs, the question is: why wasn't the instruction marked dead?
+ // If integer overflow occurs, the question is: why wasn't the instruction marked dead?
break :blk self.getResolvedInstValue(target_key).?.*;
};
log.debug("consolidating target_entry {d} {}=>{}", .{ target_key, target_value, canon_mcv });
@@ -5786,9 +5811,12 @@ fn canonicaliseBranches(
self.freeValue(target_value);
// TODO track the new register / stack allocation
}
+
if (update_parent) try self.ensureProcessDeathCapacity(canon_branch.inst_table.count());
- const canon_slice = canon_branch.inst_table.entries.slice();
- for (canon_slice.items(.key), canon_slice.items(.value)) |canon_key, canon_value| {
+ var canon_it = canon_branch.inst_table.iterator();
+ while (canon_it.next()) |canon_entry| {
+ const canon_key = canon_entry.key_ptr.*;
+ const canon_value = canon_entry.value_ptr.*;
// We already deleted the items from this table that matched the target_branch.
// So these are all instructions that are only overridden in the canon branch.
const parent_mcv =
@@ -5821,22 +5849,19 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
}
fn airBr(self: *Self, inst: Air.Inst.Index) !void {
- const branch = self.air.instructions.items(.data)[inst].br;
- try self.br(inst, branch.block_inst, branch.operand);
- return self.finishAir(inst, .dead, .{ branch.operand, .none, .none });
-}
+ const br = self.air.instructions.items(.data)[inst].br;
+ const block = br.block_inst;
-fn br(self: *Self, inst: Air.Inst.Index, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
// The first break instruction encounters `.none` here and chooses a
// machine code value for the block result, populating this field.
// Following break instructions encounter that value and use it for
// the location to store their block results.
if (self.getResolvedInstValue(block)) |dst_mcv| {
- const src_mcv = try self.resolveInst(operand);
+ const src_mcv = try self.resolveInst(br.operand);
switch (dst_mcv.*) {
.none => {
const result = result: {
- if (self.reuseOperand(inst, operand, 0, src_mcv)) break :result src_mcv;
+ if (self.reuseOperand(inst, br.operand, 0, src_mcv)) break :result src_mcv;
const new_mcv = try self.allocRegOrMem(block, true);
try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, src_mcv);
@@ -5848,16 +5873,50 @@ fn br(self: *Self, inst: Air.Inst.Index, block: Air.Inst.Index, operand: Air.Ins
else => try self.setRegOrMem(self.air.typeOfIndex(block), dst_mcv.*, src_mcv),
}
}
- return self.brVoid(block);
-}
-fn brVoid(self: *Self, block: Air.Inst.Index) !void {
+ // Process operand death early so that it is properly accounted for in the Branch below.
+ if (self.liveness.operandDies(inst, 0)) {
+ if (Air.refToIndex(br.operand)) |op_inst| self.processDeath(op_inst);
+ }
+
const block_data = self.blocks.getPtr(block).?;
+ {
+ var branch = Branch{};
+ errdefer branch.deinit(self.gpa);
+
+ var branch_i = self.branch_stack.items.len - 1;
+ while (branch_i >= block_data.branch_depth) : (branch_i -= 1) {
+ const table = &self.branch_stack.items[branch_i].inst_table;
+ try branch.inst_table.ensureUnusedCapacity(self.gpa, table.count());
+ var it = table.iterator();
+ while (it.next()) |entry| {
+ const gop = branch.inst_table.getOrPutAssumeCapacity(entry.key_ptr.*);
+ if (!gop.found_existing) gop.value_ptr.* = entry.value_ptr.*;
+ }
+ }
+
+ if (block_data.branch) |*prev_branch| {
+ log.debug("brVoid: %{d}", .{inst});
+ log.debug("Upper branches:", .{});
+ for (self.branch_stack.items) |bs| {
+ log.debug("{}", .{bs.fmtDebug()});
+ }
+ log.debug("Prev branch: {}", .{prev_branch.fmtDebug()});
+ log.debug("Cur branch: {}", .{branch.fmtDebug()});
+
+ try self.canonicaliseBranches(false, prev_branch, &branch, false);
+ prev_branch.deinit(self.gpa);
+ }
+ block_data.branch = branch;
+ }
+
// Emit a jump with a relocation. It will be patched up after the block ends.
try block_data.relocs.ensureUnusedCapacity(self.gpa, 1);
// Leave the jump offset undefined
const jmp_reloc = try self.asmJmpReloc(undefined);
block_data.relocs.appendAssumeCapacity(jmp_reloc);
+
+ self.finishAirBookkeeping();
}
fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig
index 978c75c92f..9ba91c64f3 100644
--- a/test/behavior/cast.zig
+++ b/test/behavior/cast.zig
@@ -38,8 +38,6 @@ fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
}
test "resolve undefined with integer" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
-
try testResolveUndefWithInt(true, 1234);
comptime try testResolveUndefWithInt(true, 1234);
}
diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig
index 72784d9abc..9076f9f9ac 100644
--- a/test/behavior/enum.zig
+++ b/test/behavior/enum.zig
@@ -904,7 +904,6 @@ test "enum literal casting to tagged union" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const Arch = union(enum) {
x86_64,
diff --git a/test/behavior/if.zig b/test/behavior/if.zig
index 223d73ac85..730c0713c6 100644
--- a/test/behavior/if.zig
+++ b/test/behavior/if.zig
@@ -115,7 +115,6 @@ test "if peer expressions inferred optional type" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
var self: []const u8 = "abcdef";
var index: usize = 0;
diff --git a/tools/lldb_pretty_printers.py b/tools/lldb_pretty_printers.py
index b72b6f9760..e0b84e1b41 100644
--- a/tools/lldb_pretty_printers.py
+++ b/tools/lldb_pretty_printers.py
@@ -164,6 +164,20 @@ class zig_ErrorUnion_SynthProvider:
def get_child_index(self, name): return 0 if name == ('payload' if self.payload else 'error_set') else -1
def get_child_at_index(self, index): return self.payload or self.error_set if index == 0 else None
+class zig_TaggedUnion_SynthProvider:
+ def __init__(self, value, _=None): self.value = value
+ def update(self):
+ try:
+ self.tag = self.value.GetChildMemberWithName('tag')
+ self.payload = self.value.GetChildMemberWithName('payload').GetChildMemberWithName(self.tag.value)
+ except: pass
+ def has_children(self): return True
+ def num_children(self): return 1 + (self.payload is not None)
+ def get_child_index(self, name):
+ try: return ('tag', 'payload').index(name)
+ except: return -1
+ def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index >= 0 and index < 2 else None
+
# Define Zig Standard Library
class std_SegmentedList_SynthProvider:
@@ -606,3 +620,4 @@ def __lldb_init_module(debugger, _=None):
add(debugger, category='zig.stage2', type='type.Type', summary=True)
add(debugger, category='zig.stage2', type='value.Value', identifier='TagOrPayloadPtr', synth=True)
add(debugger, category='zig.stage2', type='value.Value', summary=True)
+ add(debugger, category='zig.stage2', type='arch.x86_64.CodeGen.MCValue', identifier='zig_TaggedUnion', synth=True, inline_children=True, summary=True)
From 5e0f09168452bb099d487fd4e2fb6b9f37de5640 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Fri, 24 Mar 2023 17:44:26 -0400
Subject: [PATCH 095/216] x86_64: try to fix br canonicalization
---
src/arch/x86_64/CodeGen.zig | 106 +++++++++++++++++++-----------------
1 file changed, 57 insertions(+), 49 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index b1efcca1ac..e5028b17fc 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -214,11 +214,11 @@ const StackAllocation = struct {
const BlockData = struct {
relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},
- branch: ?Branch = null,
+ branch: Branch = .{},
branch_depth: u32,
fn deinit(self: *BlockData, gpa: Allocator) void {
- if (self.branch) |*branch| branch.deinit(gpa);
+ self.branch.deinit(gpa);
self.relocs.deinit(gpa);
self.* = undefined;
}
@@ -2759,7 +2759,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
};
defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);
- const dst_reg = try self.register_manager.allocReg(inst, gp);
+ const dst_reg = try self.register_manager.allocReg(null, gp);
const dst_mcv = MCValue{ .register = dst_reg };
const dst_lock = self.register_manager.lockReg(dst_reg);
defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
@@ -2774,14 +2774,14 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
}
const src_bits = src_ty.bitSize(self.target.*);
- const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits });
- const width_mcv = MCValue{ .register = width_reg };
+ const width_mcv =
+ try self.copyToRegisterWithInstTracking(inst, dst_ty, .{ .immediate = src_bits });
try self.genBinOpMir(.bsr, src_ty, dst_mcv, mat_src_mcv);
const dst_abi_size = @intCast(u32, @max(dst_ty.abiSize(self.target.*), 2));
try self.asmCmovccRegisterRegister(
registerAlias(dst_reg, dst_abi_size),
- registerAlias(width_reg, dst_abi_size),
+ registerAlias(width_mcv.register, dst_abi_size),
.z,
);
@@ -2845,7 +2845,6 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
registerAlias(width_reg, abi_size),
.z,
);
-
break :result dst_mcv;
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
@@ -5297,7 +5296,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
log.debug("Then branch: {}", .{then_branch.fmtDebug()});
log.debug("Else branch: {}", .{else_branch.fmtDebug()});
- try self.canonicaliseBranches(true, &then_branch, &else_branch, true);
+ try self.canonicaliseBranches(true, &then_branch, &else_branch, true, true);
// We already took care of pl_op.operand earlier, so we're going
// to pass .none here
@@ -5611,41 +5610,32 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
block_data.deinit(self.gpa);
}
- try self.branch_stack.append(.{});
- defer _ = self.branch_stack.pop();
-
const ty = self.air.typeOfIndex(inst);
const unused = !ty.hasRuntimeBitsIgnoreComptime() or self.liveness.isUnused(inst);
+
{
// Here we use `.none` to represent a null value so that the first break
// instruction will choose a MCValue for the block result and overwrite
// this field. Following break instructions will use that MCValue to put
// their block results.
const result: MCValue = if (unused) .dead else .none;
- const branch = &self.branch_stack.items[branch_depth];
+ const branch = &self.branch_stack.items[branch_depth - 1];
try branch.inst_table.putNoClobber(self.gpa, inst, result);
}
- const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
- const extra = self.air.extraData(Air.Block, ty_pl.payload);
- const body = self.air.extra[extra.end..][0..extra.data.body_len];
- try self.genBody(body);
+ {
+ try self.branch_stack.append(.{});
+ errdefer _ = self.branch_stack.pop();
+
+ const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
+ const extra = self.air.extraData(Air.Block, ty_pl.payload);
+ const body = self.air.extra[extra.end..][0..extra.data.body_len];
+ try self.genBody(body);
+ }
const block_data = self.blocks.getPtr(inst).?;
- {
- const src_branch = block_data.branch orelse self.branch_stack.items[branch_depth];
- const dst_branch = &self.branch_stack.items[branch_depth - 1];
- try dst_branch.inst_table.ensureUnusedCapacity(self.gpa, src_branch.inst_table.count());
- var it = src_branch.inst_table.iterator();
- while (it.next()) |entry| {
- const tracked_inst = entry.key_ptr.*;
- const tracked_value = entry.value_ptr.*;
- if (dst_branch.inst_table.fetchPutAssumeCapacity(tracked_inst, tracked_value)) |old_entry| {
- self.freeValue(old_entry.value);
- }
- self.getValue(tracked_value, tracked_inst);
- }
- }
+ const target_branch = self.branch_stack.pop();
+ try self.canonicaliseBranches(true, &block_data.branch, &target_branch, false, false);
for (block_data.relocs.items) |reloc| try self.performReloc(reloc);
@@ -5727,7 +5717,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
log.debug("Case-{d} branch: {}", .{ case_i, case_branch.fmtDebug() });
const final = case_i == cases_len - 1;
if (prev_branch) |*canon_branch| {
- try self.canonicaliseBranches(final, canon_branch, &case_branch, true);
+ try self.canonicaliseBranches(final, canon_branch, &case_branch, true, true);
canon_branch.deinit(self.gpa);
}
prev_branch = case_branch;
@@ -5762,7 +5752,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
log.debug("Else branch: {}", .{else_branch.fmtDebug()});
if (prev_branch) |*canon_branch| {
- try self.canonicaliseBranches(true, canon_branch, &else_branch, true);
+ try self.canonicaliseBranches(true, canon_branch, &else_branch, true, true);
canon_branch.deinit(self.gpa);
}
prev_branch = else_branch;
@@ -5778,6 +5768,7 @@ fn canonicaliseBranches(
update_parent: bool,
canon_branch: *Branch,
target_branch: *const Branch,
+ comptime set_values: bool,
comptime assert_same_deaths: bool,
) !void {
const parent_branch =
@@ -5790,16 +5781,24 @@ fn canonicaliseBranches(
const target_value = target_entry.value_ptr.*;
const canon_mcv = if (canon_branch.inst_table.fetchSwapRemove(target_key)) |canon_entry| blk: {
// The instruction's MCValue is overridden in both branches.
- if (update_parent) {
- parent_branch.inst_table.putAssumeCapacity(target_key, canon_entry.value);
- }
if (target_value == .dead) {
+ if (update_parent) {
+ parent_branch.inst_table.putAssumeCapacity(target_key, .dead);
+ }
if (assert_same_deaths) assert(canon_entry.value == .dead);
continue;
}
+ if (update_parent) {
+ parent_branch.inst_table.putAssumeCapacity(target_key, canon_entry.value);
+ }
break :blk canon_entry.value;
} else blk: {
- if (target_value == .dead) continue;
+ if (target_value == .dead) {
+ if (update_parent) {
+ parent_branch.inst_table.putAssumeCapacity(target_key, .dead);
+ }
+ continue;
+ }
// The instruction is only overridden in the else branch.
// If integer overflow occurs, the question is: why wasn't the instruction marked dead?
break :blk self.getResolvedInstValue(target_key).?.*;
@@ -5807,7 +5806,9 @@ fn canonicaliseBranches(
log.debug("consolidating target_entry {d} {}=>{}", .{ target_key, target_value, canon_mcv });
// TODO make sure the destination stack offset / register does not already have something
// going on there.
- try self.setRegOrMem(self.air.typeOfIndex(target_key), canon_mcv, target_value);
+ if (set_values) {
+ try self.setRegOrMem(self.air.typeOfIndex(target_key), canon_mcv, target_value);
+ } else self.getValue(canon_mcv, target_key);
self.freeValue(target_value);
// TODO track the new register / stack allocation
}
@@ -5825,7 +5826,9 @@ fn canonicaliseBranches(
log.debug("consolidating canon_entry {d} {}=>{}", .{ canon_key, parent_mcv, canon_value });
// TODO make sure the destination stack offset / register does not already have something
// going on there.
- try self.setRegOrMem(self.air.typeOfIndex(canon_key), canon_value, parent_mcv);
+ if (set_values) {
+ try self.setRegOrMem(self.air.typeOfIndex(canon_key), canon_value, parent_mcv);
+ } else self.getValue(canon_value, canon_key);
self.freeValue(parent_mcv);
// TODO track the new register / stack allocation
}
@@ -5890,23 +5893,28 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
try branch.inst_table.ensureUnusedCapacity(self.gpa, table.count());
var it = table.iterator();
while (it.next()) |entry| {
+ // This loop could be avoided by tracking inst depth, which
+ // will be needed later anyway for reusing loop deaths.
+ var parent_branch_i = block_data.branch_depth - 1;
+ while (parent_branch_i > 0) : (parent_branch_i -= 1) {
+ const parent_table = &self.branch_stack.items[parent_branch_i].inst_table;
+ if (parent_table.contains(entry.key_ptr.*)) break;
+ } else continue;
const gop = branch.inst_table.getOrPutAssumeCapacity(entry.key_ptr.*);
if (!gop.found_existing) gop.value_ptr.* = entry.value_ptr.*;
}
}
- if (block_data.branch) |*prev_branch| {
- log.debug("brVoid: %{d}", .{inst});
- log.debug("Upper branches:", .{});
- for (self.branch_stack.items) |bs| {
- log.debug("{}", .{bs.fmtDebug()});
- }
- log.debug("Prev branch: {}", .{prev_branch.fmtDebug()});
- log.debug("Cur branch: {}", .{branch.fmtDebug()});
-
- try self.canonicaliseBranches(false, prev_branch, &branch, false);
- prev_branch.deinit(self.gpa);
+ log.debug("airBr: %{d}", .{inst});
+ log.debug("Upper branches:", .{});
+ for (self.branch_stack.items) |bs| {
+ log.debug("{}", .{bs.fmtDebug()});
}
+ log.debug("Prev branch: {}", .{block_data.branch.fmtDebug()});
+ log.debug("Cur branch: {}", .{branch.fmtDebug()});
+
+ try self.canonicaliseBranches(false, &block_data.branch, &branch, true, false);
+ block_data.branch.deinit(self.gpa);
block_data.branch = branch;
}
From 0987ed1970bc0332844a0e398b3c981b38627ed6 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Fri, 24 Mar 2023 17:55:47 -0400
Subject: [PATCH 096/216] x86_64: detect canonicalisation hazards
---
src/arch/x86_64/CodeGen.zig | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index e5028b17fc..7335d3ac94 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -5771,6 +5771,9 @@ fn canonicaliseBranches(
comptime set_values: bool,
comptime assert_same_deaths: bool,
) !void {
+ var hazard_map = std.AutoHashMap(MCValue, void).init(self.gpa);
+ defer hazard_map.deinit();
+
const parent_branch =
if (update_parent) &self.branch_stack.items[self.branch_stack.items.len - 1] else undefined;
@@ -5804,8 +5807,10 @@ fn canonicaliseBranches(
break :blk self.getResolvedInstValue(target_key).?.*;
};
log.debug("consolidating target_entry {d} {}=>{}", .{ target_key, target_value, canon_mcv });
- // TODO make sure the destination stack offset / register does not already have something
+ // TODO handle the case where the destination stack offset / register has something
// going on there.
+ assert(!hazard_map.contains(target_value));
+ try hazard_map.putNoClobber(canon_mcv, {});
if (set_values) {
try self.setRegOrMem(self.air.typeOfIndex(target_key), canon_mcv, target_value);
} else self.getValue(canon_mcv, target_key);
@@ -5824,8 +5829,10 @@ fn canonicaliseBranches(
if (canon_value != .dead) self.getResolvedInstValue(canon_key).?.* else undefined;
if (canon_value != .dead) {
log.debug("consolidating canon_entry {d} {}=>{}", .{ canon_key, parent_mcv, canon_value });
- // TODO make sure the destination stack offset / register does not already have something
+ // TODO handle the case where the destination stack offset / register has something
// going on there.
+ assert(!hazard_map.contains(parent_mcv));
+ try hazard_map.putNoClobber(canon_value, {});
if (set_values) {
try self.setRegOrMem(self.air.typeOfIndex(canon_key), canon_value, parent_mcv);
} else self.getValue(canon_value, canon_key);
From 4ab4bd04fe8f4308d67b757eaa88f5a356aea688 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Fri, 24 Mar 2023 21:33:17 -0400
Subject: [PATCH 097/216] x86_64: add back assume unused
This seems to have been asserting due to a value tracking bug that has
since been fixed.
---
src/arch/x86_64/CodeGen.zig | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 7335d3ac94..66e1904420 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -2586,7 +2586,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
const index_ty = self.air.typeOf(bin_op.rhs);
const index = try self.resolveInst(bin_op.rhs);
const index_lock: ?RegisterLock = switch (index) {
- .register => |reg| self.register_manager.lockReg(reg),
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
else => null,
};
defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
@@ -2635,7 +2635,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
const index_ty = self.air.typeOf(extra.rhs);
const index = try self.resolveInst(extra.rhs);
const index_lock: ?RegisterLock = switch (index) {
- .register => |reg| self.register_manager.lockReg(reg),
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
else => null,
};
defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
From f6a2b72ba8b6ab8f8dbef223788c6458af3d4da0 Mon Sep 17 00:00:00 2001
From: tjog <28024277+tjog@users.noreply.github.com>
Date: Thu, 23 Mar 2023 02:21:15 +0800
Subject: [PATCH 098/216] std.process.Child: implement maxrss on Darwin
Notably the Darwin (XNU) kernel the maxrss field is number of bytes
and not kilobytes (kibibytes) like other platforms (e.g. Linux, BSD).
watchOS and tvOS are not supported because they do not have the ability
to spawn a child process. iOS is enabled but due to OS sandboxing it
should fail with a permission error.
---
lib/std/child_process.zig | 28 ++++++++++++++++++++--------
lib/std/process.zig | 2 +-
2 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig
index ca447b068d..bd67d344c7 100644
--- a/lib/std/child_process.zig
+++ b/lib/std/child_process.zig
@@ -17,7 +17,6 @@ const Os = std.builtin.Os;
const TailQueue = std.TailQueue;
const maxInt = std.math.maxInt;
const assert = std.debug.assert;
-const is_darwin = builtin.target.isDarwin();
pub const ChildProcess = struct {
pub const Id = switch (builtin.os.tag) {
@@ -77,7 +76,7 @@ pub const ChildProcess = struct {
/// requested statistics may or may not be available. If they are
/// available, then the `resource_usage_statistics` field will be populated
/// after calling `wait`.
- /// On Linux, this obtains rusage statistics from wait4().
+ /// On Linux and Darwin, this obtains rusage statistics from wait4().
request_resource_usage_statistics: bool = false,
/// This is available after calling wait if
@@ -106,12 +105,20 @@ pub const ChildProcess = struct {
return null;
}
},
+ .macos, .ios => {
+ if (rus.rusage) |ru| {
+ // Darwin oddly reports in bytes instead of kilobytes.
+ return @intCast(usize, ru.maxrss);
+ } else {
+ return null;
+ }
+ },
else => return null,
}
}
const rusage_init = switch (builtin.os.tag) {
- .linux => @as(?std.os.rusage, null),
+ .linux, .macos, .ios => @as(?std.os.rusage, null),
.windows => @as(?windows.VM_COUNTERS, null),
else => {},
};
@@ -385,11 +392,16 @@ pub const ChildProcess = struct {
fn waitUnwrapped(self: *ChildProcess) !void {
const res: os.WaitPidResult = res: {
- if (builtin.os.tag == .linux and self.request_resource_usage_statistics) {
- var ru: std.os.rusage = undefined;
- const res = os.wait4(self.id, 0, &ru);
- self.resource_usage_statistics.rusage = ru;
- break :res res;
+ if (self.request_resource_usage_statistics) {
+ switch (builtin.os.tag) {
+ .linux, .macos, .ios => {
+ var ru: std.os.rusage = undefined;
+ const res = os.wait4(self.id, 0, &ru);
+ self.resource_usage_statistics.rusage = ru;
+ break :res res;
+ },
+ else => {},
+ }
}
break :res os.waitpid(self.id, 0);
diff --git a/lib/std/process.zig b/lib/std/process.zig
index d06a012af2..f870b85774 100644
--- a/lib/std/process.zig
+++ b/lib/std/process.zig
@@ -1093,7 +1093,7 @@ pub const can_execv = switch (builtin.os.tag) {
/// Tells whether spawning child processes is supported (e.g. via ChildProcess)
pub const can_spawn = switch (builtin.os.tag) {
- .wasi => false,
+ .wasi, .watchos, .tvos => false,
else => true,
};
From fcc86832d685c09c37570562ee1036aa1eb18ea6 Mon Sep 17 00:00:00 2001
From: Jay Petacat
Date: Sat, 25 Mar 2023 00:03:22 -0600
Subject: [PATCH 099/216] std.enums.IndexedSet: Add initOne and initMany
---
lib/std/enums.zig | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/lib/std/enums.zig b/lib/std/enums.zig
index 61c2f01e23..8ef097e909 100644
--- a/lib/std/enums.zig
+++ b/lib/std/enums.zig
@@ -775,6 +775,18 @@ pub fn IndexedSet(comptime I: type, comptime Ext: fn (type) type) type {
return .{ .bits = BitSet.initFull() };
}
+ /// Returns a set containing multiple keys.
+ pub fn initMany(keys: []const Key) Self {
+ var set = initEmpty();
+ for (keys) |key| set.insert(key);
+ return set;
+ }
+
+ /// Returns a set containing a single key.
+ pub fn initOne(key: Key) Self {
+ return initMany(&[_]Key{key});
+ }
+
/// Returns the number of keys in the set.
pub fn count(self: Self) usize {
return self.bits.count();
@@ -900,20 +912,8 @@ test "pure EnumSet fns" {
const empty = EnumSet(Suit).initEmpty();
const full = EnumSet(Suit).initFull();
-
- const black = black: {
- var set = EnumSet(Suit).initEmpty();
- set.insert(.spades);
- set.insert(.clubs);
- break :black set;
- };
-
- const red = red: {
- var set = EnumSet(Suit).initEmpty();
- set.insert(.hearts);
- set.insert(.diamonds);
- break :red set;
- };
+ const black = EnumSet(Suit).initMany(&[_]Suit{ .spades, .clubs });
+ const red = EnumSet(Suit).initMany(&[_]Suit{ .hearts, .diamonds });
try testing.expect(empty.eql(empty));
try testing.expect(full.eql(full));
From 37f6f7990e882ac9869513cf920f8cd0c4850039 Mon Sep 17 00:00:00 2001
From: Marc Tiehuis
Date: Sat, 25 Mar 2023 22:49:40 +1300
Subject: [PATCH 100/216] enable more float-parsing tests
Since removing the stage1 backend we no longer have a disagreement here.
---
lib/std/fmt/parse_float.zig | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/lib/std/fmt/parse_float.zig b/lib/std/fmt/parse_float.zig
index e92564ef01..b14fe5ca3c 100644
--- a/lib/std/fmt/parse_float.zig
+++ b/lib/std/fmt/parse_float.zig
@@ -149,7 +149,7 @@ test "fmt.parseFloat hex.f64" {
try testing.expectEqual(try parseFloat(f64, "0x1p-1022"), math.floatMin(f64));
try testing.expectEqual(try parseFloat(f64, "-0x1p-1022"), -math.floatMin(f64));
// Min denormalized value.
- //try testing.expectEqual(try parseFloat(f64, "0x1p-1074"), math.floatTrueMin(f64));
+ try testing.expectEqual(try parseFloat(f64, "0x1p-1074"), math.floatTrueMin(f64));
try testing.expectEqual(try parseFloat(f64, "-0x1p-1074"), -math.floatTrueMin(f64));
}
test "fmt.parseFloat hex.f128" {
@@ -166,7 +166,6 @@ test "fmt.parseFloat hex.f128" {
// // Min denormalized value.
try testing.expectEqual(try parseFloat(f128, "0x1p-16494"), math.floatTrueMin(f128));
try testing.expectEqual(try parseFloat(f128, "-0x1p-16494"), -math.floatTrueMin(f128));
-
- // NOTE: We are performing round-to-even. Previous behavior was round-up.
- // try testing.expectEqual(try parseFloat(f128, "0x1.edcb34a235253948765432134674fp-1"), 0x1.edcb34a235253948765432134674fp-1);
+ // ensure round-to-even
+ try testing.expectEqual(try parseFloat(f128, "0x1.edcb34a235253948765432134674fp-1"), 0x1.edcb34a235253948765432134674fp-1);
}
From 3ece9758574e600c1d97add143c24fefed3d2d82 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 25 Mar 2023 00:05:54 -0400
Subject: [PATCH 101/216] x86_64: implement saturating arithmetic
---
src/arch/x86_64/CodeGen.zig | 199 +++++++++++++++++++++++++++++-------
src/arch/x86_64/encoder.zig | 2 +-
src/register_manager.zig | 19 +++-
3 files changed, 175 insertions(+), 45 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 66e1904420..6a459684ca 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -1550,28 +1550,161 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch});
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
+ const ty = self.air.typeOf(bin_op.lhs);
+
+ const lhs_mcv = try self.resolveInst(bin_op.lhs);
+ const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv))
+ lhs_mcv
+ else
+ try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv);
+ const dst_reg = dst_mcv.register;
+ const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
+ defer self.register_manager.unlockReg(dst_lock);
+
+ const rhs_mcv = try self.resolveInst(bin_op.rhs);
+ const rhs_lock = switch (rhs_mcv) {
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ else => null,
+ };
+ defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const limit_reg = try self.register_manager.allocReg(null, gp);
+ const limit_mcv = MCValue{ .register = limit_reg };
+ const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
+ defer self.register_manager.unlockReg(limit_lock);
+
+ const reg_bits = self.regBitSize(ty);
+ const cc: Condition = if (ty.isSignedInt()) cc: {
+ try self.genSetReg(ty, limit_reg, dst_mcv);
+ try self.genBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
+ try self.genBinOpMir(.xor, ty, limit_mcv, .{
+ .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
+ });
+ break :cc .o;
+ } else cc: {
+ try self.genSetReg(ty, limit_reg, .{
+ .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits),
+ });
+ break :cc .c;
+ };
+ try self.genBinOpMir(.add, ty, dst_mcv, rhs_mcv);
+
+ const abi_size = @intCast(u32, @max(ty.abiSize(self.target.*), 2));
+ try self.asmCmovccRegisterRegister(
+ registerAlias(dst_reg, abi_size),
+ registerAlias(limit_reg, abi_size),
+ cc,
+ );
+ break :result dst_mcv;
+ };
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch});
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
+ const ty = self.air.typeOf(bin_op.lhs);
+
+ const lhs_mcv = try self.resolveInst(bin_op.lhs);
+ const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv))
+ lhs_mcv
+ else
+ try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv);
+ const dst_reg = dst_mcv.register;
+ const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
+ defer self.register_manager.unlockReg(dst_lock);
+
+ const rhs_mcv = try self.resolveInst(bin_op.rhs);
+ const rhs_lock = switch (rhs_mcv) {
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ else => null,
+ };
+ defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const limit_reg = try self.register_manager.allocReg(null, gp);
+ const limit_mcv = MCValue{ .register = limit_reg };
+ const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
+ defer self.register_manager.unlockReg(limit_lock);
+
+ const reg_bits = self.regBitSize(ty);
+ const cc: Condition = if (ty.isSignedInt()) cc: {
+ try self.genSetReg(ty, limit_reg, dst_mcv);
+ try self.genBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
+ try self.genBinOpMir(.xor, ty, limit_mcv, .{
+ .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
+ });
+ break :cc .o;
+ } else cc: {
+ try self.genSetReg(ty, limit_reg, .{ .immediate = 0 });
+ break :cc .c;
+ };
+ try self.genBinOpMir(.sub, ty, dst_mcv, rhs_mcv);
+
+ const abi_size = @intCast(u32, @max(ty.abiSize(self.target.*), 2));
+ try self.asmCmovccRegisterRegister(
+ registerAlias(dst_reg, abi_size),
+ registerAlias(limit_reg, abi_size),
+ cc,
+ );
+ break :result dst_mcv;
+ };
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement mul_sat for {}", .{self.target.cpu.arch});
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
+ const ty = self.air.typeOf(bin_op.lhs);
+
+ try self.spillRegisters(&.{ .rax, .rdx });
+ const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx });
+ defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const lhs_mcv = try self.resolveInst(bin_op.lhs);
+ const lhs_lock = switch (lhs_mcv) {
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ else => null,
+ };
+ defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const rhs_mcv = try self.resolveInst(bin_op.rhs);
+ const rhs_lock = switch (rhs_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ else => null,
+ };
+ defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const limit_reg = try self.register_manager.allocReg(null, gp);
+ const limit_mcv = MCValue{ .register = limit_reg };
+ const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
+ defer self.register_manager.unlockReg(limit_lock);
+
+ const reg_bits = self.regBitSize(ty);
+ const cc: Condition = if (ty.isSignedInt()) cc: {
+ try self.genSetReg(ty, limit_reg, lhs_mcv);
+ try self.genBinOpMir(.xor, ty, limit_mcv, rhs_mcv);
+ try self.genBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
+ try self.genBinOpMir(.xor, ty, limit_mcv, .{
+ .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
+ });
+ break :cc .o;
+ } else cc: {
+ try self.genSetReg(ty, limit_reg, .{
+ .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits),
+ });
+ break :cc .c;
+ };
+
+ const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, lhs_mcv, rhs_mcv);
+ const abi_size = @intCast(u32, @max(ty.abiSize(self.target.*), 2));
+ try self.asmCmovccRegisterRegister(
+ registerAlias(dst_mcv.register, abi_size),
+ registerAlias(limit_reg, abi_size),
+ cc,
+ );
+ break :result dst_mcv;
+ };
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
@@ -3915,7 +4048,8 @@ fn genMulDivBinOp(
if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) {
return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
}
- if (ty.abiSize(self.target.*) > 8) {
+ const abi_size = @intCast(u32, ty.abiSize(self.target.*));
+ if (abi_size > 8) {
return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
}
if (tag == .div_float) {
@@ -3925,10 +4059,8 @@ fn genMulDivBinOp(
assert(self.register_manager.isRegFree(.rax));
assert(self.register_manager.isRegFree(.rdx));
- const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx });
- defer for (reg_locks) |reg| {
- self.register_manager.unlockReg(reg);
- };
+ const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx });
+ defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
const int_info = ty.intInfo(self.target.*);
const signedness = int_info.signedness;
@@ -3953,35 +4085,24 @@ fn genMulDivBinOp(
const mir_tag: Mir.Inst.Tag = switch (signedness) {
.signed => switch (tag) {
- .mul, .mulwrap => Mir.Inst.Tag.imul,
- .div_trunc, .div_exact, .rem => Mir.Inst.Tag.idiv,
+ .mul, .mulwrap => .imul,
+ .div_trunc, .div_exact, .rem => .idiv,
else => unreachable,
},
.unsigned => switch (tag) {
- .mul, .mulwrap => Mir.Inst.Tag.mul,
- .div_trunc, .div_exact, .rem => Mir.Inst.Tag.div,
+ .mul, .mulwrap => .mul,
+ .div_trunc, .div_exact, .rem => .div,
else => unreachable,
},
};
try self.genIntMulDivOpMir(mir_tag, ty, .signed, lhs, rhs);
- switch (signedness) {
- .signed => switch (tag) {
- .mul, .mulwrap, .div_trunc, .div_exact => return MCValue{ .register = .rax },
- .rem => return MCValue{ .register = .rdx },
- else => unreachable,
- },
- .unsigned => switch (tag) {
- .mul, .mulwrap, .div_trunc, .div_exact => return MCValue{
- .register = registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*))),
- },
- .rem => return MCValue{
- .register = registerAlias(.rdx, @intCast(u32, ty.abiSize(self.target.*))),
- },
- else => unreachable,
- },
- }
+ return .{ .register = registerAlias(switch (tag) {
+ .mul, .mulwrap, .div_trunc, .div_exact => .rax,
+ .rem => .rdx,
+ else => unreachable,
+ }, abi_size) };
},
.mod => {
@@ -3998,14 +4119,14 @@ fn genMulDivBinOp(
const result: MCValue = if (maybe_inst) |inst|
try self.copyToRegisterWithInstTracking(inst, ty, lhs)
else
- MCValue{ .register = try self.copyToTmpRegister(ty, lhs) };
+ .{ .register = try self.copyToTmpRegister(ty, lhs) };
try self.genBinOpMir(.sub, ty, result, div_floor);
return result;
},
.unsigned => {
try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, rhs);
- return MCValue{ .register = registerAlias(.rdx, @intCast(u32, ty.abiSize(self.target.*))) };
+ return .{ .register = registerAlias(.rdx, abi_size) };
},
}
},
diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig
index b3de7ec1bd..9206923ece 100644
--- a/src/arch/x86_64/encoder.zig
+++ b/src/arch/x86_64/encoder.zig
@@ -117,7 +117,7 @@ pub const Instruction = struct {
pub fn new(mnemonic: Mnemonic, args: Init) !Instruction {
const encoding = (try Encoding.findByMnemonic(mnemonic, args)) orelse {
- log.debug("no encoding found for: {s} {s} {s} {s} {s} {s}", .{
+ log.err("no encoding found for: {s} {s} {s} {s} {s} {s}", .{
@tagName(args.prefix),
@tagName(mnemonic),
@tagName(Encoding.Op.fromOperand(args.op1)),
diff --git a/src/register_manager.zig b/src/register_manager.zig
index 1a5d2fd501..fe53ba3b95 100644
--- a/src/register_manager.zig
+++ b/src/register_manager.zig
@@ -149,17 +149,26 @@ pub fn RegisterManager(
return RegisterLock{ .register = reg };
}
+ /// Like `lockReg` but locks multiple registers.
+ pub fn lockRegs(
+ self: *Self,
+ comptime count: comptime_int,
+ regs: [count]Register,
+ ) [count]?RegisterLock {
+ var results: [count]?RegisterLock = undefined;
+ for (&results, regs) |*result, reg| result.* = self.lockReg(reg);
+ return results;
+ }
+
/// Like `lockRegAssumeUnused` but locks multiple registers.
pub fn lockRegsAssumeUnused(
self: *Self,
comptime count: comptime_int,
regs: [count]Register,
) [count]RegisterLock {
- var buf: [count]RegisterLock = undefined;
- for (regs, 0..) |reg, i| {
- buf[i] = self.lockRegAssumeUnused(reg);
- }
- return buf;
+ var results: [count]RegisterLock = undefined;
+ for (&results, regs) |*result, reg| result.* = self.lockRegAssumeUnused(reg);
+ return results;
}
/// Unlocks the register allowing its re-allocation and re-use.
From d9ce69dc3949fb11c43520096001b7f06e1a96f3 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 25 Mar 2023 02:37:31 -0400
Subject: [PATCH 102/216] codegen: fix ptr-like optional constants
---
src/codegen.zig | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/codegen.zig b/src/codegen.zig
index c48200e845..a99ff18dfd 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -1063,13 +1063,12 @@ pub fn genTypedValue(
},
.Optional => {
if (typed_value.ty.isPtrLikeOptional()) {
- if (typed_value.val.isNull())
- return GenResult.mcv(.{ .immediate = 0 });
+ if (typed_value.val.tag() == .null_value) return GenResult.mcv(.{ .immediate = 0 });
var buf: Type.Payload.ElemType = undefined;
return genTypedValue(bin_file, src_loc, .{
.ty = typed_value.ty.optionalChild(&buf),
- .val = typed_value.val,
+ .val = if (typed_value.val.castTag(.opt_payload)) |pl| pl.data else typed_value.val,
}, owner_decl_index);
} else if (typed_value.ty.abiSize(target) == 1) {
return GenResult.mcv(.{ .immediate = @boolToInt(!typed_value.val.isNull()) });
From 0cfc0d0d13bd1e9f1a9119324fac624371aecdd3 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 25 Mar 2023 03:08:04 -0400
Subject: [PATCH 103/216] x86_64: implement struct_field_ptr for packed
containers
---
src/arch/x86_64/CodeGen.zig | 27 +++++++++++++++------------
test/behavior/bugs/12450.zig | 1 -
test/behavior/bugs/2578.zig | 1 -
test/behavior/bugs/726.zig | 2 --
test/behavior/fn.zig | 1 -
test/behavior/packed-struct.zig | 1 -
test/behavior/struct.zig | 1 -
7 files changed, 15 insertions(+), 19 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 6a459684ca..5b16ae5a1c 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -3659,34 +3659,37 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
- const result = try self.structFieldPtr(inst, extra.struct_operand, extra.field_index);
+ const result = try self.fieldPtr(inst, extra.struct_operand, extra.field_index);
return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
}
fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result = try self.structFieldPtr(inst, ty_op.operand, index);
+ const result = try self.fieldPtr(inst, ty_op.operand, index);
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
-fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
+fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
if (self.liveness.isUnused(inst)) {
return MCValue.dead;
}
const mcv = try self.resolveInst(operand);
const ptr_ty = self.air.typeOf(operand);
- const struct_ty = ptr_ty.childType();
- if (struct_ty.zigTypeTag() == .Struct and struct_ty.containerLayout() == .Packed) {
- return self.fail("TODO structFieldPtr implement packed structs", .{});
- }
- const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
+ const container_ty = ptr_ty.childType();
+ const field_offset = switch (container_ty.containerLayout()) {
+ .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, self.target.*)),
+ .Packed => if (container_ty.zigTypeTag() == .Struct and ptr_ty.ptrInfo().data.host_size == 0)
+ container_ty.packedStructFieldByteOffset(index, self.target.*)
+ else
+ 0,
+ };
const dst_mcv: MCValue = result: {
switch (mcv) {
.stack_offset => {
const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
- .immediate = struct_field_offset,
+ .immediate = field_offset,
});
const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
defer self.register_manager.unlockReg(offset_reg_lock);
@@ -3696,7 +3699,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
break :result dst_mcv;
},
.ptr_stack_offset => |off| {
- const ptr_stack_offset = off - @intCast(i32, struct_field_offset);
+ const ptr_stack_offset = off - @intCast(i32, field_offset);
break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };
},
.register => |reg| {
@@ -3704,7 +3707,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
defer self.register_manager.unlockReg(reg_lock);
const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
- .immediate = struct_field_offset,
+ .immediate = field_offset,
});
const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
defer self.register_manager.unlockReg(offset_reg_lock);
@@ -3725,7 +3728,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
try self.genBinOpMir(.add, ptr_ty, .{ .register = result_reg }, .{ .register = offset_reg });
break :result MCValue{ .register = result_reg };
},
- else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),
+ else => return self.fail("TODO implement fieldPtr for {}", .{mcv}),
}
};
return dst_mcv;
diff --git a/test/behavior/bugs/12450.zig b/test/behavior/bugs/12450.zig
index 5161e3ffd3..89e5c774e0 100644
--- a/test/behavior/bugs/12450.zig
+++ b/test/behavior/bugs/12450.zig
@@ -10,7 +10,6 @@ var buffer: [256]u8 = undefined;
test {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
diff --git a/test/behavior/bugs/2578.zig b/test/behavior/bugs/2578.zig
index ad4fb133e4..ff8ba141fa 100644
--- a/test/behavior/bugs/2578.zig
+++ b/test/behavior/bugs/2578.zig
@@ -14,7 +14,6 @@ fn bar(pointer: ?*anyopaque) void {
test "fixed" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
bar(t);
diff --git a/test/behavior/bugs/726.zig b/test/behavior/bugs/726.zig
index 1c552e1df1..cc5c2a5fb7 100644
--- a/test/behavior/bugs/726.zig
+++ b/test/behavior/bugs/726.zig
@@ -4,7 +4,6 @@ const builtin = @import("builtin");
test "@ptrCast from const to nullable" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const c: u8 = 4;
@@ -15,7 +14,6 @@ test "@ptrCast from const to nullable" {
test "@ptrCast from var in empty struct to nullable" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const container = struct {
diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig
index 5113e21452..e854764649 100644
--- a/test/behavior/fn.zig
+++ b/test/behavior/fn.zig
@@ -96,7 +96,6 @@ test "discard the result of a function that returns a struct" {
}
test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig
index 85214bd7d8..6b0570cb96 100644
--- a/test/behavior/packed-struct.zig
+++ b/test/behavior/packed-struct.zig
@@ -571,7 +571,6 @@ test "packed struct passed to callconv(.C) function" {
test "overaligned pointer to packed struct" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const S = packed struct { a: u32, b: u32 };
var foo: S align(4) = .{ .a = 123, .b = 456 };
diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig
index b250b5b087..25dd1c7958 100644
--- a/test/behavior/struct.zig
+++ b/test/behavior/struct.zig
@@ -827,7 +827,6 @@ test "non-packed struct with u128 entry in union" {
}
test "packed struct field passed to generic function" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
From 8f385e77caae676ad675ca13baea51751230f200 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 25 Mar 2023 03:44:02 -0400
Subject: [PATCH 104/216] x86_64: implement struct_field_val for packed
containers
---
src/arch/x86_64/CodeGen.zig | 47 ++++++++++++++++++---------------
test/behavior/bitcast.zig | 2 --
test/behavior/bugs/9584.zig | 1 -
test/behavior/packed-struct.zig | 4 ---
test/behavior/struct.zig | 3 ---
test/behavior/union.zig | 2 --
6 files changed, 26 insertions(+), 33 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 5b16ae5a1c..a4e51c7a8d 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -3745,18 +3745,22 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
}
const mcv = try self.resolveInst(operand);
- const struct_ty = self.air.typeOf(operand);
- if (struct_ty.zigTypeTag() == .Struct and struct_ty.containerLayout() == .Packed) {
- return self.fail("TODO airStructFieldVal implement packed structs", .{});
- }
- const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*);
- const struct_field_ty = struct_ty.structFieldType(index);
+ const container_ty = self.air.typeOf(operand);
+ const field_ty = container_ty.structFieldType(index);
+ const field_bit_offset = switch (container_ty.containerLayout()) {
+ .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, self.target.*) * 8),
+ .Packed => if (container_ty.castTag(.@"struct")) |struct_obj|
+ struct_obj.data.packedFieldBitOffset(self.target.*, index)
+ else
+ 0,
+ };
const result: MCValue = result: {
switch (mcv) {
.stack_offset => |off| {
- const stack_offset = off - @intCast(i32, struct_field_offset);
- break :result MCValue{ .stack_offset = stack_offset };
+ const byte_offset = std.math.divExact(u32, field_bit_offset, 8) catch
+ return self.fail("TODO implement struct_field_val for a packed struct", .{});
+ break :result MCValue{ .stack_offset = off - @intCast(i32, byte_offset) };
},
.register => |reg| {
const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
@@ -3779,27 +3783,28 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
// Shift by struct_field_offset.
- const shift = @intCast(u8, struct_field_offset * 8);
- try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv.register, .{ .immediate = shift });
+ try self.genShiftBinOpMir(
+ .shr,
+ Type.usize,
+ dst_mcv.register,
+ .{ .immediate = field_bit_offset },
+ );
- // Mask with reg.bitSize() - struct_field_size
- const max_reg_bit_width = Register.rax.bitSize();
- const mask_shift = @intCast(u6, (max_reg_bit_width - struct_field_ty.bitSize(self.target.*)));
- const mask = (~@as(u64, 0)) >> mask_shift;
+ // Mask to field_bit_size bits
+ const field_bit_size = field_ty.bitSize(self.target.*);
+ const mask = ~@as(u64, 0) >> @intCast(u6, 64 - field_bit_size);
const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });
try self.genBinOpMir(.@"and", Type.usize, dst_mcv, .{ .register = tmp_reg });
- const signedness: std.builtin.Signedness = blk: {
- if (struct_field_ty.zigTypeTag() != .Int) break :blk .unsigned;
- break :blk struct_field_ty.intInfo(self.target.*).signedness;
- };
- const field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
- if (signedness == .signed and field_size < 8) {
+ const signedness =
+ if (field_ty.isAbiInt()) field_ty.intInfo(self.target.*).signedness else .unsigned;
+ const field_byte_size = @intCast(u32, field_ty.abiSize(self.target.*));
+ if (signedness == .signed and field_byte_size < 8) {
try self.asmRegisterRegister(
.movsx,
dst_mcv.register,
- registerAlias(dst_mcv.register, field_size),
+ registerAlias(dst_mcv.register, field_byte_size),
);
}
diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig
index 552080c836..8ac87bb9c0 100644
--- a/test/behavior/bitcast.zig
+++ b/test/behavior/bitcast.zig
@@ -157,7 +157,6 @@ test "bitcast generates a temporary value" {
}
test "@bitCast packed structs at runtime and comptime" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -215,7 +214,6 @@ test "@bitCast extern structs at runtime and comptime" {
}
test "bitcast packed struct to integer and back" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/bugs/9584.zig b/test/behavior/bugs/9584.zig
index f80ff05228..307f1689bf 100644
--- a/test/behavior/bugs/9584.zig
+++ b/test/behavior/bugs/9584.zig
@@ -44,7 +44,6 @@ pub fn b(x: *X) !void {
}
test {
- if (builtin.zig_backend == .stage2_x86_64) 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
diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig
index 6b0570cb96..6cc021dd1a 100644
--- a/test/behavior/packed-struct.zig
+++ b/test/behavior/packed-struct.zig
@@ -254,7 +254,6 @@ test "regular in irregular packed struct" {
}
test "byte-aligned field pointer offsets" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -397,7 +396,6 @@ test "@ptrToInt on a packed struct field" {
}
test "optional pointer in packed struct" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -530,7 +528,6 @@ test "nested packed struct field access test" {
test "runtime init of unnamed packed struct type" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
var z: u8 = 123;
@@ -545,7 +542,6 @@ test "runtime init of unnamed packed struct type" {
test "packed struct passed to callconv(.C) function" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const S = struct {
diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig
index 25dd1c7958..61318ad6d2 100644
--- a/test/behavior/struct.zig
+++ b/test/behavior/struct.zig
@@ -387,7 +387,6 @@ const APackedStruct = packed struct {
test "packed struct" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
var foo = APackedStruct{
@@ -496,7 +495,6 @@ const Bitfields = packed struct {
test "packed struct fields are ordered from LSB to MSB" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
var all: u64 = 0x7765443322221111;
@@ -632,7 +630,6 @@ test "default struct initialization fields" {
}
test "packed array 24bits" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/union.zig b/test/behavior/union.zig
index b78bac5c3e..35bdca270e 100644
--- a/test/behavior/union.zig
+++ b/test/behavior/union.zig
@@ -1408,7 +1408,6 @@ test "union field ptr - zero sized field" {
}
test "packed union in packed struct" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
@@ -1494,7 +1493,6 @@ test "union reassignment can use previous value" {
}
test "packed union with zero-bit field" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
From 77300c02d65af81da6019995e4f1a156ef364df4 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 25 Mar 2023 05:16:33 -0400
Subject: [PATCH 105/216] x86_64: implement large ptr_elem_val
---
src/arch/x86_64/CodeGen.zig | 150 ++++++++++++++++--------------------
1 file changed, 68 insertions(+), 82 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index a4e51c7a8d..2b62854fb9 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -2386,8 +2386,8 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
.stack_offset => |off| try self.asmMemoryImmediate(
.mov,
- Memory.sib(.byte, .{ .base = .rsp, .disp = pl_abi_size - off }),
- Immediate.u(0),
+ Memory.sib(.byte, .{ .base = .rbp, .disp = pl_abi_size - off }),
+ Immediate.u(1),
),
}
}
@@ -2606,10 +2606,9 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
}
fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
- const is_volatile = false; // TODO
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
- const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: {
- const slice_ty = self.air.typeOf(bin_op.lhs);
+ const slice_ty = self.air.typeOf(bin_op.lhs);
+ const result = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs);
@@ -2696,54 +2695,44 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
}
fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
- const is_volatile = false; // TODO
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
-
- if (!is_volatile and self.liveness.isUnused(inst)) {
- return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
- }
-
- // this is identical to the `airPtrElemPtr` codegen expect here an
- // additional `mov` is needed at the end to get the actual value
-
const ptr_ty = self.air.typeOf(bin_op.lhs);
- const ptr = try self.resolveInst(bin_op.lhs);
- const ptr_lock: ?RegisterLock = switch (ptr) {
- .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
- else => null,
+ const result = if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {
+ // this is identical to the `airPtrElemPtr` codegen expect here an
+ // additional `mov` is needed at the end to get the actual value
+
+ const elem_ty = ptr_ty.elemType2();
+ const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*));
+ const index_ty = self.air.typeOf(bin_op.rhs);
+ const index_mcv = try self.resolveInst(bin_op.rhs);
+ const index_lock = switch (index_mcv) {
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ else => null,
+ };
+ defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_abi_size);
+ const offset_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
+ defer self.register_manager.unlockReg(offset_lock);
+
+ const ptr_mcv = try self.resolveInst(bin_op.lhs);
+ const elem_ptr_reg = if (ptr_mcv.isRegister() and self.liveness.operandDies(inst, 0))
+ ptr_mcv.register
+ else
+ try self.copyToTmpRegister(ptr_ty, ptr_mcv);
+ const elem_ptr_lock = self.register_manager.lockRegAssumeUnused(elem_ptr_reg);
+ defer self.register_manager.unlockReg(elem_ptr_lock);
+ try self.asmRegisterRegister(.add, elem_ptr_reg, offset_reg);
+
+ const dst_mcv = try self.allocRegOrMem(inst, true);
+ const dst_lock = switch (dst_mcv) {
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ else => null,
+ };
+ defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
+ try self.load(dst_mcv, .{ .register = elem_ptr_reg }, ptr_ty);
+ break :result dst_mcv;
};
- defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
-
- const elem_ty = ptr_ty.elemType2();
- const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*));
- const index_ty = self.air.typeOf(bin_op.rhs);
- const index = try self.resolveInst(bin_op.rhs);
- const index_lock: ?RegisterLock = switch (index) {
- .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
- else => null,
- };
- defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
-
- const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
- const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
- defer self.register_manager.unlockReg(offset_reg_lock);
-
- const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);
- try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
-
- const result: MCValue = result: {
- if (elem_abi_size > 8) {
- return self.fail("TODO copy value with size {} from pointer", .{elem_abi_size});
- } else {
- try self.asmRegisterMemory(
- .mov,
- registerAlias(dst_mcv.register, elem_abi_size),
- Memory.sib(Memory.PtrSize.fromSize(elem_abi_size), .{ .base = dst_mcv.register }),
- );
- break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) };
- }
- };
-
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
@@ -2751,36 +2740,34 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
- if (self.liveness.isUnused(inst)) {
- return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });
- }
+ const result = if (self.liveness.isUnused(inst)) .dead else result: {
+ const ptr_ty = self.air.typeOf(extra.lhs);
+ const ptr = try self.resolveInst(extra.lhs);
+ const ptr_lock: ?RegisterLock = switch (ptr) {
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ else => null,
+ };
+ defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
- const ptr_ty = self.air.typeOf(extra.lhs);
- const ptr = try self.resolveInst(extra.lhs);
- const ptr_lock: ?RegisterLock = switch (ptr) {
- .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
- else => null,
+ const elem_ty = ptr_ty.elemType2();
+ const elem_abi_size = elem_ty.abiSize(self.target.*);
+ const index_ty = self.air.typeOf(extra.rhs);
+ const index = try self.resolveInst(extra.rhs);
+ const index_lock: ?RegisterLock = switch (index) {
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ else => null,
+ };
+ defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
+ const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
+ defer self.register_manager.unlockReg(offset_reg_lock);
+
+ const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);
+ try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
+ break :result dst_mcv;
};
- defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
-
- const elem_ty = ptr_ty.elemType2();
- const elem_abi_size = elem_ty.abiSize(self.target.*);
- const index_ty = self.air.typeOf(extra.rhs);
- const index = try self.resolveInst(extra.rhs);
- const index_lock: ?RegisterLock = switch (index) {
- .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
- else => null,
- };
- defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
-
- const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
- const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
- defer self.register_manager.unlockReg(offset_reg_lock);
-
- const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);
- try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
-
- return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none });
+ return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
}
fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
@@ -2953,12 +2940,11 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
const extra_bits = self.regExtraBits(src_ty);
const masked_mcv = if (extra_bits > 0) masked: {
const mask_mcv = MCValue{
- .immediate = ((@as(u64, 1) << @intCast(u6, extra_bits)) - 1) << @intCast(u6, src_bits),
+ .immediate = ((@as(u64, 1) << @intCast(u6, extra_bits)) - 1) <<
+ @intCast(u6, src_bits),
};
const tmp_mcv = tmp: {
- if (src_mcv.isImmediate() or self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) {
- break :tmp src_mcv;
- }
+ if (src_mcv.isImmediate() or self.liveness.operandDies(inst, 0)) break :tmp src_mcv;
try self.genSetReg(src_ty, dst_reg, src_mcv);
break :tmp dst_mcv;
};
From d064cf639f0f05f0f5dda84c228783c37db010b8 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 25 Mar 2023 08:58:00 -0400
Subject: [PATCH 106/216] x86_64: implement 128-bit shifts
---
src/arch/x86_64/CodeGen.zig | 609 +++++++++++++++++++++-------------
src/arch/x86_64/Emit.zig | 95 ++++--
src/arch/x86_64/Encoding.zig | 13 +-
src/arch/x86_64/Mir.zig | 84 +++--
src/arch/x86_64/encoder.zig | 20 +-
src/arch/x86_64/encodings.zig | 14 +
6 files changed, 543 insertions(+), 292 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 2b62854fb9..f010a00551 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -409,10 +409,7 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
_ = try self.addInst(.{
.tag = .setcc,
.ops = .r_cc,
- .data = .{ .r_cc = .{
- .r1 = reg,
- .cc = cc,
- } },
+ .data = .{ .r_cc = .{ .r = reg, .cc = cc } },
});
}
@@ -424,14 +421,11 @@ fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {
.rip => .m_rip_cc,
else => unreachable,
},
- .data = .{ .x_cc = .{
- .payload = switch (m) {
- .sib => try self.addExtra(Mir.MemorySib.encode(m)),
- .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
- else => unreachable,
- },
- .cc = cc,
- } },
+ .data = .{ .x_cc = .{ .cc = cc, .payload = switch (m) {
+ .sib => try self.addExtra(Mir.MemorySib.encode(m)),
+ .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+ else => unreachable,
+ } } },
});
}
@@ -439,11 +433,7 @@ fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bi
_ = try self.addInst(.{
.tag = .cmovcc,
.ops = .rr_cc,
- .data = .{ .rr_cc = .{
- .r1 = reg1,
- .r2 = reg2,
- .cc = cc,
- } },
+ .data = .{ .rr_cc = .{ .r1 = reg1, .r2 = reg2, .cc = cc } },
});
}
@@ -455,15 +445,11 @@ fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condi
.rip => .rm_rip_cc,
else => unreachable,
},
- .data = .{ .rx_cc = .{
- .r1 = reg,
- .cc = cc,
- .payload = switch (m) {
- .sib => try self.addExtra(Mir.MemorySib.encode(m)),
- .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
- else => unreachable,
- },
- } },
+ .data = .{ .rx_cc = .{ .r = reg, .cc = cc, .payload = switch (m) {
+ .sib => try self.addExtra(Mir.MemorySib.encode(m)),
+ .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+ else => unreachable,
+ } } },
});
}
@@ -479,10 +465,7 @@ fn asmJccReloc(self: *Self, target: Mir.Inst.Index, cc: bits.Condition) !Mir.Ins
return self.addInst(.{
.tag = .jcc,
.ops = .inst_cc,
- .data = .{ .inst_cc = .{
- .inst = target,
- .cc = cc,
- } },
+ .data = .{ .inst_cc = .{ .inst = target, .cc = cc } },
});
}
@@ -503,13 +486,15 @@ fn asmRegister(self: *Self, tag: Mir.Inst.Tag, reg: Register) !void {
}
fn asmImmediate(self: *Self, tag: Mir.Inst.Tag, imm: Immediate) !void {
- const ops: Mir.Inst.Ops = if (imm == .signed) .imm_s else .imm_u;
_ = try self.addInst(.{
.tag = tag,
- .ops = ops,
- .data = .{ .imm = switch (imm) {
- .signed => |x| @bitCast(u32, x),
- .unsigned => |x| @intCast(u32, x),
+ .ops = switch (imm) {
+ .signed => .i_s,
+ .unsigned => .i_u,
+ },
+ .data = .{ .i = switch (imm) {
+ .signed => |s| @bitCast(u32, s),
+ .unsigned => |u| @intCast(u32, u),
} },
});
}
@@ -518,37 +503,43 @@ fn asmRegisterRegister(self: *Self, tag: Mir.Inst.Tag, reg1: Register, reg2: Reg
_ = try self.addInst(.{
.tag = tag,
.ops = .rr,
- .data = .{ .rr = .{
- .r1 = reg1,
- .r2 = reg2,
- } },
+ .data = .{ .rr = .{ .r1 = reg1, .r2 = reg2 } },
});
}
fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Immediate) !void {
const ops: Mir.Inst.Ops = switch (imm) {
.signed => .ri_s,
- .unsigned => |x| if (x <= math.maxInt(u32)) .ri_u else .ri64,
- };
- const data: Mir.Inst.Data = switch (ops) {
- .ri_s => .{ .ri = .{
- .r1 = reg,
- .imm = @bitCast(u32, imm.signed),
- } },
- .ri_u => .{ .ri = .{
- .r1 = reg,
- .imm = @intCast(u32, imm.unsigned),
- } },
- .ri64 => .{ .rx = .{
- .r1 = reg,
- .payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)),
- } },
- else => unreachable,
+ .unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64,
};
_ = try self.addInst(.{
.tag = tag,
.ops = ops,
- .data = data,
+ .data = switch (ops) {
+ .ri_s, .ri_u => .{ .ri = .{ .r = reg, .i = switch (imm) {
+ .signed => |s| @bitCast(u32, s),
+ .unsigned => |u| @intCast(u32, u),
+ } } },
+ .ri64 => .{ .rx = .{
+ .r = reg,
+ .payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)),
+ } },
+ else => unreachable,
+ },
+ });
+}
+
+fn asmRegisterRegisterRegister(
+ self: *Self,
+ tag: Mir.Inst.Tag,
+ reg1: Register,
+ reg2: Register,
+ reg3: Register,
+) !void {
+ _ = try self.addInst(.{
+ .tag = tag,
+ .ops = .rrr,
+ .data = .{ .rrr = .{ .r1 = reg1, .r2 = reg2, .r3 = reg3 } },
});
}
@@ -559,109 +550,142 @@ fn asmRegisterRegisterImmediate(
reg2: Register,
imm: Immediate,
) !void {
- const ops: Mir.Inst.Ops = switch (imm) {
- .signed => .rri_s,
- .unsigned => .rri_u,
- };
- const data: Mir.Inst.Data = switch (ops) {
- .rri_s => .{ .rri = .{
- .r1 = reg1,
- .r2 = reg2,
- .imm = @bitCast(u32, imm.signed),
- } },
- .rri_u => .{ .rri = .{
- .r1 = reg1,
- .r2 = reg2,
- .imm = @intCast(u32, imm.unsigned),
- } },
- else => unreachable,
- };
_ = try self.addInst(.{
.tag = tag,
- .ops = ops,
- .data = data,
+ .ops = switch (imm) {
+ .signed => .rri_s,
+ .unsigned => .rri_u,
+ },
+ .data = .{ .rri = .{ .r1 = reg1, .r2 = reg2, .i = switch (imm) {
+ .signed => |s| @bitCast(u32, s),
+ .unsigned => |u| @intCast(u32, u),
+ } } },
});
}
fn asmMemory(self: *Self, tag: Mir.Inst.Tag, m: Memory) !void {
- const ops: Mir.Inst.Ops = switch (m) {
- .sib => .m_sib,
- .rip => .m_rip,
- else => unreachable,
- };
- const data: Mir.Inst.Data = .{ .payload = switch (ops) {
- .m_sib => try self.addExtra(Mir.MemorySib.encode(m)),
- .m_rip => try self.addExtra(Mir.MemoryRip.encode(m)),
- else => unreachable,
- } };
_ = try self.addInst(.{
.tag = tag,
- .ops = ops,
- .data = data,
- });
-}
-
-fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.Tag, m: Memory, imm: Immediate) !void {
- const ops: Mir.Inst.Ops = switch (m) {
- .sib => if (imm == .signed) .mi_s_sib else .mi_u_sib,
- .rip => if (imm == .signed) .mi_s_rip else .mi_u_rip,
- else => unreachable,
- };
- const payload: u32 = switch (ops) {
- .mi_s_sib, .mi_u_sib => try self.addExtra(Mir.MemorySib.encode(m)),
- .mi_s_rip, .mi_u_rip => try self.addExtra(Mir.MemoryRip.encode(m)),
- else => unreachable,
- };
- const data: Mir.Inst.Data = .{
- .xi = .{ .payload = payload, .imm = switch (imm) {
- .signed => |x| @bitCast(u32, x),
- .unsigned => |x| @intCast(u32, x),
+ .ops = switch (m) {
+ .sib => .m_sib,
+ .rip => .m_rip,
+ else => unreachable,
+ },
+ .data = .{ .payload = switch (m) {
+ .sib => try self.addExtra(Mir.MemorySib.encode(m)),
+ .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+ else => unreachable,
} },
- };
- _ = try self.addInst(.{
- .tag = tag,
- .ops = ops,
- .data = data,
});
}
fn asmRegisterMemory(self: *Self, tag: Mir.Inst.Tag, reg: Register, m: Memory) !void {
- const ops: Mir.Inst.Ops = switch (m) {
- .sib => .rm_sib,
- .rip => .rm_rip,
- else => unreachable,
- };
- const data: Mir.Inst.Data = .{
- .rx = .{ .r1 = reg, .payload = switch (ops) {
- .rm_sib => try self.addExtra(Mir.MemorySib.encode(m)),
- .rm_rip => try self.addExtra(Mir.MemoryRip.encode(m)),
- else => unreachable,
- } },
- };
_ = try self.addInst(.{
.tag = tag,
- .ops = ops,
- .data = data,
+ .ops = switch (m) {
+ .sib => .rm_sib,
+ .rip => .rm_rip,
+ else => unreachable,
+ },
+ .data = .{ .rx = .{ .r = reg, .payload = switch (m) {
+ .sib => try self.addExtra(Mir.MemorySib.encode(m)),
+ .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+ else => unreachable,
+ } } },
});
}
fn asmMemoryRegister(self: *Self, tag: Mir.Inst.Tag, m: Memory, reg: Register) !void {
- const ops: Mir.Inst.Ops = switch (m) {
- .sib => .mr_sib,
- .rip => .mr_rip,
- else => unreachable,
- };
- const data: Mir.Inst.Data = .{
- .rx = .{ .r1 = reg, .payload = switch (ops) {
- .mr_sib => try self.addExtra(Mir.MemorySib.encode(m)),
- .mr_rip => try self.addExtra(Mir.MemoryRip.encode(m)),
- else => unreachable,
- } },
- };
_ = try self.addInst(.{
.tag = tag,
- .ops = ops,
- .data = data,
+ .ops = switch (m) {
+ .sib => .mr_sib,
+ .rip => .mr_rip,
+ else => unreachable,
+ },
+ .data = .{ .rx = .{ .r = reg, .payload = switch (m) {
+ .sib => try self.addExtra(Mir.MemorySib.encode(m)),
+ .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+ else => unreachable,
+ } } },
+ });
+}
+
+fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.Tag, m: Memory, imm: Immediate) !void {
+ _ = try self.addInst(.{
+ .tag = tag,
+ .ops = switch (m) {
+ .sib => switch (imm) {
+ .signed => .mi_sib_s,
+ .unsigned => .mi_sib_u,
+ },
+ .rip => switch (imm) {
+ .signed => .mi_rip_s,
+ .unsigned => .mi_rip_u,
+ },
+ else => unreachable,
+ },
+ .data = .{ .ix = .{ .i = switch (imm) {
+ .signed => |s| @bitCast(u32, s),
+ .unsigned => |u| @intCast(u32, u),
+ }, .payload = switch (m) {
+ .sib => try self.addExtra(Mir.MemorySib.encode(m)),
+ .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+ else => unreachable,
+ } } },
+ });
+}
+
+fn asmMemoryRegisterRegister(
+ self: *Self,
+ tag: Mir.Inst.Tag,
+ m: Memory,
+ reg1: Register,
+ reg2: Register,
+) !void {
+ _ = try self.addInst(.{
+ .tag = tag,
+ .ops = switch (m) {
+ .sib => .mrr_sib,
+ .rip => .mrr_rip,
+ else => unreachable,
+ },
+ .data = .{ .rrx = .{ .r1 = reg1, .r2 = reg2, .payload = switch (m) {
+ .sib => try self.addExtra(Mir.MemorySib.encode(m)),
+ .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+ else => unreachable,
+ } } },
+ });
+}
+
+fn asmMemoryRegisterImmediate(
+ self: *Self,
+ tag: Mir.Inst.Tag,
+ m: Memory,
+ reg: Register,
+ imm: Immediate,
+) !void {
+ _ = try self.addInst(.{
+ .tag = tag,
+ .ops = switch (m) {
+ .sib => switch (imm) {
+ .signed => .mri_sib_s,
+ .unsigned => .mri_sib_u,
+ },
+ .rip => switch (imm) {
+ .signed => .mri_rip_s,
+ .unsigned => .mri_sib_u,
+ },
+ else => unreachable,
+ },
+ .data = .{ .rix = .{ .r = reg, .i = switch (imm) {
+ .signed => |s| @bitCast(u32, s),
+ .unsigned => |u| @intCast(u32, u),
+ }, .payload = switch (m) {
+ .sib => try self.addExtra(Mir.MemorySib.encode(m)),
+ .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+ else => unreachable,
+ } } },
});
}
@@ -768,18 +792,12 @@ fn gen(self: *Self) InnerError!void {
self.mir_instructions.set(backpatch_stack_sub, .{
.tag = .sub,
.ops = .ri_u,
- .data = .{ .ri = .{
- .r1 = .rsp,
- .imm = aligned_stack_end,
- } },
+ .data = .{ .ri = .{ .r = .rsp, .i = aligned_stack_end } },
});
self.mir_instructions.set(backpatch_stack_add, .{
.tag = .add,
.ops = .ri_u,
- .data = .{ .ri = .{
- .r1 = .rsp,
- .imm = aligned_stack_end,
- } },
+ .data = .{ .ri = .{ .r = .rsp, .i = aligned_stack_end } },
});
const save_reg_list = try self.addExtra(Mir.SaveRegisterList{
@@ -1732,6 +1750,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
.add_with_overflow => try self.genBinOp(null, .add, bin_op.lhs, bin_op.rhs),
.sub_with_overflow => try self.genBinOp(null, .sub, bin_op.lhs, bin_op.rhs),
.shl_with_overflow => blk: {
+ try self.register_manager.getReg(.rcx, null);
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const shift_ty = self.air.typeOf(bin_op.rhs);
@@ -2022,6 +2041,7 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {
try self.spillRegisters(&.{.rcx});
const tag = self.air.instructions.items(.tag)[inst];
+ try self.register_manager.getReg(.rcx, null);
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const lhs_ty = self.air.typeOf(bin_op.lhs);
@@ -2151,7 +2171,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
if (err_off > 0) {
const shift = @intCast(u6, err_off * 8);
- try self.genShiftBinOpMir(.shr, err_union_ty, result.register, .{ .immediate = shift });
+ try self.genShiftBinOpMir(.shr, err_union_ty, result, .{ .immediate = shift });
} else {
try self.truncateRegister(Type.anyerror, result.register);
}
@@ -2183,9 +2203,7 @@ fn genUnwrapErrorUnionPayloadMir(
const payload_ty = err_union_ty.errorUnionPayload();
const result: MCValue = result: {
- if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
- break :result MCValue.none;
- }
+ if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result .none;
const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
switch (err_union) {
@@ -2198,17 +2216,17 @@ fn genUnwrapErrorUnionPayloadMir(
const eu_lock = self.register_manager.lockReg(reg);
defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
- const result_reg: Register = if (maybe_inst) |inst|
- (try self.copyToRegisterWithInstTracking(inst, err_union_ty, err_union)).register
+ const result_mcv: MCValue = if (maybe_inst) |inst|
+ try self.copyToRegisterWithInstTracking(inst, err_union_ty, err_union)
else
- try self.copyToTmpRegister(err_union_ty, err_union);
+ .{ .register = try self.copyToTmpRegister(err_union_ty, err_union) };
if (payload_off > 0) {
const shift = @intCast(u6, payload_off * 8);
- try self.genShiftBinOpMir(.shr, err_union_ty, result_reg, .{ .immediate = shift });
+ try self.genShiftBinOpMir(.shr, err_union_ty, result_mcv, .{ .immediate = shift });
} else {
- try self.truncateRegister(payload_ty, result_reg);
+ try self.truncateRegister(payload_ty, result_mcv.register);
}
- break :result MCValue{ .register = result_reg };
+ break :result result_mcv;
},
else => return self.fail("TODO implement genUnwrapErrorUnionPayloadMir for {}", .{err_union}),
}
@@ -2848,7 +2866,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
else
0;
const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);
- try self.genShiftBinOpMir(.shr, Type.usize, result.register, .{ .immediate = shift });
+ try self.genShiftBinOpMir(.shr, Type.usize, result, .{ .immediate = shift });
break :blk MCValue{
.register = registerAlias(result.register, @intCast(u32, layout.tag_size)),
};
@@ -3769,12 +3787,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
// Shift by struct_field_offset.
- try self.genShiftBinOpMir(
- .shr,
- Type.usize,
- dst_mcv.register,
- .{ .immediate = field_bit_offset },
- );
+ try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv, .{ .immediate = field_bit_offset });
// Mask to field_bit_size bits
const field_bit_size = field_ty.bitSize(self.target.*);
@@ -3932,29 +3945,186 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
}
/// Clobbers .rcx for non-immediate shift value.
-fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shift: MCValue) !void {
- switch (tag) {
- .sal, .sar, .shl, .shr => {},
- else => unreachable,
- }
-
- const abi_size = @intCast(u32, ty.abiSize(self.target.*));
- blk: {
- switch (shift) {
+fn genShiftBinOpMir(
+ self: *Self,
+ tag: Mir.Inst.Tag,
+ ty: Type,
+ lhs_mcv: MCValue,
+ shift_mcv: MCValue,
+) !void {
+ const rhs_mcv: MCValue = rhs: {
+ switch (shift_mcv) {
.immediate => |imm| switch (imm) {
0 => return,
- else => return self.asmRegisterImmediate(tag, registerAlias(reg, abi_size), Immediate.u(imm)),
- },
- .register => |shift_reg| {
- if (shift_reg == .rcx) break :blk;
+ else => break :rhs shift_mcv,
},
+ .register => |shift_reg| if (shift_reg == .rcx) break :rhs shift_mcv,
else => {},
}
self.register_manager.getRegAssumeFree(.rcx, null);
- try self.genSetReg(Type.u8, .rcx, shift);
- }
+ try self.genSetReg(Type.u8, .rcx, shift_mcv);
+ break :rhs .{ .register = .rcx };
+ };
- try self.asmRegisterRegister(tag, registerAlias(reg, abi_size), .cl);
+ const abi_size = @intCast(u32, ty.abiSize(self.target.*));
+ if (abi_size <= 8) {
+ switch (lhs_mcv) {
+ .register => |lhs_reg| switch (rhs_mcv) {
+ .immediate => |rhs_imm| try self.asmRegisterImmediate(
+ tag,
+ registerAlias(lhs_reg, abi_size),
+ Immediate.u(rhs_imm),
+ ),
+ .register => |rhs_reg| try self.asmRegisterRegister(
+ tag,
+ registerAlias(lhs_reg, abi_size),
+ registerAlias(rhs_reg, 1),
+ ),
+ else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
+ @tagName(lhs_mcv),
+ @tagName(rhs_mcv),
+ }),
+ },
+ .stack_offset => |lhs_off| switch (rhs_mcv) {
+ .immediate => |rhs_imm| try self.asmMemoryImmediate(
+ tag,
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -lhs_off }),
+ Immediate.u(rhs_imm),
+ ),
+ .register => |rhs_reg| try self.asmMemoryRegister(
+ tag,
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -lhs_off }),
+ registerAlias(rhs_reg, 1),
+ ),
+ else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
+ @tagName(lhs_mcv),
+ @tagName(rhs_mcv),
+ }),
+ },
+ else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
+ @tagName(lhs_mcv),
+ @tagName(rhs_mcv),
+ }),
+ }
+ } else if (abi_size <= 16) {
+ const tmp_reg = try self.register_manager.allocReg(null, gp);
+ const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
+ defer self.register_manager.unlockReg(tmp_lock);
+
+ const info: struct { offsets: [2]i32, double_tag: Mir.Inst.Tag } = switch (tag) {
+ .shl, .sal => .{ .offsets = .{ 0, 8 }, .double_tag = .shld },
+ .shr, .sar => .{ .offsets = .{ 8, 0 }, .double_tag = .shrd },
+ else => unreachable,
+ };
+ switch (lhs_mcv) {
+ .stack_offset => |dst_off| switch (rhs_mcv) {
+ .immediate => |rhs_imm| if (rhs_imm == 0) {} else if (rhs_imm < 64) {
+ try self.asmRegisterMemory(
+ .mov,
+ tmp_reg,
+ Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
+ );
+ try self.asmMemoryRegisterImmediate(
+ info.double_tag,
+ Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[1] - dst_off }),
+ tmp_reg,
+ Immediate.u(rhs_imm),
+ );
+ try self.asmMemoryImmediate(
+ tag,
+ Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
+ Immediate.u(rhs_imm),
+ );
+ } else {
+ assert(rhs_imm < 128);
+ try self.asmRegisterMemory(
+ .mov,
+ tmp_reg,
+ Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
+ );
+ if (rhs_imm > 64) {
+ try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(rhs_imm - 64));
+ }
+ try self.asmMemoryRegister(
+ .mov,
+ Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[1] - dst_off }),
+ tmp_reg,
+ );
+ switch (tag) {
+ .shl, .sal, .shr => {
+ try self.asmRegisterRegister(.xor, tmp_reg.to32(), tmp_reg.to32());
+ try self.asmMemoryRegister(
+ .mov,
+ Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
+ tmp_reg,
+ );
+ },
+ .sar => try self.asmMemoryImmediate(
+ tag,
+ Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
+ Immediate.u(63),
+ ),
+ else => unreachable,
+ }
+ },
+ else => {
+ const first_reg = try self.register_manager.allocReg(null, gp);
+ const first_lock = self.register_manager.lockRegAssumeUnused(first_reg);
+ defer self.register_manager.unlockReg(first_lock);
+
+ const second_reg = try self.register_manager.allocReg(null, gp);
+ const second_lock = self.register_manager.lockRegAssumeUnused(second_reg);
+ defer self.register_manager.unlockReg(second_lock);
+
+ try self.genSetReg(Type.u8, .cl, rhs_mcv);
+ try self.asmRegisterMemory(
+ .mov,
+ first_reg,
+ Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
+ );
+ try self.asmRegisterMemory(
+ .mov,
+ second_reg,
+ Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[1] - dst_off }),
+ );
+ switch (tag) {
+ .shl, .sal, .shr => try self.asmRegisterRegister(
+ .xor,
+ tmp_reg.to32(),
+ tmp_reg.to32(),
+ ),
+ .sar => {
+ try self.asmRegisterRegister(.mov, tmp_reg, first_reg);
+ try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(63));
+ },
+ else => unreachable,
+ }
+ try self.asmRegisterRegisterRegister(info.double_tag, second_reg, first_reg, .cl);
+ try self.asmRegisterRegister(tag, first_reg, .cl);
+ try self.asmRegisterImmediate(.cmp, .cl, Immediate.u(64));
+ try self.asmCmovccRegisterRegister(second_reg, first_reg, .ae);
+ try self.asmCmovccRegisterRegister(first_reg, tmp_reg, .ae);
+ try self.asmMemoryRegister(
+ .mov,
+ Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[1] - dst_off }),
+ second_reg,
+ );
+ try self.asmMemoryRegister(
+ .mov,
+ Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
+ first_reg,
+ );
+ },
+ },
+ else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
+ @tagName(lhs_mcv),
+ @tagName(rhs_mcv),
+ }),
+ }
+ } else return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
+ @tagName(lhs_mcv),
+ @tagName(rhs_mcv),
+ });
}
/// Result is always a register.
@@ -3964,68 +4134,61 @@ fn genShiftBinOp(
self: *Self,
tag: Air.Inst.Tag,
maybe_inst: ?Air.Inst.Index,
- lhs: MCValue,
- rhs: MCValue,
+ lhs_mcv: MCValue,
+ rhs_mcv: MCValue,
lhs_ty: Type,
rhs_ty: Type,
) !MCValue {
- if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) {
- return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()});
- }
- if (lhs_ty.abiSize(self.target.*) > 8) {
+ if (lhs_ty.zigTypeTag() == .Vector) {
return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()});
}
assert(rhs_ty.abiSize(self.target.*) == 1);
- const lhs_lock: ?RegisterLock = switch (lhs) {
- .register => |reg| self.register_manager.lockReg(reg),
- else => null,
- };
- defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
-
- const rhs_lock: ?RegisterLock = switch (rhs) {
- .register => |reg| self.register_manager.lockReg(reg),
- else => null,
- };
- defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
+ const lhs_abi_size = lhs_ty.abiSize(self.target.*);
+ if (lhs_abi_size > 16) {
+ return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()});
+ }
self.register_manager.getRegAssumeFree(.rcx, null);
const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
defer self.register_manager.unlockReg(rcx_lock);
- const dst: MCValue = blk: {
+ const lhs_lock = switch (lhs_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ else => null,
+ };
+ defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const rhs_lock = switch (rhs_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ else => null,
+ };
+ defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const dst_mcv: MCValue = dst: {
if (maybe_inst) |inst| {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
- // TODO dst can also be a memory location
- if (self.reuseOperand(inst, bin_op.lhs, 0, lhs) and lhs.isRegister()) {
- break :blk lhs;
- }
- break :blk try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs);
+ if (self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) break :dst lhs_mcv;
}
- break :blk MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) };
+ const dst_mcv = try self.allocRegOrMemAdvanced(lhs_ty, maybe_inst, true);
+ try self.setRegOrMem(lhs_ty, dst_mcv, lhs_mcv);
+ break :dst dst_mcv;
};
const signedness = lhs_ty.intInfo(self.target.*).signedness;
- switch (tag) {
- .shl => try self.genShiftBinOpMir(switch (signedness) {
+ try self.genShiftBinOpMir(switch (tag) {
+ .shl, .shl_exact => switch (signedness) {
.signed => .sal,
.unsigned => .shl,
- }, lhs_ty, dst.register, rhs),
-
- .shl_exact => try self.genShiftBinOpMir(.shl, lhs_ty, dst.register, rhs),
-
- .shr,
- .shr_exact,
- => try self.genShiftBinOpMir(switch (signedness) {
+ },
+ .shr, .shr_exact => switch (signedness) {
.signed => .sar,
.unsigned => .shr,
- }, lhs_ty, dst.register, rhs),
-
+ },
else => unreachable,
- }
-
- return dst;
+ }, lhs_ty, dst_mcv, rhs_mcv);
+ return dst_mcv;
}
/// Result is always a register.
@@ -5552,7 +5715,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !
const tmp_reg = try self.copyToTmpRegister(ty, operand);
if (err_off > 0) {
const shift = @intCast(u6, err_off * 8);
- try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{ .immediate = shift });
+ try self.genShiftBinOpMir(.shr, ty, .{ .register = tmp_reg }, .{ .immediate = shift });
} else {
try self.truncateRegister(Type.anyerror, tmp_reg);
}
@@ -6506,7 +6669,7 @@ fn genInlineMemcpyRegisterRegister(
}), registerAlias(tmp_reg, nearest_power_of_two));
if (nearest_power_of_two > 1) {
- try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{
+ try self.genShiftBinOpMir(.shr, ty, .{ .register = tmp_reg }, .{
.immediate = nearest_power_of_two * 8,
});
}
@@ -7032,7 +7195,7 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
try self.spillEflagsIfOccupied();
_ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
- .r1 = new_reg,
+ .r = new_reg,
.payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
} } });
@@ -7110,7 +7273,7 @@ fn atomicOp(
.xadd, .add, .sub, .@"and", .@"or", .xor => .lock_mr_sib,
else => unreachable,
}, .data = .{ .rx = .{
- .r1 = registerAlias(dst_reg, val_abi_size),
+ .r = registerAlias(dst_reg, val_abi_size),
.payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
} } });
return;
@@ -7702,8 +7865,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
switch (int_info.signedness) {
.signed => {
const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
- try self.genShiftBinOpMir(.sal, Type.isize, reg, .{ .immediate = shift });
- try self.genShiftBinOpMir(.sar, Type.isize, reg, .{ .immediate = shift });
+ try self.genShiftBinOpMir(.sal, Type.isize, .{ .register = reg }, .{ .immediate = shift });
+ try self.genShiftBinOpMir(.sar, Type.isize, .{ .register = reg }, .{ .immediate = shift });
},
.unsigned => {
const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index cd8389aa49..b4218f48a9 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -121,7 +121,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.sbb,
.sfence,
.shl,
+ .shld,
.shr,
+ .shrd,
.sub,
.syscall,
.@"test",
@@ -231,10 +233,10 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
const prefix: Instruction.Prefix = switch (ops) {
.lock_m_sib,
.lock_m_rip,
- .lock_mi_u_sib,
- .lock_mi_u_rip,
- .lock_mi_s_sib,
- .lock_mi_s_rip,
+ .lock_mi_sib_u,
+ .lock_mi_rip_u,
+ .lock_mi_sib_s,
+ .lock_mi_rip_s,
.lock_mr_sib,
.lock_mr_rip,
.lock_moffs_rax,
@@ -249,31 +251,36 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
switch (ops) {
.none => {},
- .imm_s => op1 = .{ .imm = Immediate.s(@bitCast(i32, data.imm)) },
- .imm_u => op1 = .{ .imm = Immediate.u(data.imm) },
+ .i_s => op1 = .{ .imm = Immediate.s(@bitCast(i32, data.i)) },
+ .i_u => op1 = .{ .imm = Immediate.u(data.i) },
.r => op1 = .{ .reg = data.r },
.rr => {
op1 = .{ .reg = data.rr.r1 };
op2 = .{ .reg = data.rr.r2 };
},
+ .rrr => {
+ op1 = .{ .reg = data.rrr.r1 };
+ op2 = .{ .reg = data.rrr.r2 };
+ op3 = .{ .reg = data.rrr.r3 };
+ },
.ri_s, .ri_u => {
const imm = switch (ops) {
- .ri_s => Immediate.s(@bitCast(i32, data.ri.imm)),
- .ri_u => Immediate.u(data.ri.imm),
+ .ri_s => Immediate.s(@bitCast(i32, data.ri.i)),
+ .ri_u => Immediate.u(data.ri.i),
else => unreachable,
};
- op1 = .{ .reg = data.ri.r1 };
+ op1 = .{ .reg = data.ri.r };
op2 = .{ .imm = imm };
},
.ri64 => {
const imm64 = emit.mir.extraData(Mir.Imm64, data.rx.payload).data;
- op1 = .{ .reg = data.rx.r1 };
+ op1 = .{ .reg = data.rx.r };
op2 = .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) };
},
.rri_s, .rri_u => {
const imm = switch (ops) {
- .rri_s => Immediate.s(@bitCast(i32, data.rri.imm)),
- .rri_u => Immediate.u(data.rri.imm),
+ .rri_s => Immediate.s(@bitCast(i32, data.rri.i)),
+ .rri_u => Immediate.u(data.rri.i),
else => unreachable,
};
op1 = .{ .reg = data.rri.r1 };
@@ -288,21 +295,21 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
const mrip = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
},
- .mi_s_sib, .mi_u_sib, .lock_mi_s_sib, .lock_mi_u_sib => {
- const msib = emit.mir.extraData(Mir.MemorySib, data.xi.payload).data;
+ .mi_sib_s, .mi_sib_u, .lock_mi_sib_s, .lock_mi_sib_u => {
+ const msib = emit.mir.extraData(Mir.MemorySib, data.ix.payload).data;
const imm = switch (ops) {
- .mi_s_sib, .lock_mi_s_sib => Immediate.s(@bitCast(i32, data.xi.imm)),
- .mi_u_sib, .lock_mi_u_sib => Immediate.u(data.xi.imm),
+ .mi_sib_s, .lock_mi_sib_s => Immediate.s(@bitCast(i32, data.ix.i)),
+ .mi_sib_u, .lock_mi_sib_u => Immediate.u(data.ix.i),
else => unreachable,
};
op1 = .{ .mem = Mir.MemorySib.decode(msib) };
op2 = .{ .imm = imm };
},
- .mi_u_rip, .mi_s_rip, .lock_mi_u_rip, .lock_mi_s_rip => {
- const mrip = emit.mir.extraData(Mir.MemoryRip, data.xi.payload).data;
+ .mi_rip_u, .mi_rip_s, .lock_mi_rip_u, .lock_mi_rip_s => {
+ const mrip = emit.mir.extraData(Mir.MemoryRip, data.ix.payload).data;
const imm = switch (ops) {
- .mi_s_rip, .lock_mi_s_rip => Immediate.s(@bitCast(i32, data.xi.imm)),
- .mi_u_rip, .lock_mi_u_rip => Immediate.u(data.xi.imm),
+ .mi_rip_s, .lock_mi_rip_s => Immediate.s(@bitCast(i32, data.ix.i)),
+ .mi_rip_u, .lock_mi_rip_u => Immediate.u(data.ix.i),
else => unreachable,
};
op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
@@ -310,7 +317,7 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
},
.rm_sib, .mr_sib, .lock_mr_sib => {
const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data;
- const op_r = .{ .reg = data.rx.r1 };
+ const op_r = .{ .reg = data.rx.r };
const op_m = .{ .mem = Mir.MemorySib.decode(msib) };
switch (ops) {
.rm_sib => {
@@ -326,7 +333,7 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
},
.rm_rip, .mr_rip, .lock_mr_rip => {
const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data;
- const op_r = .{ .reg = data.rx.r1 };
+ const op_r = .{ .reg = data.rx.r };
const op_m = .{ .mem = Mir.MemoryRip.decode(mrip) };
switch (ops) {
.rm_rip => {
@@ -340,6 +347,40 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
else => unreachable,
}
},
+ .mrr_sib => {
+ const msib = emit.mir.extraData(Mir.MemorySib, data.rrx.payload).data;
+ op1 = .{ .mem = Mir.MemorySib.decode(msib) };
+ op2 = .{ .reg = data.rrx.r1 };
+ op2 = .{ .reg = data.rrx.r2 };
+ },
+ .mrr_rip => {
+ const mrip = emit.mir.extraData(Mir.MemoryRip, data.rrx.payload).data;
+ op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
+ op2 = .{ .reg = data.rrx.r1 };
+ op2 = .{ .reg = data.rrx.r2 };
+ },
+ .mri_sib_u, .mri_sib_s => {
+ const msib = emit.mir.extraData(Mir.MemorySib, data.rix.payload).data;
+ const imm = switch (ops) {
+ .mri_sib_s => Immediate.s(@bitCast(i32, data.rix.i)),
+ .mri_sib_u, .lock_mi_rip_u => Immediate.u(data.rix.i),
+ else => unreachable,
+ };
+ op1 = .{ .mem = Mir.MemorySib.decode(msib) };
+ op2 = .{ .reg = data.rix.r };
+ op3 = .{ .imm = imm };
+ },
+ .mri_rip_u, .mri_rip_s => {
+ const mrip = emit.mir.extraData(Mir.MemoryRip, data.rix.payload).data;
+ const imm = switch (ops) {
+ .mri_rip_s => Immediate.s(@bitCast(i32, data.rix.i)),
+ .mri_rip_u, .lock_mi_rip_u => Immediate.u(data.rix.i),
+ else => unreachable,
+ };
+ op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
+ op2 = .{ .reg = data.rix.r };
+ op3 = .{ .imm = imm };
+ },
else => return emit.fail("TODO handle generic encoding: {s}, {s}", .{
@tagName(mnemonic),
@tagName(ops),
@@ -451,12 +492,12 @@ fn mirMovsx(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
},
.rm_sib => {
const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data;
- op1 = .{ .reg = data.rx.r1 };
+ op1 = .{ .reg = data.rx.r };
op2 = .{ .mem = Mir.MemorySib.decode(msib) };
},
.rm_rip => {
const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data;
- op1 = .{ .reg = data.rx.r1 };
+ op1 = .{ .reg = data.rx.r };
op2 = .{ .mem = Mir.MemoryRip.decode(mrip) };
},
else => unreachable, // TODO
@@ -495,7 +536,7 @@ fn mirCmovcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
const extra = emit.mir.extraData(Mir.MemorySib, data.payload).data;
const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
return emit.encode(mnemonic, .{
- .op1 = .{ .reg = data.r1 },
+ .op1 = .{ .reg = data.r },
.op2 = .{ .mem = Mir.MemorySib.decode(extra) },
});
},
@@ -504,7 +545,7 @@ fn mirCmovcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
const extra = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
return emit.encode(mnemonic, .{
- .op1 = .{ .reg = data.r1 },
+ .op1 = .{ .reg = data.r },
.op2 = .{ .mem = Mir.MemoryRip.decode(extra) },
});
},
@@ -519,7 +560,7 @@ fn mirSetcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
const data = emit.mir.instructions.items(.data)[inst].r_cc;
const mnemonic = mnemonicFromConditionCode("set", data.cc);
return emit.encode(mnemonic, .{
- .op1 = .{ .reg = data.r1 },
+ .op1 = .{ .reg = data.r },
});
},
.m_sib_cc => {
diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig
index 891fc4e9a1..de669a9f8d 100644
--- a/src/arch/x86_64/Encoding.zig
+++ b/src/arch/x86_64/Encoding.zig
@@ -262,15 +262,15 @@ pub fn format(
try writer.print("+{s} ", .{tag});
},
.m, .mi, .m1, .mc => try writer.print("/{d} ", .{encoding.modRmExt()}),
- .mr, .rm, .rmi => try writer.writeAll("/r "),
+ .mr, .rm, .rmi, .mri, .mrc => try writer.writeAll("/r "),
}
switch (encoding.op_en) {
- .i, .d, .zi, .oi, .mi, .rmi => {
+ .i, .d, .zi, .oi, .mi, .rmi, .mri => {
const op = switch (encoding.op_en) {
.i, .d => encoding.op1,
.zi, .oi, .mi => encoding.op2,
- .rmi => encoding.op3,
+ .rmi, .mri => encoding.op3,
else => unreachable,
};
const tag = switch (op) {
@@ -285,7 +285,7 @@ pub fn format(
};
try writer.print("{s} ", .{tag});
},
- .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm => {},
+ .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc => {},
}
try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
@@ -334,7 +334,7 @@ pub const Mnemonic = enum {
rcl, rcr, ret, rol, ror,
sal, sar, sbb,
scas, scasb, scasd, scasq, scasw,
- shl, shr, sub, syscall,
+ shl, shld, shr, shrd, sub, syscall,
seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,
setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,
setnz, seto, setp, setpe, setpo, sets, setz,
@@ -374,7 +374,8 @@ pub const OpEn = enum {
i, zi,
d, m,
fd, td,
- m1, mc, mi, mr, rm, rmi,
+ m1, mc, mi, mr, rm,
+ rmi, mri, mrc,
// zig fmt: on
};
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index 59c292c500..9b2fa2e969 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -138,8 +138,12 @@ pub const Inst = struct {
sfence,
/// Logical shift left
shl,
+ /// Double precision shift left
+ shld,
/// Logical shift right
shr,
+ /// Double precision shift right
+ shrd,
/// Subtract
sub,
/// Syscall
@@ -284,10 +288,10 @@ pub const Inst = struct {
ri64,
/// Immediate (sign-extended) operand.
/// Uses `imm` payload.
- imm_s,
+ i_s,
/// Immediate (unsigned) operand.
/// Uses `imm` payload.
- imm_u,
+ i_u,
/// Relative displacement operand.
/// Uses `imm` payload.
rel,
@@ -316,23 +320,41 @@ pub const Inst = struct {
/// Uses `x_cc` with extra data of type `MemoryRip`.
m_rip_cc,
/// Memory (SIB), immediate (unsigned) operands.
- /// Uses `xi` payload with extra data of type `MemorySib`.
- mi_u_sib,
+ /// Uses `ix` payload with extra data of type `MemorySib`.
+ mi_sib_u,
/// Memory (RIP), immediate (unsigned) operands.
- /// Uses `xi` payload with extra data of type `MemoryRip`.
- mi_u_rip,
+ /// Uses `ix` payload with extra data of type `MemoryRip`.
+ mi_rip_u,
/// Memory (SIB), immediate (sign-extend) operands.
- /// Uses `xi` payload with extra data of type `MemorySib`.
- mi_s_sib,
+ /// Uses `ix` payload with extra data of type `MemorySib`.
+ mi_sib_s,
/// Memory (RIP), immediate (sign-extend) operands.
- /// Uses `xi` payload with extra data of type `MemoryRip`.
- mi_s_rip,
+ /// Uses `ix` payload with extra data of type `MemoryRip`.
+ mi_rip_s,
/// Memory (SIB), register operands.
/// Uses `rx` payload with extra data of type `MemorySib`.
mr_sib,
/// Memory (RIP), register operands.
/// Uses `rx` payload with extra data of type `MemoryRip`.
mr_rip,
+ /// Memory (SIB), register, register operands.
+ /// Uses `rrx` payload with extra data of type `MemorySib`.
+ mrr_sib,
+ /// Memory (RIP), register, register operands.
+ /// Uses `rrx` payload with extra data of type `MemoryRip`.
+ mrr_rip,
+ /// Memory (SIB), register, immediate (unsigned) operands.
+ /// Uses `rix` payload with extra data of type `MemorySib`.
+ mri_sib_u,
+ /// Memory (RIP), register, immediate (unsigned) operands.
+ /// Uses `rix` payload with extra data of type `MemoryRip`.
+ mri_rip_u,
+ /// Memory (SIB), register, immediate (signed) operands.
+ /// Uses `rix` payload with extra data of type `MemorySib`.
+ mri_sib_s,
+ /// Memory (RIP), register, immediate (signed) operands.
+ /// Uses `rix` payload with extra data of type `MemoryRip`.
+ mri_rip_s,
/// Rax, Memory moffs.
/// Uses `payload` with extra data of type `MemoryMoffs`.
rax_moffs,
@@ -347,16 +369,16 @@ pub const Inst = struct {
lock_m_rip,
/// Memory (SIB), immediate (unsigned) operands with lock prefix.
/// Uses `xi` payload with extra data of type `MemorySib`.
- lock_mi_u_sib,
+ lock_mi_sib_u,
/// Memory (RIP), immediate (unsigned) operands with lock prefix.
/// Uses `xi` payload with extra data of type `MemoryRip`.
- lock_mi_u_rip,
+ lock_mi_rip_u,
/// Memory (SIB), immediate (sign-extend) operands with lock prefix.
/// Uses `xi` payload with extra data of type `MemorySib`.
- lock_mi_s_sib,
+ lock_mi_sib_s,
/// Memory (RIP), immediate (sign-extend) operands with lock prefix.
/// Uses `xi` payload with extra data of type `MemoryRip`.
- lock_mi_s_rip,
+ lock_mi_rip_s,
/// Memory (SIB), register operands with lock prefix.
/// Uses `rx` payload with extra data of type `MemorySib`.
lock_mr_sib,
@@ -400,7 +422,7 @@ pub const Inst = struct {
cc: bits.Condition,
},
/// A 32-bit immediate value.
- imm: u32,
+ i: u32,
r: Register,
rr: struct {
r1: Register,
@@ -414,16 +436,16 @@ pub const Inst = struct {
rri: struct {
r1: Register,
r2: Register,
- imm: u32,
+ i: u32,
},
/// Condition code (CC), followed by custom payload found in extra.
x_cc: struct {
- payload: u32,
cc: bits.Condition,
+ payload: u32,
},
/// Register with condition code (CC).
r_cc: struct {
- r1: Register,
+ r: Register,
cc: bits.Condition,
},
/// Register, register with condition code (CC).
@@ -434,24 +456,36 @@ pub const Inst = struct {
},
/// Register, immediate.
ri: struct {
- r1: Register,
- imm: u32,
+ r: Register,
+ i: u32,
},
/// Register, followed by custom payload found in extra.
rx: struct {
- r1: Register,
+ r: Register,
payload: u32,
},
/// Register with condition code (CC), followed by custom payload found in extra.
rx_cc: struct {
- r1: Register,
+ r: Register,
cc: bits.Condition,
payload: u32,
},
- /// Custom payload followed by an immediate.
- xi: struct {
+ /// Immediate, followed by Custom payload found in extra.
+ ix: struct {
+ i: u32,
+ payload: u32,
+ },
+ /// Register, register, followed by Custom payload found in extra.
+ rrx: struct {
+ r1: Register,
+ r2: Register,
+ payload: u32,
+ },
+ /// Register, immediate, followed by Custom payload found in extra.
+ rix: struct {
+ r: Register,
+ i: u32,
payload: u32,
- imm: u32,
},
/// String instruction prefix and width.
string: struct {
diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig
index 9206923ece..05f66062ac 100644
--- a/src/arch/x86_64/encoder.zig
+++ b/src/arch/x86_64/encoder.zig
@@ -174,7 +174,7 @@ pub const Instruction = struct {
.td => try encoder.imm64(inst.op1.mem.moffs.offset),
else => {
const mem_op = switch (encoding.op_en) {
- .m, .mi, .m1, .mc, .mr => inst.op1,
+ .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.op1,
.rm, .rmi => inst.op2,
else => unreachable,
};
@@ -182,7 +182,7 @@ pub const Instruction = struct {
.reg => |reg| {
const rm = switch (encoding.op_en) {
.m, .mi, .m1, .mc => encoding.modRmExt(),
- .mr => inst.op2.reg.lowEnc(),
+ .mr, .mri, .mrc => inst.op2.reg.lowEnc(),
.rm, .rmi => inst.op1.reg.lowEnc(),
else => unreachable,
};
@@ -191,7 +191,7 @@ pub const Instruction = struct {
.mem => |mem| {
const op = switch (encoding.op_en) {
.m, .mi, .m1, .mc => .none,
- .mr => inst.op2,
+ .mr, .mri, .mrc => inst.op2,
.rm, .rmi => inst.op1,
else => unreachable,
};
@@ -202,7 +202,7 @@ pub const Instruction = struct {
switch (encoding.op_en) {
.mi => try encodeImm(inst.op2.imm, encoding.op2, encoder),
- .rmi => try encodeImm(inst.op3.imm, encoding.op3, encoder),
+ .rmi, .mri => try encodeImm(inst.op3.imm, encoding.op3, encoder),
else => {},
}
},
@@ -251,7 +251,7 @@ pub const Instruction = struct {
else => unreachable,
};
} else null,
- .m, .mi, .m1, .mc, .mr => if (inst.op1.isSegmentRegister()) blk: {
+ .m, .mi, .m1, .mc, .mr, .mri, .mrc => if (inst.op1.isSegmentRegister()) blk: {
break :blk switch (inst.op1) {
.reg => |r| r,
.mem => |m| m.base().?,
@@ -275,13 +275,11 @@ pub const Instruction = struct {
switch (op_en) {
.np, .i, .zi, .fd, .td, .d => {},
- .o, .oi => {
- rex.b = inst.op1.reg.isExtended();
- },
- .m, .mi, .m1, .mc, .mr, .rm, .rmi => {
+ .o, .oi => rex.b = inst.op1.reg.isExtended(),
+ .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc => {
const r_op = switch (op_en) {
.rm, .rmi => inst.op1,
- .mr => inst.op2,
+ .mr, .mri, .mrc => inst.op2,
else => null,
};
if (r_op) |op| {
@@ -290,7 +288,7 @@ pub const Instruction = struct {
const b_x_op = switch (op_en) {
.rm, .rmi => inst.op2,
- .m, .mi, .m1, .mc, .mr => inst.op1,
+ .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.op1,
else => unreachable,
};
switch (b_x_op) {
diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig
index 23a125789b..d0ded0136b 100644
--- a/src/arch/x86_64/encodings.zig
+++ b/src/arch/x86_64/encodings.zig
@@ -693,6 +693,13 @@ pub const table = &[_]Entry{
.{ .shl, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },
.{ .shl, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 4, .long },
+ .{ .shld, .mri, .rm16, .r16, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .none },
+ .{ .shld, .mrc, .rm16, .r16, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .none },
+ .{ .shld, .mri, .rm32, .r32, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .none },
+ .{ .shld, .mri, .rm64, .r64, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .long },
+ .{ .shld, .mrc, .rm32, .r32, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .none },
+ .{ .shld, .mrc, .rm64, .r64, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .long },
+
.{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .none },
.{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .rex },
.{ .shr, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 5, .none },
@@ -709,6 +716,13 @@ pub const table = &[_]Entry{
.{ .shr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 5, .none },
.{ .shr, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 5, .long },
+ .{ .shrd, .mri, .rm16, .r16, .imm8, .none, &.{ 0x0f, 0xac }, 0, .none },
+ .{ .shrd, .mrc, .rm16, .r16, .cl, .none, &.{ 0x0f, 0xad }, 0, .none },
+ .{ .shrd, .mri, .rm32, .r32, .imm8, .none, &.{ 0x0f, 0xac }, 0, .none },
+ .{ .shrd, .mri, .rm64, .r64, .imm8, .none, &.{ 0x0f, 0xac }, 0, .long },
+ .{ .shrd, .mrc, .rm32, .r32, .cl, .none, &.{ 0x0f, 0xad }, 0, .none },
+ .{ .shrd, .mrc, .rm64, .r64, .cl, .none, &.{ 0x0f, 0xad }, 0, .long },
+
.{ .stos, .np, .m8, .none, .none, .none, &.{ 0xaa }, 0, .none },
.{ .stos, .np, .m16, .none, .none, .none, &.{ 0xab }, 0, .none },
.{ .stos, .np, .m32, .none, .none, .none, &.{ 0xab }, 0, .none },
From a2f6e068b0082692f2c5475c1e31290b9c016010 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 25 Mar 2023 11:00:26 -0400
Subject: [PATCH 107/216] x86_64: implement 128-bit intcast
---
src/arch/x86_64/CodeGen.zig | 125 +++++++++++++++++++++++++-----------
1 file changed, 86 insertions(+), 39 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index f010a00551..3c64f15ef1 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -1410,38 +1410,80 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- if (self.liveness.isUnused(inst))
- return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
-
- const operand_ty = self.air.typeOf(ty_op.operand);
- const operand = try self.resolveInst(ty_op.operand);
- const info_a = operand_ty.intInfo(self.target.*);
- const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*);
-
- const operand_abi_size = operand_ty.abiSize(self.target.*);
- const dest_ty = self.air.typeOfIndex(inst);
- const dest_abi_size = dest_ty.abiSize(self.target.*);
- const dst_mcv: MCValue = blk: {
- if (info_a.bits == info_b.bits) {
- break :blk operand;
- }
- if (operand_abi_size > 8 or dest_abi_size > 8) {
- return self.fail("TODO implement intCast for abi sizes larger than 8", .{});
- }
-
- const operand_lock: ?RegisterLock = switch (operand) {
+ const result = if (self.liveness.isUnused(inst)) .dead else result: {
+ const src_ty = self.air.typeOf(ty_op.operand);
+ const src_int_info = src_ty.intInfo(self.target.*);
+ const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
+ const src_mcv = try self.resolveInst(ty_op.operand);
+ const src_lock = switch (src_mcv) {
.register => |reg| self.register_manager.lockRegAssumeUnused(reg),
else => null,
};
- defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
+ defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
- const reg = try self.register_manager.allocReg(inst, gp);
- try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });
- try self.genSetReg(operand_ty, reg, operand);
- break :blk MCValue{ .register = reg };
+ const dst_ty = self.air.typeOfIndex(inst);
+ const dst_int_info = dst_ty.intInfo(self.target.*);
+ const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
+ const dst_mcv = if (dst_abi_size <= src_abi_size and
+ self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ src_mcv
+ else
+ try self.allocRegOrMem(inst, true);
+
+ const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty;
+ const signedness: std.builtin.Signedness = if (dst_int_info.signedness == .signed and
+ src_int_info.signedness == .signed) .signed else .unsigned;
+ switch (dst_mcv) {
+ .register => |dst_reg| {
+ const min_abi_size = @min(dst_abi_size, src_abi_size);
+ const tag: Mir.Inst.Tag = switch (signedness) {
+ .signed => .movsx,
+ .unsigned => if (min_abi_size == 4) .mov else .movzx,
+ };
+ const dst_alias = switch (tag) {
+ .movsx => dst_reg.to64(),
+ .mov, .movzx => if (min_abi_size > 4) dst_reg.to64() else dst_reg.to32(),
+ else => unreachable,
+ };
+ switch (src_mcv) {
+ .register => |src_reg| {
+ try self.asmRegisterRegister(
+ tag,
+ dst_alias,
+ registerAlias(src_reg, min_abi_size),
+ );
+ },
+ .stack_offset => |src_off| {
+ try self.asmRegisterMemory(tag, dst_alias, Memory.sib(
+ Memory.PtrSize.fromSize(min_abi_size),
+ .{ .base = .rbp, .disp = -src_off },
+ ));
+ },
+ else => return self.fail("TODO airIntCast from {s} to {s}", .{
+ @tagName(src_mcv),
+ @tagName(dst_mcv),
+ }),
+ }
+ if (self.regExtraBits(min_ty) > 0) try self.truncateRegister(min_ty, dst_reg);
+ },
+ else => {
+ try self.setRegOrMem(min_ty, dst_mcv, src_mcv);
+ const extra = dst_abi_size * 8 - dst_int_info.bits;
+ if (extra > 0) {
+ try self.genShiftBinOpMir(switch (signedness) {
+ .signed => .sal,
+ .unsigned => .shl,
+ }, dst_ty, dst_mcv, .{ .immediate = extra });
+ try self.genShiftBinOpMir(switch (signedness) {
+ .signed => .sar,
+ .unsigned => .shr,
+ }, dst_ty, dst_mcv, .{ .immediate = extra });
+ }
+ },
+ }
+ break :result dst_mcv;
};
-
- return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
+ return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
@@ -6555,20 +6597,25 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
.disp = -stack_offset,
}), immediate);
},
- 8 => {
+ 3, 5...7 => unreachable,
+ else => {
// 64 bit write to memory would take two mov's anyways so we
// insted just use two 32 bit writes to avoid register allocation
- try self.asmMemoryImmediate(.mov, Memory.sib(.dword, .{
- .base = base_reg,
- .disp = -stack_offset + 4,
- }), Immediate.u(@truncate(u32, x_big >> 32)));
- try self.asmMemoryImmediate(.mov, Memory.sib(.dword, .{
- .base = base_reg,
- .disp = -stack_offset,
- }), Immediate.u(@truncate(u32, x_big)));
- },
- else => {
- return self.fail("TODO implement set abi_size=large stack variable with immediate", .{});
+ var offset: i32 = 0;
+ while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate(
+ .mov,
+ Memory.sib(.dword, .{ .base = base_reg, .disp = offset - stack_offset }),
+ if (ty.isSignedInt())
+ Immediate.s(@truncate(
+ i32,
+ @bitCast(i64, x_big) >> (math.cast(u6, offset * 8) orelse 63),
+ ))
+ else
+ Immediate.u(@truncate(
+ u32,
+ if (math.cast(u6, offset * 8)) |shift| x_big >> shift else 0,
+ )),
+ );
},
}
},
From 6d9bdc8733419ebfc9527d114b637c57d3fd8a42 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 25 Mar 2023 11:00:42 -0400
Subject: [PATCH 108/216] x86_64: fix cmpxchg
---
src/arch/x86_64/CodeGen.zig | 2 +-
src/arch/x86_64/encodings.zig | 4 ++--
test/behavior/atomics.zig | 4 ----
3 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 3c64f15ef1..c7326ef3b0 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -7242,7 +7242,7 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
try self.spillEflagsIfOccupied();
_ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
- .r = new_reg,
+ .r = registerAlias(new_reg, val_abi_size),
.payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
} } });
diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig
index d0ded0136b..9683ef991a 100644
--- a/src/arch/x86_64/encodings.zig
+++ b/src/arch/x86_64/encodings.zig
@@ -257,8 +257,8 @@ pub const table = &[_]Entry{
.{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .none },
.{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .rex },
- .{ .cmpxchg, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb1 }, 0, .rex },
- .{ .cmpxchg, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb1 }, 0, .rex },
+ .{ .cmpxchg, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb1 }, 0, .none },
+ .{ .cmpxchg, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb1 }, 0, .none },
.{ .cmpxchg, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb1 }, 0, .long },
.{ .cmpxchg8b , .m, .m64, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .none },
diff --git a/test/behavior/atomics.zig b/test/behavior/atomics.zig
index a1e3af6e9a..e6000cd848 100644
--- a/test/behavior/atomics.zig
+++ b/test/behavior/atomics.zig
@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
test "cmpxchg" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_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
@@ -96,7 +95,6 @@ test "cmpxchg with ptr" {
test "cmpxchg with ignored result" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_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
@@ -143,7 +141,6 @@ var a_global_variable = @as(u32, 1234);
test "cmpxchg on a global variable" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_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
@@ -384,7 +381,6 @@ fn testAtomicRmwInt128(comptime signedness: std.builtin.Signedness) !void {
test "atomics with different types" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_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
From 1e080e505617b8a7961971630c059592f7366223 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 25 Mar 2023 13:44:50 -0400
Subject: [PATCH 109/216] x86_64: implement atomic loops
---
src/arch/x86_64/CodeGen.zig | 295 ++++++++++++++----
src/arch/x86_64/bits.zig | 23 +-
test/behavior/array.zig | 2 -
test/behavior/bugs/10684.zig | 1 -
test/behavior/bugs/12051.zig | 1 -
test/behavior/bugs/12092.zig | 1 -
test/behavior/bugs/12142.zig | 1 -
test/behavior/bugs/6456.zig | 1 -
test/behavior/bugs/8646.zig | 1 -
test/behavior/empty_tuple_fields.zig | 2 -
test/behavior/lower_strlit_to_vector.zig | 1 -
test/behavior/math.zig | 1 -
test/behavior/optional.zig | 1 -
test/behavior/packed-struct.zig | 2 -
.../packed_struct_explicit_backing_int.zig | 1 -
test/behavior/pointers.zig | 2 -
test/behavior/slice.zig | 3 -
test/behavior/struct.zig | 1 -
test/behavior/switch.zig | 1 -
test/behavior/threadlocal.zig | 1 -
test/behavior/translate_c_macros.zig | 8 -
test/behavior/tuple.zig | 1 -
test/behavior/tuple_declarations.zig | 2 -
test/behavior/type.zig | 2 -
test/behavior/type_info.zig | 1 -
test/behavior/typename.zig | 2 -
test/behavior/vector.zig | 1 -
27 files changed, 249 insertions(+), 110 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index c7326ef3b0..f6ccedb91d 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -1438,7 +1438,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
const min_abi_size = @min(dst_abi_size, src_abi_size);
const tag: Mir.Inst.Tag = switch (signedness) {
.signed => .movsx,
- .unsigned => if (min_abi_size == 4) .mov else .movzx,
+ .unsigned => if (min_abi_size > 2) .mov else .movzx,
};
const dst_alias = switch (tag) {
.movsx => dst_reg.to64(),
@@ -3889,10 +3889,10 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
const src_ty = self.air.typeOf(src_air);
const src_mcv = try self.resolveInst(src_air);
if (src_ty.zigTypeTag() == .Vector) {
- return self.fail("TODO implement genBinOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
+ return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
}
if (src_ty.abiSize(self.target.*) > 8) {
- return self.fail("TODO implement genBinOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
+ return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
}
switch (src_mcv) {
@@ -4192,7 +4192,7 @@ fn genShiftBinOp(
return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()});
}
- self.register_manager.getRegAssumeFree(.rcx, null);
+ try self.register_manager.getReg(.rcx, null);
const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
defer self.register_manager.unlockReg(rcx_lock);
@@ -4717,7 +4717,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
);
}
},
- else => return self.fail("TODO getBinOpMir implement large immediate ABI", .{}),
+ else => return self.fail("TODO genBinOpMir implement large immediate ABI", .{}),
}
},
.memory,
@@ -4798,28 +4798,28 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
);
}
},
- else => return self.fail("TODO getBinOpMir implement large immediate ABI", .{}),
+ else => return self.fail("TODO genBinOpMir implement large immediate ABI", .{}),
}
},
.memory,
.stack_offset,
.ptr_stack_offset,
=> {
- return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});
+ return self.fail("TODO implement x86 genBinOpMir source memory", .{});
},
.linker_load => {
- return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});
+ return self.fail("TODO implement x86 genBinOpMir source symbol at index in linker", .{});
},
.eflags => {
- return self.fail("TODO implement x86 ADD/SUB/CMP source eflags", .{});
+ return self.fail("TODO implement x86 genBinOpMir source eflags", .{});
},
}
},
.memory => {
- return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{});
+ return self.fail("TODO implement x86 genBinOpMir destination memory", .{});
},
.linker_load => {
- return self.fail("TODO implement x86 ADD/SUB/CMP destination symbol at index", .{});
+ return self.fail("TODO implement x86 genBinOpMir destination symbol at index", .{});
},
}
}
@@ -7219,20 +7219,37 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
const ptr_ty = self.air.typeOf(extra.ptr);
const ptr_mcv = try self.resolveInst(extra.ptr);
const val_ty = self.air.typeOf(extra.expected_value);
+ const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
+
+ try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx });
+ const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx });
+ for (regs_lock) |lock| self.register_manager.unlockReg(lock);
const exp_mcv = try self.resolveInst(extra.expected_value);
- try self.genSetReg(val_ty, .rax, exp_mcv);
+ if (val_abi_size > 8) switch (exp_mcv) {
+ .stack_offset => |exp_off| {
+ try self.genSetReg(Type.usize, .rax, .{ .stack_offset = exp_off - 0 });
+ try self.genSetReg(Type.usize, .rdx, .{ .stack_offset = exp_off - 8 });
+ },
+ else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}),
+ } else try self.genSetReg(val_ty, .rax, exp_mcv);
const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);
defer self.register_manager.unlockReg(rax_lock);
const new_mcv = try self.resolveInst(extra.new_value);
- const new_reg = try self.copyToTmpRegister(val_ty, new_mcv);
+ const new_reg: Register = if (val_abi_size > 8) switch (new_mcv) {
+ .stack_offset => |new_off| new: {
+ try self.genSetReg(Type.usize, .rbx, .{ .stack_offset = new_off - 0 });
+ try self.genSetReg(Type.usize, .rcx, .{ .stack_offset = new_off - 8 });
+ break :new undefined;
+ },
+ else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}),
+ } else try self.copyToTmpRegister(val_ty, new_mcv);
const new_lock = self.register_manager.lockRegAssumeUnused(new_reg);
defer self.register_manager.unlockReg(new_lock);
- const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
- const ptr_mem: Memory = switch (ptr_mcv) {
+ const ptr_mem = switch (ptr_mcv) {
.register => |reg| Memory.sib(ptr_size, .{ .base = reg }),
.ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),
else => Memory.sib(ptr_size, .{ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }),
@@ -7241,16 +7258,30 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
try self.spillEflagsIfOccupied();
- _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
- .r = registerAlias(new_reg, val_abi_size),
- .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
- } } });
+ if (val_abi_size <= 8) {
+ _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
+ .r = registerAlias(new_reg, val_abi_size),
+ .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
+ } } });
+ } else {
+ _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{
+ .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
+ } });
+ }
const result: MCValue = result: {
if (self.liveness.isUnused(inst)) break :result .dead;
- self.eflags_inst = inst;
- break :result .{ .register_overflow = .{ .reg = .rax, .eflags = .ne } };
+ if (val_abi_size <= 8) {
+ self.eflags_inst = inst;
+ break :result .{ .register_overflow = .{ .reg = .rax, .eflags = .ne } };
+ }
+
+ const dst_mcv = try self.allocRegOrMem(inst, false);
+ try self.genSetStack(Type.bool, dst_mcv.stack_offset - 16, .{ .eflags = .ne }, .{});
+ try self.genSetStack(Type.usize, dst_mcv.stack_offset - 8, .{ .register = .rdx }, .{});
+ try self.genSetStack(Type.usize, dst_mcv.stack_offset - 0, .{ .register = .rax }, .{});
+ break :result dst_mcv;
};
return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
}
@@ -7263,9 +7294,10 @@ fn atomicOp(
ptr_ty: Type,
val_ty: Type,
unused: bool,
- op: ?std.builtin.AtomicRmwOp,
+ rmw_op: ?std.builtin.AtomicRmwOp,
order: std.builtin.AtomicOrder,
) InnerError!void {
+ const dst_mcv = MCValue{ .register = dst_reg };
const dst_lock = self.register_manager.lockReg(dst_reg);
defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
@@ -7283,7 +7315,7 @@ fn atomicOp(
const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
- const ptr_mem: Memory = switch (ptr_mcv) {
+ const ptr_mem = switch (ptr_mcv) {
.register => |reg| Memory.sib(ptr_size, .{ .base = reg }),
.ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),
else => Memory.sib(ptr_size, .{ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }),
@@ -7291,48 +7323,197 @@ fn atomicOp(
const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null;
defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
- try self.genSetReg(val_ty, dst_reg, val_mcv);
+ const method: enum { lock, loop, libcall } = if (val_ty.isRuntimeFloat())
+ .loop
+ else switch (rmw_op orelse .Xchg) {
+ .Xchg,
+ .Add,
+ .Sub,
+ => if (val_abi_size <= 8) .lock else if (val_abi_size <= 16) .loop else .libcall,
+ .And,
+ .Or,
+ .Xor,
+ => if (val_abi_size <= 8 and unused) .lock else if (val_abi_size <= 16) .loop else .libcall,
+ .Nand,
+ .Max,
+ .Min,
+ => if (val_abi_size <= 16) .loop else .libcall,
+ };
+ switch (method) {
+ .lock => {
+ const tag: Mir.Inst.Tag = if (rmw_op) |op| switch (op) {
+ .Xchg => if (unused) .mov else .xchg,
+ .Add => if (unused) .add else .xadd,
+ .Sub => if (unused) .sub else .xadd,
+ .And => .@"and",
+ .Or => .@"or",
+ .Xor => .xor,
+ else => unreachable,
+ } else switch (order) {
+ .Unordered, .Monotonic, .Release, .AcqRel => .mov,
+ .Acquire => unreachable,
+ .SeqCst => .xchg,
+ };
- const need_loop = val_ty.isRuntimeFloat() or if (op) |rmw| switch (rmw) {
- .Xchg, .Add, .Sub => false,
- .And, .Or, .Xor => !unused,
- .Nand, .Max, .Min => true,
- } else false;
- if (!need_loop) {
- const tag: Mir.Inst.Tag = if (op) |rmw| switch (rmw) {
- .Xchg => if (unused) .mov else .xchg,
- .Add => if (unused) .add else .xadd,
- .Sub => if (unused) .sub else .xadd,
- .And => .@"and",
- .Or => .@"or",
- .Xor => .xor,
- else => unreachable,
- } else switch (order) {
- .Unordered, .Monotonic, .Release, .AcqRel => .mov,
- .Acquire => unreachable,
- .SeqCst => .xchg,
- };
- if (op == std.builtin.AtomicRmwOp.Sub and tag == .xadd) {
- try self.genUnOpMir(.neg, val_ty, .{ .register = dst_reg });
- }
- _ = try self.addInst(.{ .tag = tag, .ops = switch (tag) {
- .mov, .xchg => .mr_sib,
- .xadd, .add, .sub, .@"and", .@"or", .xor => .lock_mr_sib,
- else => unreachable,
- }, .data = .{ .rx = .{
- .r = registerAlias(dst_reg, val_abi_size),
- .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
- } } });
- return;
+ try self.genSetReg(val_ty, dst_reg, val_mcv);
+ if (rmw_op == std.builtin.AtomicRmwOp.Sub and tag == .xadd) {
+ try self.genUnOpMir(.neg, val_ty, .{ .register = dst_reg });
+ }
+ _ = try self.addInst(.{ .tag = tag, .ops = switch (tag) {
+ .mov, .xchg => .mr_sib,
+ .xadd, .add, .sub, .@"and", .@"or", .xor => .lock_mr_sib,
+ else => unreachable,
+ }, .data = .{ .rx = .{
+ .r = registerAlias(dst_reg, val_abi_size),
+ .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
+ } } });
+ },
+ .loop => _ = try self.asmJccReloc(if (val_abi_size <= 8) loop: {
+ try self.genSetReg(val_ty, dst_reg, val_mcv);
+ try self.asmRegisterMemory(.mov, registerAlias(.rax, val_abi_size), ptr_mem);
+ const loop = @intCast(u32, self.mir_instructions.len);
+ if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
+ try self.genSetReg(val_ty, dst_reg, .{ .register = .rax });
+ }
+ if (rmw_op) |op| switch (op) {
+ .Xchg => try self.genSetReg(val_ty, dst_reg, val_mcv),
+ .Add => try self.genBinOpMir(.add, val_ty, dst_mcv, val_mcv),
+ .Sub => try self.genBinOpMir(.sub, val_ty, dst_mcv, val_mcv),
+ .And => try self.genBinOpMir(.@"and", val_ty, dst_mcv, val_mcv),
+ .Nand => {
+ try self.genBinOpMir(.@"and", val_ty, dst_mcv, val_mcv);
+ try self.genUnOpMir(.not, val_ty, dst_mcv);
+ },
+ .Or => try self.genBinOpMir(.@"or", val_ty, dst_mcv, val_mcv),
+ .Xor => try self.genBinOpMir(.xor, val_ty, dst_mcv, val_mcv),
+ .Min, .Max => {
+ const cc: Condition = switch (if (val_ty.isAbiInt())
+ val_ty.intInfo(self.target.*).signedness
+ else
+ .unsigned) {
+ .unsigned => switch (op) {
+ .Min => .a,
+ .Max => .b,
+ else => unreachable,
+ },
+ .signed => switch (op) {
+ .Min => .g,
+ .Max => .l,
+ else => unreachable,
+ },
+ };
+
+ try self.genBinOpMir(.cmp, val_ty, dst_mcv, val_mcv);
+ switch (val_mcv) {
+ .register => |val_reg| try self.asmCmovccRegisterRegister(
+ registerAlias(dst_reg, val_abi_size),
+ registerAlias(val_reg, val_abi_size),
+ cc,
+ ),
+ .stack_offset => |val_off| try self.asmCmovccRegisterMemory(
+ registerAlias(dst_reg, val_abi_size),
+ Memory.sib(
+ Memory.PtrSize.fromSize(val_abi_size),
+ .{ .base = .rbp, .disp = -val_off },
+ ),
+ cc,
+ ),
+ else => {
+ const val_reg = try self.copyToTmpRegister(val_ty, val_mcv);
+ try self.asmCmovccRegisterRegister(
+ registerAlias(dst_reg, val_abi_size),
+ registerAlias(val_reg, val_abi_size),
+ cc,
+ );
+ },
+ }
+ },
+ };
+ _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
+ .r = registerAlias(dst_reg, val_abi_size),
+ .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
+ } } });
+ break :loop loop;
+ } else loop: {
+ try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{
+ .base = ptr_mem.sib.base,
+ .scale_index = ptr_mem.sib.scale_index,
+ .disp = ptr_mem.sib.disp + 0,
+ }));
+ try self.asmRegisterMemory(.mov, .rdx, Memory.sib(.qword, .{
+ .base = ptr_mem.sib.base,
+ .scale_index = ptr_mem.sib.scale_index,
+ .disp = ptr_mem.sib.disp + 8,
+ }));
+ const loop = @intCast(u32, self.mir_instructions.len);
+ switch (val_mcv) {
+ .stack_offset => |val_off| {
+ const val_lo_mem = Memory.sib(.qword, .{ .base = .rbp, .disp = 0 - val_off });
+ const val_hi_mem = Memory.sib(.qword, .{ .base = .rbp, .disp = 8 - val_off });
+
+ if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
+ try self.asmRegisterRegister(.mov, .rbx, .rax);
+ try self.asmRegisterRegister(.mov, .rcx, .rdx);
+ }
+ if (rmw_op) |op| switch (op) {
+ .Xchg => {
+ try self.asmRegisterMemory(.mov, .rbx, val_lo_mem);
+ try self.asmRegisterMemory(.mov, .rcx, val_hi_mem);
+ },
+ .Add => {
+ try self.asmRegisterMemory(.add, .rbx, val_lo_mem);
+ try self.asmRegisterMemory(.adc, .rcx, val_hi_mem);
+ },
+ .Sub => {
+ try self.asmRegisterMemory(.sub, .rbx, val_lo_mem);
+ try self.asmRegisterMemory(.sbb, .rcx, val_hi_mem);
+ },
+ .And => {
+ try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
+ try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
+ },
+ .Nand => {
+ try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
+ try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
+ try self.asmRegister(.not, .rbx);
+ try self.asmRegister(.not, .rcx);
+ },
+ .Or => {
+ try self.asmRegisterMemory(.@"or", .rbx, val_lo_mem);
+ try self.asmRegisterMemory(.@"or", .rcx, val_hi_mem);
+ },
+ .Xor => {
+ try self.asmRegisterMemory(.xor, .rbx, val_lo_mem);
+ try self.asmRegisterMemory(.xor, .rcx, val_hi_mem);
+ },
+ else => return self.fail(
+ "TODO implement x86 atomic loop for large abi {s}",
+ .{@tagName(op)},
+ ),
+ };
+ },
+ else => return self.fail(
+ "TODO implement x86 atomic loop for large abi {s}",
+ .{@tagName(val_mcv)},
+ ),
+ }
+ _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{
+ .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
+ } });
+ break :loop loop;
+ }, .ne),
+ .libcall => return self.fail("TODO implement x86 atomic libcall", .{}),
}
-
- return self.fail("TODO implement x86 atomic loop", .{});
}
fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data;
+ try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx });
+ const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx });
+ defer for (regs_lock) |lock| self.register_manager.unlockReg(lock);
+
const unused = self.liveness.isUnused(inst);
const dst_reg = try self.register_manager.allocReg(if (unused) null else inst, gp);
diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig
index c10bfe4039..76ad26a9a0 100644
--- a/src/arch/x86_64/bits.zig
+++ b/src/arch/x86_64/bits.zig
@@ -411,20 +411,17 @@ pub const Memory = union(enum) {
dword,
qword,
tbyte,
+ dqword,
pub fn fromSize(size: u32) PtrSize {
- return if (size <= 1)
- .byte
- else if (size <= 2)
- .word
- else if (size <= 4)
- .dword
- else if (size <= 8)
- .qword
- else if (size == 10)
- .tbyte
- else
- unreachable;
+ return switch (size) {
+ 1...1 => .byte,
+ 2...2 => .word,
+ 3...4 => .dword,
+ 5...8 => .qword,
+ 9...16 => .dqword,
+ else => unreachable,
+ };
}
pub fn fromBitSize(bit_size: u64) PtrSize {
@@ -434,6 +431,7 @@ pub const Memory = union(enum) {
32 => .dword,
64 => .qword,
80 => .tbyte,
+ 128 => .dqword,
else => unreachable,
};
}
@@ -445,6 +443,7 @@ pub const Memory = union(enum) {
.dword => 32,
.qword => 64,
.tbyte => 80,
+ .dqword => 128,
};
}
};
diff --git a/test/behavior/array.zig b/test/behavior/array.zig
index 96b1be1778..b2d9816c18 100644
--- a/test/behavior/array.zig
+++ b/test/behavior/array.zig
@@ -70,7 +70,6 @@ test "array concat with undefined" {
test "array concat with tuple" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const array: [2]u8 = .{ 1, 2 };
{
@@ -641,7 +640,6 @@ test "tuple to array handles sentinel" {
}
test "array init of container level array variable" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/bugs/10684.zig b/test/behavior/bugs/10684.zig
index 8b0bd6ebca..ef104a3f0c 100644
--- a/test/behavior/bugs/10684.zig
+++ b/test/behavior/bugs/10684.zig
@@ -4,7 +4,6 @@ const expectEqualStrings = std.testing.expectEqualStrings;
test "slicing slices" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
diff --git a/test/behavior/bugs/12051.zig b/test/behavior/bugs/12051.zig
index efbfc88404..5e2087d422 100644
--- a/test/behavior/bugs/12051.zig
+++ b/test/behavior/bugs/12051.zig
@@ -3,7 +3,6 @@ const builtin = @import("builtin");
test {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
diff --git a/test/behavior/bugs/12092.zig b/test/behavior/bugs/12092.zig
index 3a7b9766a3..216138d748 100644
--- a/test/behavior/bugs/12092.zig
+++ b/test/behavior/bugs/12092.zig
@@ -15,7 +15,6 @@ fn takeFoo(foo: *const Foo) !void {
test {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
diff --git a/test/behavior/bugs/12142.zig b/test/behavior/bugs/12142.zig
index db303d617a..1efbd0dbb4 100644
--- a/test/behavior/bugs/12142.zig
+++ b/test/behavior/bugs/12142.zig
@@ -20,7 +20,6 @@ fn letter(e: Letter) u8 {
test {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
diff --git a/test/behavior/bugs/6456.zig b/test/behavior/bugs/6456.zig
index 03c687232f..3dbec7bc70 100644
--- a/test/behavior/bugs/6456.zig
+++ b/test/behavior/bugs/6456.zig
@@ -11,7 +11,6 @@ const text =
;
test "issue 6456" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
diff --git a/test/behavior/bugs/8646.zig b/test/behavior/bugs/8646.zig
index 2e181a682e..da9359a60a 100644
--- a/test/behavior/bugs/8646.zig
+++ b/test/behavior/bugs/8646.zig
@@ -8,7 +8,6 @@ const array = [_][]const []const u8{
test {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
diff --git a/test/behavior/empty_tuple_fields.zig b/test/behavior/empty_tuple_fields.zig
index 7309dc9b3e..9f1d4dee1a 100644
--- a/test/behavior/empty_tuple_fields.zig
+++ b/test/behavior/empty_tuple_fields.zig
@@ -3,7 +3,6 @@ const builtin = @import("builtin");
test "empty file level struct" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const T = @import("empty_file_level_struct.zig");
@@ -15,7 +14,6 @@ test "empty file level struct" {
test "empty file level union" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const T = @import("empty_file_level_union.zig");
diff --git a/test/behavior/lower_strlit_to_vector.zig b/test/behavior/lower_strlit_to_vector.zig
index 427379636e..948d708aa7 100644
--- a/test/behavior/lower_strlit_to_vector.zig
+++ b/test/behavior/lower_strlit_to_vector.zig
@@ -2,7 +2,6 @@ const std = @import("std");
const builtin = @import("builtin");
test "strlit to vector" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/math.zig b/test/behavior/math.zig
index d7b8e4764b..9e3c2b02fd 100644
--- a/test/behavior/math.zig
+++ b/test/behavior/math.zig
@@ -560,7 +560,6 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {
test "negation wrapping" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
try expectEqual(@as(u1, 1), negateWrap(u1, 1));
}
diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig
index 95b39f2170..9fb0a617a3 100644
--- a/test/behavior/optional.zig
+++ b/test/behavior/optional.zig
@@ -431,7 +431,6 @@ test "alignment of wrapping an optional payload" {
test "Optional slice size is optimized" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
try expect(@sizeOf(?[]u8) == @sizeOf([]u8));
diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig
index 6cc021dd1a..a7dfd46064 100644
--- a/test/behavior/packed-struct.zig
+++ b/test/behavior/packed-struct.zig
@@ -120,7 +120,6 @@ test "consistent size of packed structs" {
}
test "correct sizeOf and offsets in packed structs" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -188,7 +187,6 @@ test "correct sizeOf and offsets in packed structs" {
}
test "nested packed structs" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/packed_struct_explicit_backing_int.zig b/test/behavior/packed_struct_explicit_backing_int.zig
index b5d6ed24fb..fab43816da 100644
--- a/test/behavior/packed_struct_explicit_backing_int.zig
+++ b/test/behavior/packed_struct_explicit_backing_int.zig
@@ -6,7 +6,6 @@ const native_endian = builtin.cpu.arch.endian();
test "packed struct explicit backing integer" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig
index e5ccfec543..0532212559 100644
--- a/test/behavior/pointers.zig
+++ b/test/behavior/pointers.zig
@@ -412,7 +412,6 @@ test "@ptrToInt on null optional at comptime" {
test "indexing array with sentinel returns correct type" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
var s: [:0]const u8 = "abc";
@@ -497,7 +496,6 @@ test "pointer to constant decl preserves alignment" {
test "ptrCast comptime known slice to C pointer" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const s: [:0]const u8 = "foo";
diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig
index 2a0944a5b6..029f6838d0 100644
--- a/test/behavior/slice.zig
+++ b/test/behavior/slice.zig
@@ -688,7 +688,6 @@ test "slice field ptr var" {
test "global slice field access" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const S = struct {
@@ -733,7 +732,6 @@ test "empty slice ptr is non null" {
test "slice decays to many pointer" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
var buf: [8]u8 = "abcdefg\x00".*;
const p: [*:0]const u8 = buf[0..7 :0];
@@ -744,7 +742,6 @@ test "write through pointer to optional slice arg" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const S = struct {
fn bar(foo: *?[]const u8) !void {
diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig
index 61318ad6d2..b59615f01a 100644
--- a/test/behavior/struct.zig
+++ b/test/behavior/struct.zig
@@ -935,7 +935,6 @@ test "comptime struct field" {
}
test "tuple element initialized with fn call" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig
index 132cef5c1e..52f5b79723 100644
--- a/test/behavior/switch.zig
+++ b/test/behavior/switch.zig
@@ -620,7 +620,6 @@ test "switch on error set with single else" {
}
test "switch capture copies its payload" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/threadlocal.zig b/test/behavior/threadlocal.zig
index 1f1bc6bea4..f025e99ee7 100644
--- a/test/behavior/threadlocal.zig
+++ b/test/behavior/threadlocal.zig
@@ -21,7 +21,6 @@ test "thread local variable" {
test "pointer to thread local array" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) {
diff --git a/test/behavior/translate_c_macros.zig b/test/behavior/translate_c_macros.zig
index 6d8d4eca6d..bc19cddc22 100644
--- a/test/behavior/translate_c_macros.zig
+++ b/test/behavior/translate_c_macros.zig
@@ -23,7 +23,6 @@ test "casting to void with a macro" {
}
test "initializer list expression" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -52,7 +51,6 @@ test "reference to a struct type" {
test "cast negative integer to pointer" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -98,7 +96,6 @@ test "casting or calling a value with a paren-surrounded macro" {
test "nested comma operator" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -109,7 +106,6 @@ test "nested comma operator" {
test "cast functions" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -123,7 +119,6 @@ test "cast functions" {
test "large integer macro" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -133,7 +128,6 @@ test "large integer macro" {
test "string literal macro with embedded tab character" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -143,7 +137,6 @@ test "string literal macro with embedded tab character" {
test "string and char literals that are not UTF-8 encoded. Issue #12784" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -188,7 +181,6 @@ test "Macro that uses division operator. Issue #13162" {
test "Macro that uses remainder operator. Issue #13346" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig
index 3f557bc40e..1cf68a0769 100644
--- a/test/behavior/tuple.zig
+++ b/test/behavior/tuple.zig
@@ -381,7 +381,6 @@ test "tuple of struct concatenation and coercion to array" {
test "nested runtime conditionals in tuple initializer" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
var data: u8 = 0;
const x = .{
diff --git a/test/behavior/tuple_declarations.zig b/test/behavior/tuple_declarations.zig
index 87d4997c8b..74ee7da1dd 100644
--- a/test/behavior/tuple_declarations.zig
+++ b/test/behavior/tuple_declarations.zig
@@ -7,7 +7,6 @@ const expectEqualStrings = testing.expectEqualStrings;
test "tuple declaration type info" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
{
const T = struct { comptime u32 align(2) = 1, []const u8 };
@@ -57,7 +56,6 @@ test "tuple declaration type info" {
test "Tuple declaration usage" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const T = struct { u32, []const u8 };
var t: T = .{ 1, "foo" };
diff --git a/test/behavior/type.zig b/test/behavior/type.zig
index 7f44f350d1..a12949fffd 100644
--- a/test/behavior/type.zig
+++ b/test/behavior/type.zig
@@ -200,7 +200,6 @@ test "Type.ErrorUnion" {
test "Type.Opaque" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -348,7 +347,6 @@ test "Type.Struct" {
}
test "Type.Enum" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig
index 495c1f3195..5a1ab7c2aa 100644
--- a/test/behavior/type_info.zig
+++ b/test/behavior/type_info.zig
@@ -568,7 +568,6 @@ test "value from struct @typeInfo default_value can be loaded at comptime" {
test "@typeInfo decls and usingnamespace" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const A = struct {
const x = 5;
diff --git a/test/behavior/typename.zig b/test/behavior/typename.zig
index 92dc428903..e8327a1981 100644
--- a/test/behavior/typename.zig
+++ b/test/behavior/typename.zig
@@ -64,7 +64,6 @@ test "anon field init" {
}
test "basic" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -228,7 +227,6 @@ test "local variable" {
}
test "comptime parameters not converted to anytype in function type" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig
index 562e9aba20..3b716692ef 100644
--- a/test/behavior/vector.zig
+++ b/test/behavior/vector.zig
@@ -1267,7 +1267,6 @@ test "store to vector in slice" {
test "addition of vectors represented as strings" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const V = @Vector(3, u8);
const foo: V = "foo".*;
From d29c674d0dfab215e230a3d31eddf7ca164491a0 Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 25 Mar 2023 16:04:30 -0400
Subject: [PATCH 110/216] x86_64: implement teb inline assembly for windows
---
src/arch/x86_64/CodeGen.zig | 140 +++++++++++++++++++++++-------------
1 file changed, 92 insertions(+), 48 deletions(-)
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index f6ccedb91d..a2c5b291bf 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -6265,13 +6265,23 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
extra_i += inputs.len;
- const dead = !is_volatile and self.liveness.isUnused(inst);
- const result: MCValue = if (dead) .dead else result: {
+ var result: MCValue = .none;
+ if (!is_volatile and self.liveness.isUnused(inst)) result = .dead else {
+ var args = std.StringArrayHashMap(MCValue).init(self.gpa);
+ try args.ensureTotalCapacity(outputs.len + inputs.len + clobbers_len);
+ defer {
+ for (args.values()) |arg| switch (arg) {
+ .register => |reg| self.register_manager.unlockReg(.{ .register = reg }),
+ else => {},
+ };
+ args.deinit();
+ }
+
if (outputs.len > 1) {
return self.fail("TODO implement codegen for asm with more than 1 output", .{});
}
- const output_constraint: ?[]const u8 = for (outputs) |output| {
+ for (outputs) |output| {
if (output != .none) {
return self.fail("TODO implement codegen for non-expr asm", .{});
}
@@ -6282,8 +6292,21 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
// for the string, we still use the next u32 for the null terminator.
extra_i += (constraint.len + name.len + (2 + 3)) / 4;
- break constraint;
- } else null;
+ const mcv: MCValue = if (mem.eql(u8, constraint, "=r"))
+ .{ .register = self.register_manager.tryAllocReg(inst, gp) orelse
+ return self.fail("ran out of registers lowering inline asm", .{}) }
+ else if (mem.startsWith(u8, constraint, "={") and mem.endsWith(u8, constraint, "}"))
+ .{ .register = parseRegName(constraint["={".len .. constraint.len - "}".len]) orelse
+ return self.fail("unrecognized register constraint: '{s}'", .{constraint}) }
+ else
+ return self.fail("unrecognized constraint: '{s}'", .{constraint});
+ args.putAssumeCapacity(name, mcv);
+ switch (mcv) {
+ .register => |reg| _ = self.register_manager.lockRegAssumeUnused(reg),
+ else => {},
+ }
+ if (output == .none) result = mcv;
+ }
for (inputs) |input| {
const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
@@ -6317,52 +6340,73 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
}
}
- const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
-
- {
- var iter = std.mem.tokenize(u8, asm_source, "\n\r");
- while (iter.next()) |ins| {
- if (mem.eql(u8, ins, "syscall")) {
- try self.asmOpOnly(.syscall);
- } else if (mem.indexOf(u8, ins, "push")) |_| {
- const arg = ins[4..];
- if (mem.indexOf(u8, arg, "$")) |l| {
- const n = std.fmt.parseInt(u8, ins[4 + l + 1 ..], 10) catch {
- return self.fail("TODO implement more inline asm int parsing", .{});
- };
- try self.asmImmediate(.push, Immediate.u(n));
- } else if (mem.indexOf(u8, arg, "%%")) |l| {
- const reg_name = ins[4 + l + 2 ..];
- const reg = parseRegName(reg_name) orelse
- return self.fail("unrecognized register: '{s}'", .{reg_name});
- try self.asmRegister(.push, reg);
- } else return self.fail("TODO more push operands", .{});
- } else if (mem.indexOf(u8, ins, "pop")) |_| {
- const arg = ins[3..];
- if (mem.indexOf(u8, arg, "%%")) |l| {
- const reg_name = ins[3 + l + 2 ..];
- const reg = parseRegName(reg_name) orelse
- return self.fail("unrecognized register: '{s}'", .{reg_name});
- try self.asmRegister(.pop, reg);
- } else return self.fail("TODO more pop operands", .{});
- } else {
- return self.fail("TODO implement support for more x86 assembly instructions", .{});
+ const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
+ var line_it = mem.tokenize(u8, asm_source, "\n\r");
+ while (line_it.next()) |line| {
+ var mnem_it = mem.tokenize(u8, line, " \t");
+ const mnem = mnem_it.next() orelse continue;
+ if (mem.startsWith(u8, mnem, "#")) continue;
+ var arg_it = mem.tokenize(u8, mnem_it.rest(), ", ");
+ if (std.ascii.eqlIgnoreCase(mnem, "syscall")) {
+ if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
+ return self.fail("Too many operands: '{s}'", .{line});
+ try self.asmOpOnly(.syscall);
+ } else if (std.ascii.eqlIgnoreCase(mnem, "push")) {
+ const src = arg_it.next() orelse
+ return self.fail("Not enough operands: '{s}'", .{line});
+ if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
+ return self.fail("Too many operands: '{s}'", .{line});
+ if (mem.startsWith(u8, src, "$")) {
+ const imm = std.fmt.parseInt(u32, src["$".len..], 0) catch
+ return self.fail("Invalid immediate: '{s}'", .{src});
+ try self.asmImmediate(.push, Immediate.u(imm));
+ } else if (mem.startsWith(u8, src, "%%")) {
+ const reg = parseRegName(src["%%".len..]) orelse
+ return self.fail("Invalid register: '{s}'", .{src});
+ try self.asmRegister(.push, reg);
+ } else return self.fail("Unsupported operand: '{s}'", .{src});
+ } else if (std.ascii.eqlIgnoreCase(mnem, "pop")) {
+ const dst = arg_it.next() orelse
+ return self.fail("Not enough operands: '{s}'", .{line});
+ if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
+ return self.fail("Too many operands: '{s}'", .{line});
+ if (mem.startsWith(u8, dst, "%%")) {
+ const reg = parseRegName(dst["%%".len..]) orelse
+ return self.fail("Invalid register: '{s}'", .{dst});
+ try self.asmRegister(.pop, reg);
+ } else return self.fail("Unsupported operand: '{s}'", .{dst});
+ } else if (std.ascii.eqlIgnoreCase(mnem, "movq")) {
+ const src = arg_it.next() orelse
+ return self.fail("Not enough operands: '{s}'", .{line});
+ const dst = arg_it.next() orelse
+ return self.fail("Not enough operands: '{s}'", .{line});
+ if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
+ return self.fail("Too many operands: '{s}'", .{line});
+ if (mem.startsWith(u8, src, "%%")) {
+ const colon = mem.indexOfScalarPos(u8, src, "%%".len + 2, ':');
+ const src_reg = parseRegName(src["%%".len .. colon orelse src.len]) orelse
+ return self.fail("Invalid register: '{s}'", .{src});
+ if (colon) |colon_pos| {
+ const src_disp = std.fmt.parseInt(i32, src[colon_pos + 1 ..], 0) catch
+ return self.fail("Invalid immediate: '{s}'", .{src});
+ if (mem.startsWith(u8, dst, "%[") and mem.endsWith(u8, dst, "]")) {
+ switch (args.get(dst["%[".len .. dst.len - "]".len]) orelse
+ return self.fail("no matching constraint for: '{s}'", .{dst})) {
+ .register => |dst_reg| try self.asmRegisterMemory(
+ .mov,
+ dst_reg,
+ Memory.sib(.qword, .{ .base = src_reg, .disp = src_disp }),
+ ),
+ else => return self.fail("Invalid constraint: '{s}'", .{dst}),
+ }
+ } else return self.fail("Unsupported operand: '{s}'", .{dst});
+ } else return self.fail("Unsupported operand: '{s}'", .{src});
}
+ } else {
+ return self.fail("Unsupported instruction: '{s}'", .{mnem});
}
}
-
- if (output_constraint) |output| {
- if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {
- return self.fail("unrecognized asm output constraint: '{s}'", .{output});
- }
- const reg_name = output[2 .. output.len - 1];
- const reg = parseRegName(reg_name) orelse
- return self.fail("unrecognized register: '{s}'", .{reg_name});
- break :result .{ .register = reg };
- } else {
- break :result .none;
- }
- };
+ }
simple: {
var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);
From a80be15cd494dbd25874db8ef63c1cbbcdfc732a Mon Sep 17 00:00:00 2001
From: Jacob Young
Date: Sat, 25 Mar 2023 16:21:00 -0400
Subject: [PATCH 111/216] behavior: disable multi threaded for the
stage2_x86_64 windows target
See #15075 for more details.
---
test/tests.zig | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/tests.zig b/test/tests.zig
index 26e684cd0d..517d789b18 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -112,6 +112,7 @@ const test_targets = blk: {
.os_tag = .windows,
.abi = .gnu,
},
+ .single_threaded = true, // https://github.com/ziglang/zig/issues/15075
.backend = .stage2_x86_64,
},
From 113f80bcf793b2841635d136e561bcc0bbe89086 Mon Sep 17 00:00:00 2001
From: kcbanner
Date: Thu, 2 Mar 2023 22:15:31 -0500
Subject: [PATCH 112/216] coff: change dynamicbase to default to true (to match
lld), change it to pass the negation to lld, and add --no-dynamicbase build:
expose linker_dynamicbase on CompileStep and map it to emit --no-dynamicbase
---
lib/std/Build/CompileStep.zig | 5 +++++
src/link/Coff/lld.zig | 4 ++--
src/main.zig | 8 +++++---
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/lib/std/Build/CompileStep.zig b/lib/std/Build/CompileStep.zig
index 2747f56af2..96fd9deb9c 100644
--- a/lib/std/Build/CompileStep.zig
+++ b/lib/std/Build/CompileStep.zig
@@ -140,6 +140,8 @@ link_function_sections: bool = false,
/// exported symbols.
link_gc_sections: ?bool = null,
+linker_dynamicbase: ?bool = null,
+
linker_allow_shlib_undefined: ?bool = null,
/// Permit read-only relocations in read-only segments. Disallowed by default.
@@ -1474,6 +1476,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
if (self.link_gc_sections) |x| {
try zig_args.append(if (x) "--gc-sections" else "--no-gc-sections");
}
+ if (self.linker_dynamicbase) |x| {
+ if (!x) try zig_args.append("--no-dynamicbase");
+ }
if (self.linker_allow_shlib_undefined) |x| {
try zig_args.append(if (x) "-fallow-shlib-undefined" else "-fno-allow-shlib-undefined");
}
diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig
index c308ff5989..358c905b2c 100644
--- a/src/link/Coff/lld.zig
+++ b/src/link/Coff/lld.zig
@@ -223,8 +223,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
if (self.base.options.nxcompat) {
try argv.append("-nxcompat");
}
- if (self.base.options.dynamicbase) {
- try argv.append("-dynamicbase");
+ if (!self.base.options.dynamicbase) {
+ try argv.append("-dynamicbase:NO");
}
try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path}));
diff --git a/src/main.zig b/src/main.zig
index 961d649d38..479c7e518c 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -778,7 +778,7 @@ fn buildOutputType(
var linker_z_max_page_size: ?u64 = null;
var linker_tsaware = false;
var linker_nxcompat = false;
- var linker_dynamicbase = false;
+ var linker_dynamicbase = true;
var linker_optimization: ?u8 = null;
var linker_module_definition_file: ?[]const u8 = null;
var test_evented_io = false;
@@ -1371,6 +1371,8 @@ fn buildOutputType(
linker_opt_bisect_limit = std.math.lossyCast(i32, parseIntSuffix(arg, "-fopt-bisect-limit=".len));
} else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
link_eh_frame_hdr = true;
+ } else if (mem.eql(u8, arg, "--no-dynamicbase")) {
+ linker_dynamicbase = false;
} else if (mem.eql(u8, arg, "--emit-relocs")) {
link_emit_relocs = true;
} else if (mem.eql(u8, arg, "-fallow-shlib-undefined")) {
@@ -2105,8 +2107,8 @@ fn buildOutputType(
linker_tsaware = true;
} else if (mem.eql(u8, arg, "--nxcompat")) {
linker_nxcompat = true;
- } else if (mem.eql(u8, arg, "--dynamicbase")) {
- linker_dynamicbase = true;
+ } else if (mem.eql(u8, arg, "--no-dynamicbase")) {
+ linker_dynamicbase = false;
} else if (mem.eql(u8, arg, "--high-entropy-va")) {
// This option does not do anything.
} else if (mem.eql(u8, arg, "--export-all-symbols")) {
From c79073c176a909abce3feba96203caef1e6d8360 Mon Sep 17 00:00:00 2001
From: kcbanner
Date: Thu, 2 Mar 2023 22:54:35 -0500
Subject: [PATCH 113/216] compilation: fixup linker_dynamicbase default in
InitOptions
---
src/Compilation.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 858afb6ca3..2c9b4e4063 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -575,7 +575,7 @@ pub const InitOptions = struct {
linker_z_max_page_size: ?u64 = null,
linker_tsaware: bool = false,
linker_nxcompat: bool = false,
- linker_dynamicbase: bool = false,
+ linker_dynamicbase: bool = true,
linker_optimization: ?u8 = null,
linker_compress_debug_sections: ?link.CompressDebugSections = null,
linker_module_definition_file: ?[]const u8 = null,
From 1b97881e38e56ae3bdfc4009265840b77fa9e325 Mon Sep 17 00:00:00 2001
From: Jakub Konka
Date: Sat, 25 Mar 2023 21:27:47 +0100
Subject: [PATCH 114/216] libc: update macOS libc headers
---
.../aarch64-macos.11-none/arm/_limits.h | 4 -
.../aarch64-macos.11-none/arm/_mcontext.h | 4 -
.../aarch64-macos.11-none/arm/_param.h | 3 -
.../aarch64-macos.11-none/arm/_types.h | 4 -
.../include/aarch64-macos.11-none/arm/arch.h | 4 -
.../aarch64-macos.11-none/arm/endian.h | 3 -
.../aarch64-macos.11-none/arm/limits.h | 4 -
.../include/aarch64-macos.11-none/arm/param.h | 4 -
.../aarch64-macos.11-none/arm/signal.h | 4 -
.../include/aarch64-macos.11-none/arm/types.h | 8 +-
.../aarch64-macos.11-none/mach/arm/_structs.h | 23 +-
.../aarch64-macos.11-none/mach/arm/boolean.h | 4 -
.../mach/arm/exception.h | 3 -
.../mach/arm/kern_return.h | 4 -
.../mach/arm/processor_info.h | 4 -
.../aarch64-macos.11-none/mach/arm/rpc.h | 4 -
.../mach/arm/thread_state.h | 8 +-
.../mach/arm/thread_status.h | 32 +-
.../aarch64-macos.11-none/mach/arm/vm_param.h | 4 -
.../aarch64-macos.11-none/mach/arm/vm_types.h | 25 +-
lib/libc/include/any-macos-any/db.h | 219 +
lib/libc/include/any-macos-any/err.h | 93 +
lib/libc/include/any-macos-any/fts.h | 190 +
lib/libc/include/any-macos-any/iso646.h | 52 +
.../any-macos-any/libkern/OSCacheControl.h | 66 +
.../include/any-macos-any/libkern/OSDebug.h | 59 +
.../include/any-macos-any/libkern/OSKextLib.h | 571 ++
.../include/any-macos-any/libkern/OSReturn.h | 198 +
.../libkern/OSThermalNotification.h | 135 +
lib/libc/include/any-macos-any/stddef.h | 90 +
.../any-macos-any/sys/_types/_offsetof.h | 30 +
.../any-macos-any/sys/_types/_ptrdiff_t.h | 33 +
lib/libc/include/any-macos-any/vis.h | 138 +
.../include/any-macos.11-any/AssertMacros.h | 1441 ++++
.../any-macos.11-any/AvailabilityInternal.h | 10 +-
.../any-macos.11-any/AvailabilityMacros.h | 4015 ++++++++++
.../any-macos.11-any/AvailabilityVersions.h | 24 -
.../any-macos.11-any/TargetConditionals.h | 12 +-
lib/libc/include/any-macos.11-any/assert.h | 111 +
.../any-macos.11-any/device/device_types.h | 118 +
.../include/any-macos.11-any/dispatch/base.h | 306 +
.../include/any-macos.11-any/dispatch/queue.h | 4 +-
lib/libc/include/any-macos.11-any/execinfo.h | 63 +
.../include/any-macos.11-any/gethostuuid.h | 42 +
.../any-macos.11-any/libkern/OSDebug.h | 69 +
.../any-macos.11-any/libkern/OSKextLib.h | 572 ++
lib/libc/include/any-macos.11-any/libproc.h | 187 +
.../include/any-macos.11-any/mach-o/loader.h | 4 -
.../include/any-macos.11-any/mach/clock.h | 245 +
.../any-macos.11-any/mach/clock_priv.h | 199 +
.../any-macos.11-any/mach/exception_types.h | 206 +
.../include/any-macos.11-any/mach/host_priv.h | 1163 +++
.../any-macos.11-any/mach/host_security.h | 221 +
.../any-macos.11-any/mach/kern_return.h | 342 +
.../include/any-macos.11-any/mach/lock_set.h | 350 +
lib/libc/include/any-macos.11-any/mach/mach.h | 245 +
.../include/any-macos.11-any/mach/mach_host.h | 1295 ++++
.../include/any-macos.11-any/mach/mach_init.h | 2 +
.../include/any-macos.11-any/mach/mach_port.h | 1808 +++++
.../any-macos.11-any/mach/mach_types.h | 5 -
.../mach/mach_voucher_types.h | 245 +
.../include/any-macos.11-any/mach/machine.h | 409 +
.../mach/machine/thread_state.h | 40 +
.../include/any-macos.11-any/mach/message.h | 908 +++
lib/libc/include/any-macos.11-any/mach/mig.h | 180 +
lib/libc/include/any-macos.11-any/mach/port.h | 445 ++
.../include/any-macos.11-any/mach/processor.h | 360 +
.../any-macos.11-any/mach/processor_set.h | 585 ++
.../any-macos.11-any/mach/sync_policy.h | 49 +
lib/libc/include/any-macos.11-any/mach/task.h | 154 +-
.../include/any-macos.11-any/mach/task_info.h | 10 -
.../any-macos.11-any/mach/task_inspect.h | 54 +
.../mach/task_special_ports.h | 135 +
.../any-macos.11-any/mach/thread_act.h | 1435 ++++
.../any-macos.11-any/mach/thread_policy.h | 266 +
.../any-macos.11-any/mach/thread_state.h | 63 +
.../include/any-macos.11-any/mach/vm_map.h | 1503 ++++
.../include/any-macos.11-any/mach/vm_prot.h | 153 +
.../any-macos.11-any/mach/vm_statistics.h | 552 ++
.../include/any-macos.11-any/mach/vm_types.h | 97 +
.../mach_debug/mach_debug_types.h | 95 +
.../any-macos.11-any/machine/_mcontext.h | 34 +
.../include/any-macos.11-any/machine/_param.h | 34 +
.../include/any-macos.11-any/machine/limits.h | 11 +
.../include/any-macos.11-any/malloc/malloc.h | 314 +
lib/libc/include/any-macos.11-any/net/if.h | 13 +-
.../include/any-macos.11-any/net/if_var.h | 120 +-
.../include/any-macos.11-any/net/net_kev.h | 98 +
.../include/any-macos.11-any/netinet6/in6.h | 681 ++
.../any-macos.11-any/objc/NSObjCRuntime.h | 33 +
.../include/any-macos.11-any/objc/message.h | 388 +
.../include/any-macos.11-any/objc/objc-api.h | 304 +
.../include/any-macos.11-any/objc/runtime.h | 263 +
lib/libc/include/any-macos.11-any/os/base.h | 322 +
lib/libc/include/any-macos.11-any/pthread.h | 592 ++
lib/libc/include/any-macos.11-any/simd/base.h | 122 +
.../include/any-macos.11-any/simd/common.h | 4458 +++++++++++
.../any-macos.11-any/simd/conversion.h | 1966 +++++
lib/libc/include/any-macos.11-any/simd/math.h | 5380 +++++++++++++
.../include/any-macos.11-any/simd/matrix.h | 1786 +++++
.../any-macos.11-any/simd/matrix_types.h | 264 +
.../any-macos.11-any/simd/quaternion.h | 1194 +++
.../any-macos.11-any/simd/vector_make.h | 6768 +++++++++++++++++
lib/libc/include/any-macos.11-any/stdio.h | 410 +
lib/libc/include/any-macos.11-any/stdlib.h | 373 +
.../any-macos.11-any/sys/_symbol_aliasing.h | 30 -
.../any-macos.11-any/sys/_types/_uintptr_t.h | 31 +
lib/libc/include/any-macos.11-any/sys/attr.h | 7 +-
lib/libc/include/any-macos.11-any/sys/cdefs.h | 22 +-
lib/libc/include/any-macos.11-any/sys/event.h | 5 +-
lib/libc/include/any-macos.11-any/sys/fcntl.h | 13 +-
lib/libc/include/any-macos.11-any/sys/ioctl.h | 110 +
lib/libc/include/any-macos.11-any/sys/mount.h | 2 +-
.../include/any-macos.11-any/sys/proc_info.h | 11 +-
.../include/any-macos.11-any/sys/random.h | 40 +
.../include/any-macos.11-any/sys/resource.h | 520 ++
.../include/any-macos.11-any/sys/socket.h | 741 ++
.../include/any-macos.11-any/sys/sockio.h | 180 +
.../include/any-macos.11-any/sys/sysctl.h | 26 +-
.../include/any-macos.11-any/sys/ttycom.h | 173 +
lib/libc/include/any-macos.11-any/unistd.h | 787 ++
lib/libc/include/any-macos.11-any/uuid/uuid.h | 79 +
.../include/any-macos.11-any/xpc/activity.h | 446 ++
.../any-macos.11-any/xpc/availability.h | 124 +
lib/libc/include/any-macos.11-any/xpc/base.h | 213 +
.../include/any-macos.11-any/xpc/connection.h | 748 ++
.../AvailabilityMacros.h | 0
.../dispatch/base.h | 0
.../libproc.h | 0
.../mach/clock.h | 0
.../mach/clock_priv.h | 0
.../mach/exception_types.h | 0
.../mach/host_priv.h | 0
.../mach/host_security.h | 0
.../mach/lock_set.h | 0
.../mach/mach.h | 0
.../mach/mach_host.h | 0
.../mach/mach_port.h | 0
.../mach/mach_voucher_types.h | 0
.../mach/machine.h | 0
.../mach/message.h | 0
.../mach/port.h | 0
.../mach/processor.h | 0
.../mach/processor_set.h | 0
.../mach/thread_act.h | 0
.../mach/thread_policy.h | 0
.../mach/vm_map.h | 0
.../mach/vm_prot.h | 0
.../mach/vm_statistics.h | 0
.../mach/vm_types.h | 0
.../mach_debug/mach_debug_types.h | 0
.../malloc/malloc.h | 0
.../netinet6/in6.h | 0
.../objc/NSObjCRuntime.h | 0
.../objc/message.h | 0
.../objc/objc-api.h | 0
.../os/base.h | 0
.../pthread.h | 0
.../simd/base.h | 0
.../simd/math.h | 0
.../stdio.h | 0
.../stdlib.h | 0
.../sys/resource.h | 0
.../sys/socket.h | 0
.../xpc/base.h | 0
.../xpc/connection.h | 0
.../any-macos.13-any/AvailabilityInternal.h | 8 +-
.../any-macos.13-any/AvailabilityVersions.h | 4 +
lib/libc/include/any-macos.13-any/net/if.h | 2 +-
.../any-macos.13-any/sys/_symbol_aliasing.h | 12 +
.../any-macos.13-any/sys/constrained_ctypes.h | 106 +-
lib/libc/include/any-macos.13-any/vis.h | 143 +
.../x86_64-macos.11-none/i386/_limits.h | 4 -
.../x86_64-macos.11-none/i386/_mcontext.h | 4 -
.../x86_64-macos.11-none/i386/_param.h | 3 -
.../x86_64-macos.11-none/i386/_types.h | 4 -
.../x86_64-macos.11-none/i386/eflags.h | 4 -
.../x86_64-macos.11-none/i386/endian.h | 3 -
.../x86_64-macos.11-none/i386/limits.h | 4 -
.../include/x86_64-macos.11-none/i386/param.h | 4 -
.../x86_64-macos.11-none/i386/signal.h | 4 -
.../include/x86_64-macos.11-none/i386/types.h | 8 +-
.../x86_64-macos.11-none/mach/i386/_structs.h | 4 -
.../x86_64-macos.11-none/mach/i386/boolean.h | 4 -
.../mach/i386/exception.h | 4 -
.../x86_64-macos.11-none/mach/i386/fp_reg.h | 4 -
.../mach/i386/kern_return.h | 4 -
.../mach/i386/processor_info.h | 4 -
.../x86_64-macos.11-none/mach/i386/rpc.h | 4 -
.../mach/i386/thread_state.h | 6 +-
.../mach/i386/thread_status.h | 6 +-
.../x86_64-macos.11-none/mach/i386/vm_param.h | 10 +-
.../x86_64-macos.11-none/mach/i386/vm_types.h | 17 +-
193 files changed, 52831 insertions(+), 613 deletions(-)
create mode 100644 lib/libc/include/any-macos-any/db.h
create mode 100644 lib/libc/include/any-macos-any/err.h
create mode 100644 lib/libc/include/any-macos-any/fts.h
create mode 100644 lib/libc/include/any-macos-any/iso646.h
create mode 100644 lib/libc/include/any-macos-any/libkern/OSCacheControl.h
create mode 100644 lib/libc/include/any-macos-any/libkern/OSDebug.h
create mode 100644 lib/libc/include/any-macos-any/libkern/OSKextLib.h
create mode 100644 lib/libc/include/any-macos-any/libkern/OSReturn.h
create mode 100644 lib/libc/include/any-macos-any/libkern/OSThermalNotification.h
create mode 100644 lib/libc/include/any-macos-any/stddef.h
create mode 100644 lib/libc/include/any-macos-any/sys/_types/_offsetof.h
create mode 100644 lib/libc/include/any-macos-any/sys/_types/_ptrdiff_t.h
create mode 100644 lib/libc/include/any-macos-any/vis.h
create mode 100644 lib/libc/include/any-macos.11-any/AssertMacros.h
create mode 100644 lib/libc/include/any-macos.11-any/AvailabilityMacros.h
create mode 100644 lib/libc/include/any-macos.11-any/assert.h
create mode 100644 lib/libc/include/any-macos.11-any/device/device_types.h
create mode 100644 lib/libc/include/any-macos.11-any/dispatch/base.h
create mode 100644 lib/libc/include/any-macos.11-any/execinfo.h
create mode 100644 lib/libc/include/any-macos.11-any/gethostuuid.h
create mode 100644 lib/libc/include/any-macos.11-any/libkern/OSDebug.h
create mode 100644 lib/libc/include/any-macos.11-any/libkern/OSKextLib.h
create mode 100644 lib/libc/include/any-macos.11-any/libproc.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/clock.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/clock_priv.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/exception_types.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/host_priv.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/host_security.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/kern_return.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/lock_set.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/mach.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/mach_host.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/mach_port.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/mach_voucher_types.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/machine.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/machine/thread_state.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/message.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/mig.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/port.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/processor.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/processor_set.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/sync_policy.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/task_inspect.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/task_special_ports.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/thread_act.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/thread_policy.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/thread_state.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/vm_map.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/vm_prot.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/vm_statistics.h
create mode 100644 lib/libc/include/any-macos.11-any/mach/vm_types.h
create mode 100644 lib/libc/include/any-macos.11-any/mach_debug/mach_debug_types.h
create mode 100644 lib/libc/include/any-macos.11-any/machine/_mcontext.h
create mode 100644 lib/libc/include/any-macos.11-any/machine/_param.h
create mode 100644 lib/libc/include/any-macos.11-any/machine/limits.h
create mode 100644 lib/libc/include/any-macos.11-any/malloc/malloc.h
create mode 100644 lib/libc/include/any-macos.11-any/net/net_kev.h
create mode 100644 lib/libc/include/any-macos.11-any/netinet6/in6.h
create mode 100644 lib/libc/include/any-macos.11-any/objc/NSObjCRuntime.h
create mode 100644 lib/libc/include/any-macos.11-any/objc/message.h
create mode 100644 lib/libc/include/any-macos.11-any/objc/objc-api.h
create mode 100644 lib/libc/include/any-macos.11-any/os/base.h
create mode 100644 lib/libc/include/any-macos.11-any/pthread.h
create mode 100644 lib/libc/include/any-macos.11-any/simd/base.h
create mode 100644 lib/libc/include/any-macos.11-any/simd/common.h
create mode 100644 lib/libc/include/any-macos.11-any/simd/conversion.h
create mode 100644 lib/libc/include/any-macos.11-any/simd/math.h
create mode 100644 lib/libc/include/any-macos.11-any/simd/matrix.h
create mode 100644 lib/libc/include/any-macos.11-any/simd/matrix_types.h
create mode 100644 lib/libc/include/any-macos.11-any/simd/quaternion.h
create mode 100644 lib/libc/include/any-macos.11-any/simd/vector_make.h
create mode 100644 lib/libc/include/any-macos.11-any/stdio.h
create mode 100644 lib/libc/include/any-macos.11-any/stdlib.h
create mode 100644 lib/libc/include/any-macos.11-any/sys/_types/_uintptr_t.h
create mode 100644 lib/libc/include/any-macos.11-any/sys/ioctl.h
create mode 100644 lib/libc/include/any-macos.11-any/sys/random.h
create mode 100644 lib/libc/include/any-macos.11-any/sys/resource.h
create mode 100644 lib/libc/include/any-macos.11-any/sys/socket.h
create mode 100644 lib/libc/include/any-macos.11-any/sys/sockio.h
create mode 100644 lib/libc/include/any-macos.11-any/sys/ttycom.h
create mode 100644 lib/libc/include/any-macos.11-any/unistd.h
create mode 100644 lib/libc/include/any-macos.11-any/uuid/uuid.h
create mode 100644 lib/libc/include/any-macos.11-any/xpc/activity.h
create mode 100644 lib/libc/include/any-macos.11-any/xpc/availability.h
create mode 100644 lib/libc/include/any-macos.11-any/xpc/base.h
create mode 100644 lib/libc/include/any-macos.11-any/xpc/connection.h
rename lib/libc/include/{any-macos-any => any-macos.12-any}/AvailabilityMacros.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/dispatch/base.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/libproc.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/clock.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/clock_priv.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/exception_types.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/host_priv.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/host_security.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/lock_set.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/mach.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/mach_host.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/mach_port.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/mach_voucher_types.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/machine.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/message.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/port.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/processor.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/processor_set.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/thread_act.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/thread_policy.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/vm_map.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/vm_prot.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/vm_statistics.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach/vm_types.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/mach_debug/mach_debug_types.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/malloc/malloc.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/netinet6/in6.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/objc/NSObjCRuntime.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/objc/message.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/objc/objc-api.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/os/base.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/pthread.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/simd/base.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/simd/math.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/stdio.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/stdlib.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/sys/resource.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/sys/socket.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/xpc/base.h (100%)
rename lib/libc/include/{any-macos-any => any-macos.12-any}/xpc/connection.h (100%)
create mode 100644 lib/libc/include/any-macos.13-any/vis.h
diff --git a/lib/libc/include/aarch64-macos.11-none/arm/_limits.h b/lib/libc/include/aarch64-macos.11-none/arm/_limits.h
index 8cb2759402..dd9eb5c2be 100644
--- a/lib/libc/include/aarch64-macos.11-none/arm/_limits.h
+++ b/lib/libc/include/aarch64-macos.11-none/arm/_limits.h
@@ -4,10 +4,6 @@
#ifndef _ARM__LIMITS_H_
#define _ARM__LIMITS_H_
-#if defined (__arm__) || defined (__arm64__)
-
#define __DARWIN_CLK_TCK 100 /* ticks per second */
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* _ARM__LIMITS_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/arm/_mcontext.h b/lib/libc/include/aarch64-macos.11-none/arm/_mcontext.h
index 26b83ce221..72253cfbac 100644
--- a/lib/libc/include/aarch64-macos.11-none/arm/_mcontext.h
+++ b/lib/libc/include/aarch64-macos.11-none/arm/_mcontext.h
@@ -29,8 +29,6 @@
#ifndef __ARM_MCONTEXT_H_
#define __ARM_MCONTEXT_H_
-#if defined (__arm__) || defined (__arm64__)
-
#include /* __DARWIN_UNIX03 */
#include
#include
@@ -90,6 +88,4 @@ typedef _STRUCT_MCONTEXT32 *mcontext_t;
#endif
#endif /* _MCONTEXT_T */
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* __ARM_MCONTEXT_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/arm/_param.h b/lib/libc/include/aarch64-macos.11-none/arm/_param.h
index 10b9edf2f3..81c5bf53cf 100644
--- a/lib/libc/include/aarch64-macos.11-none/arm/_param.h
+++ b/lib/libc/include/aarch64-macos.11-none/arm/_param.h
@@ -5,8 +5,6 @@
#ifndef _ARM__PARAM_H_
#define _ARM__PARAM_H_
-#if defined (__arm__) || defined (__arm64__)
-
#include
/*
@@ -20,6 +18,5 @@
#define __DARWIN_ALIGNBYTES32 (sizeof(__uint32_t) - 1)
#define __DARWIN_ALIGN32(p) ((__darwin_size_t)((__darwin_size_t)(p) + __DARWIN_ALIGNBYTES32) &~ __DARWIN_ALIGNBYTES32)
-#endif /* defined (__arm__) || defined (__arm64__) */
#endif /* _ARM__PARAM_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/arm/_types.h b/lib/libc/include/aarch64-macos.11-none/arm/_types.h
index 403ec44048..d6c4de8fac 100644
--- a/lib/libc/include/aarch64-macos.11-none/arm/_types.h
+++ b/lib/libc/include/aarch64-macos.11-none/arm/_types.h
@@ -4,8 +4,6 @@
#ifndef _BSD_ARM__TYPES_H_
#define _BSD_ARM__TYPES_H_
-#if defined (__arm__) || defined (__arm64__)
-
/*
* This header file contains integer types. It's intended to also contain
* flotaing point and other arithmetic types, as needed, later.
@@ -97,6 +95,4 @@ typedef __uint32_t __darwin_socklen_t; /* socklen_t (duh) */
typedef long __darwin_ssize_t; /* byte count or error */
typedef long __darwin_time_t; /* time() */
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* _BSD_ARM__TYPES_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/arm/arch.h b/lib/libc/include/aarch64-macos.11-none/arm/arch.h
index b8b25e55d3..e93e87bf06 100644
--- a/lib/libc/include/aarch64-macos.11-none/arm/arch.h
+++ b/lib/libc/include/aarch64-macos.11-none/arm/arch.h
@@ -28,8 +28,6 @@
#ifndef _ARM_ARCH_H
#define _ARM_ARCH_H
-#if defined (__arm__) || defined (__arm64__)
-
/* Collect the __ARM_ARCH_*__ compiler flags into something easier to use. */
#if defined (__ARM_ARCH_7A__) || defined (__ARM_ARCH_7S__) || defined (__ARM_ARCH_7F__) || defined (__ARM_ARCH_7K__)
#define _ARM_ARCH_7
@@ -66,6 +64,4 @@
#define _ARM_ARCH_4
#endif
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/arm/endian.h b/lib/libc/include/aarch64-macos.11-none/arm/endian.h
index 851f2eafe2..d05874ecf4 100644
--- a/lib/libc/include/aarch64-macos.11-none/arm/endian.h
+++ b/lib/libc/include/aarch64-macos.11-none/arm/endian.h
@@ -42,8 +42,6 @@
#ifndef _ARM__ENDIAN_H_
#define _ARM__ENDIAN_H_
-#if defined (__arm__) || defined (__arm64__)
-
#include
/*
* Define _NOQUAD if the compiler does NOT support 64-bit integers.
@@ -77,5 +75,4 @@
#include
#endif /* defined(KERNEL) || (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)) */
-#endif /* defined (__arm__) || defined (__arm64__) */
#endif /* !_ARM__ENDIAN_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/arm/limits.h b/lib/libc/include/aarch64-macos.11-none/arm/limits.h
index 21de9a758b..f889c48b6a 100644
--- a/lib/libc/include/aarch64-macos.11-none/arm/limits.h
+++ b/lib/libc/include/aarch64-macos.11-none/arm/limits.h
@@ -39,8 +39,6 @@
#ifndef _ARM_LIMITS_H_
#define _ARM_LIMITS_H_
-#if defined (__arm__) || defined (__arm64__)
-
#include
#include
@@ -109,6 +107,4 @@
#endif /* (!_POSIX_C_SOURCE && !_XOPEN_SOURCE) || _DARWIN_C_SOURCE */
#endif /* !_ANSI_SOURCE */
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* _ARM_LIMITS_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/arm/param.h b/lib/libc/include/aarch64-macos.11-none/arm/param.h
index f36fa322cb..e70f68f9c3 100644
--- a/lib/libc/include/aarch64-macos.11-none/arm/param.h
+++ b/lib/libc/include/aarch64-macos.11-none/arm/param.h
@@ -48,8 +48,6 @@
#ifndef _ARM_PARAM_H_
#define _ARM_PARAM_H_
-#if defined (__arm__) || defined (__arm64__)
-
#include
/*
@@ -146,6 +144,4 @@
#define DELAY(n) { int N = (n); while (--N > 0); }
#endif /* defined(KERNEL) || defined(STANDALONE) */
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* _ARM_PARAM_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/arm/signal.h b/lib/libc/include/aarch64-macos.11-none/arm/signal.h
index 4a8b96b383..80d2564826 100644
--- a/lib/libc/include/aarch64-macos.11-none/arm/signal.h
+++ b/lib/libc/include/aarch64-macos.11-none/arm/signal.h
@@ -9,14 +9,10 @@
#ifndef _ARM_SIGNAL_
#define _ARM_SIGNAL_ 1
-#if defined (__arm__) || defined (__arm64__)
-
#include
#ifndef _ANSI_SOURCE
typedef int sig_atomic_t;
#endif /* ! _ANSI_SOURCE */
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* _ARM_SIGNAL_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/arm/types.h b/lib/libc/include/aarch64-macos.11-none/arm/types.h
index 6cc1f453c9..9a6c23bb9a 100644
--- a/lib/libc/include/aarch64-macos.11-none/arm/types.h
+++ b/lib/libc/include/aarch64-macos.11-none/arm/types.h
@@ -39,12 +39,9 @@
* @(#)types.h 8.3 (Berkeley) 1/5/94
*/
-#ifndef _ARM_MACHTYPES_H_
-#define _ARM_MACHTYPES_H_
+#ifndef _MACHTYPES_H_
#define _MACHTYPES_H_
-#if defined (__arm__) || defined (__arm64__)
-
#ifndef __ASSEMBLER__
#include
#include
@@ -107,5 +104,4 @@ typedef u_int64_t syscall_arg_t;
#endif
#endif /* __ASSEMBLER__ */
-#endif /* defined (__arm__) || defined (__arm64__) */
-#endif /* _ARM_MACHTYPES_H_ */
\ No newline at end of file
+#endif /* _MACHTYPES_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/mach/arm/_structs.h b/lib/libc/include/aarch64-macos.11-none/mach/arm/_structs.h
index da0ec8b687..ddee2f7341 100644
--- a/lib/libc/include/aarch64-macos.11-none/mach/arm/_structs.h
+++ b/lib/libc/include/aarch64-macos.11-none/mach/arm/_structs.h
@@ -31,8 +31,6 @@
#ifndef _MACH_ARM__STRUCTS_H_
#define _MACH_ARM__STRUCTS_H_
-#if defined (__arm__) || defined (__arm64__)
-
#include /* __DARWIN_UNIX03 */
#include /* __uint32_t */
@@ -509,6 +507,25 @@ _STRUCT_ARM_NEON_STATE
#endif /* __DARWIN_UNIX03 */
+#if __DARWIN_UNIX03
+#define _STRUCT_ARM_AMX_STATE_V1 struct __darwin_arm_amx_state_v1
+_STRUCT_ARM_AMX_STATE_V1
+{
+ __uint8_t __x[8][64]; /* 8 64-byte registers */
+ __uint8_t __y[8][64]; /* 8 64-byte registers */
+ __uint8_t __z[64][64]; /* 64 64-byte registers in an M-by-N matrix */
+ __uint64_t __amx_state_t_el1; /* AMX_STATE_T_EL1 value */
+} __attribute__((aligned(64)));
+#else /* !__DARWIN_UNIX03 */
+#define _STRUCT_ARM_AMX_STATE_V1 struct arm_amx_state_v1
+_STRUCT_ARM_AMX_STATE_V1
+{
+ __uint8_t x[8][64]; /* 8 64-byte registers */
+ __uint8_t y[8][64]; /* 8 64-byte registers */
+ __uint8_t z[64][64]; /* 64 64-byte registers in an M-by-N matrix */
+ __uint64_t amx_state_t_el1; /* AMX_STATE_T_EL1 value. */
+} __attribute__((aligned(64)));
+#endif /* __DARWIN_UNIX03 */
#define _STRUCT_ARM_PAGEIN_STATE struct __arm_pagein_state
_STRUCT_ARM_PAGEIN_STATE
@@ -625,6 +642,4 @@ _STRUCT_ARM_CPMU_STATE64
};
#endif /* !__DARWIN_UNIX03 */
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* _MACH_ARM__STRUCTS_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/mach/arm/boolean.h b/lib/libc/include/aarch64-macos.11-none/mach/arm/boolean.h
index 9cdf7c237e..703153e4e6 100644
--- a/lib/libc/include/aarch64-macos.11-none/mach/arm/boolean.h
+++ b/lib/libc/include/aarch64-macos.11-none/mach/arm/boolean.h
@@ -65,10 +65,6 @@
#ifndef _MACH_ARM_BOOLEAN_H_
#define _MACH_ARM_BOOLEAN_H_
-#if defined (__arm__) || defined (__arm64__)
-
typedef int boolean_t;
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* _MACH_ARM_BOOLEAN_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/mach/arm/exception.h b/lib/libc/include/aarch64-macos.11-none/mach/arm/exception.h
index c27dec1b56..cf804261a9 100644
--- a/lib/libc/include/aarch64-macos.11-none/mach/arm/exception.h
+++ b/lib/libc/include/aarch64-macos.11-none/mach/arm/exception.h
@@ -29,8 +29,6 @@
#ifndef _MACH_ARM_EXCEPTION_H_
#define _MACH_ARM_EXCEPTION_H_
-#if defined (__arm__) || defined (__arm64__)
-
#define EXC_TYPES_COUNT 14 /* incl. illegal exception 0 */
#define EXC_MASK_MACHINE 0
@@ -77,6 +75,5 @@
#define EXC_ARM_BREAKPOINT 1 /* breakpoint trap */
-#endif /* defined (__arm__) || defined (__arm64__) */
#endif /* _MACH_ARM_EXCEPTION_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/mach/arm/kern_return.h b/lib/libc/include/aarch64-macos.11-none/mach/arm/kern_return.h
index bfa07951b3..0c23b0f973 100644
--- a/lib/libc/include/aarch64-macos.11-none/mach/arm/kern_return.h
+++ b/lib/libc/include/aarch64-macos.11-none/mach/arm/kern_return.h
@@ -67,12 +67,8 @@
#ifndef _MACH_ARM_KERN_RETURN_H_
#define _MACH_ARM_KERN_RETURN_H_
-#if defined (__arm__) || defined (__arm64__)
-
#ifndef ASSEMBLER
typedef int kern_return_t;
#endif /* ASSEMBLER */
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* _MACH_ARM_KERN_RETURN_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/mach/arm/processor_info.h b/lib/libc/include/aarch64-macos.11-none/mach/arm/processor_info.h
index a302fbfcd3..cc2cfadeb4 100644
--- a/lib/libc/include/aarch64-macos.11-none/mach/arm/processor_info.h
+++ b/lib/libc/include/aarch64-macos.11-none/mach/arm/processor_info.h
@@ -29,8 +29,6 @@
#ifndef _MACH_ARM_PROCESSOR_INFO_H_
#define _MACH_ARM_PROCESSOR_INFO_H_
-#if defined (__arm__) || defined (__arm64__)
-
#define PROCESSOR_CPU_STAT 0x10000003 /* Low-level CPU statistics */
#define PROCESSOR_CPU_STAT64 0x10000004 /* Low-level CPU statistics, in full 64-bit */
@@ -71,6 +69,4 @@ typedef struct processor_cpu_stat64 *processor_cpu_stat64_t;
#define PROCESSOR_CPU_STAT64_COUNT ((mach_msg_type_number_t) \
(sizeof(processor_cpu_stat64_data_t) / sizeof(integer_t)))
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* _MACH_ARM_PROCESSOR_INFO_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/mach/arm/rpc.h b/lib/libc/include/aarch64-macos.11-none/mach/arm/rpc.h
index cb100ece01..3543cdf1ad 100644
--- a/lib/libc/include/aarch64-macos.11-none/mach/arm/rpc.h
+++ b/lib/libc/include/aarch64-macos.11-none/mach/arm/rpc.h
@@ -32,8 +32,4 @@
#ifndef _MACH_ARM_RPC_H_
#define _MACH_ARM_RPC_H_
-#if defined (__arm__) || defined (__arm64__)
-
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* _MACH_ARM_RPC_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/mach/arm/thread_state.h b/lib/libc/include/aarch64-macos.11-none/mach/arm/thread_state.h
index d72a3c2013..75c28e6692 100644
--- a/lib/libc/include/aarch64-macos.11-none/mach/arm/thread_state.h
+++ b/lib/libc/include/aarch64-macos.11-none/mach/arm/thread_state.h
@@ -32,11 +32,13 @@
#ifndef _MACH_ARM_THREAD_STATE_H_
#define _MACH_ARM_THREAD_STATE_H_
-#if defined (__arm__) || defined (__arm64__)
-
/* Size of maximum exported thread state in words */
#define ARM_THREAD_STATE_MAX (1296) /* Size of biggest state possible */
-#endif /* defined (__arm__) || defined (__arm64__) */
+#if defined (__arm__) || defined(__arm64__)
+#define THREAD_STATE_MAX ARM_THREAD_STATE_MAX
+#else
+#error Unsupported arch
+#endif
#endif /* _MACH_ARM_THREAD_STATE_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/mach/arm/thread_status.h b/lib/libc/include/aarch64-macos.11-none/mach/arm/thread_status.h
index 849eca5900..f8d0ccb037 100644
--- a/lib/libc/include/aarch64-macos.11-none/mach/arm/thread_status.h
+++ b/lib/libc/include/aarch64-macos.11-none/mach/arm/thread_status.h
@@ -33,12 +33,10 @@
#ifndef _ARM_THREAD_STATUS_H_
#define _ARM_THREAD_STATUS_H_
-#if defined (__arm__) || defined (__arm64__)
-
#include
-#include
#include
#include
+#include
/*
* Support for determining the state of a thread
@@ -69,12 +67,13 @@
#define ARM_CPMU_STATE64 18
+/* API */
+#define ARM_AMX_STATE 24
+#define ARM_AMX_STATE_V1 25
+#define ARM_STATE_FLAVOR_IS_OTHER_VALID(_flavor_) \
+ ((_flavor_) == ARM_AMX_STATE_V1)
#define ARM_PAGEIN_STATE 27
-#ifndef ARM_STATE_FLAVOR_IS_OTHER_VALID
-#define ARM_STATE_FLAVOR_IS_OTHER_VALID(_flavor_) 0
-#endif
-
#define VALID_THREAD_STATE_FLAVOR(x) \
((x == ARM_THREAD_STATE) || \
(x == ARM_VFP_STATE) || \
@@ -171,6 +170,7 @@ typedef _STRUCT_ARM_NEON_STATE arm_neon_state_t;
typedef _STRUCT_ARM_NEON_STATE arm_neon_state32_t;
typedef _STRUCT_ARM_NEON_STATE64 arm_neon_state64_t;
+typedef _STRUCT_ARM_AMX_STATE_V1 arm_amx_state_v1_t;
typedef _STRUCT_ARM_EXCEPTION_STATE arm_exception_state_t;
typedef _STRUCT_ARM_EXCEPTION_STATE arm_exception_state32_t;
@@ -224,12 +224,26 @@ typedef _STRUCT_ARM_LEGACY_DEBUG_STATE arm_debug_state_t;
#define MACHINE_THREAD_STATE_COUNT ARM_UNIFIED_THREAD_STATE_COUNT
+struct arm_amx_state {
+ arm_state_hdr_t ash;
+ union {
+ arm_amx_state_v1_t as_v1;
+ } uas;
+};
+#define as_v1 uas.as_v1
+typedef struct arm_amx_state arm_amx_state_t;
+
+#define ARM_AMX_STATE_V1_COUNT ((mach_msg_type_number_t) \
+ (sizeof(arm_amx_state_v1_t)/sizeof(unsigned int)))
+
+#define ARM_AMX_STATE_COUNT ((mach_msg_type_number_t) \
+ (sizeof(arm_amx_state_t)/sizeof(unsigned int)))
+
+
/*
* Largest state on this machine:
*/
#define THREAD_MACHINE_STATE_MAX THREAD_STATE_MAX
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* _ARM_THREAD_STATUS_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/mach/arm/vm_param.h b/lib/libc/include/aarch64-macos.11-none/mach/arm/vm_param.h
index acb1392418..1738a03517 100644
--- a/lib/libc/include/aarch64-macos.11-none/mach/arm/vm_param.h
+++ b/lib/libc/include/aarch64-macos.11-none/mach/arm/vm_param.h
@@ -36,8 +36,6 @@
#ifndef _MACH_ARM_VM_PARAM_H_
#define _MACH_ARM_VM_PARAM_H_
-#if defined (__arm__) || defined (__arm64__)
-
#if !defined (KERNEL) && !defined (__ASSEMBLER__)
#include
@@ -106,6 +104,4 @@
#define SWI_SYSCALL 0x80
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* _MACH_ARM_VM_PARAM_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-macos.11-none/mach/arm/vm_types.h b/lib/libc/include/aarch64-macos.11-none/mach/arm/vm_types.h
index 396923d4c2..6fcf262c24 100644
--- a/lib/libc/include/aarch64-macos.11-none/mach/arm/vm_types.h
+++ b/lib/libc/include/aarch64-macos.11-none/mach/arm/vm_types.h
@@ -67,14 +67,11 @@
#ifndef _MACH_ARM_VM_TYPES_H_
#define _MACH_ARM_VM_TYPES_H_
-#if defined (__arm__) || defined (__arm64__)
-
#ifndef ASSEMBLER
#include
#include
#include
-#include
/*
* natural_t and integer_t are Mach's legacy types for machine-
@@ -101,18 +98,18 @@ typedef int integer_t;
* e.g. an offset into a virtual memory space.
*/
#ifdef __LP64__
-typedef uintptr_t vm_offset_t __kernel_ptr_semantics;
+typedef uintptr_t vm_offset_t;
typedef uintptr_t vm_size_t;
-typedef uint64_t mach_vm_address_t __kernel_ptr_semantics;
-typedef uint64_t mach_vm_offset_t __kernel_ptr_semantics;
+typedef uint64_t mach_vm_address_t;
+typedef uint64_t mach_vm_offset_t;
typedef uint64_t mach_vm_size_t;
-typedef uint64_t vm_map_offset_t __kernel_ptr_semantics;
-typedef uint64_t vm_map_address_t __kernel_ptr_semantics;
+typedef uint64_t vm_map_offset_t;
+typedef uint64_t vm_map_address_t;
typedef uint64_t vm_map_size_t;
#else
-typedef natural_t vm_offset_t __kernel_ptr_semantics;
+typedef natural_t vm_offset_t;
/*
* A vm_size_t is the proper type for e.g.
* expressing the difference between two
@@ -132,13 +129,13 @@ typedef uint32_t mach_vm_address_t;
typedef uint32_t mach_vm_offset_t;
typedef uint32_t mach_vm_size_t;
#else
-typedef uint64_t mach_vm_address_t __kernel_ptr_semantics;
-typedef uint64_t mach_vm_offset_t __kernel_ptr_semantics;
+typedef uint64_t mach_vm_address_t;
+typedef uint64_t mach_vm_offset_t;
typedef uint64_t mach_vm_size_t;
#endif
-typedef uint32_t vm_map_offset_t __kernel_ptr_semantics;
-typedef uint32_t vm_map_address_t __kernel_ptr_semantics;
+typedef uint32_t vm_map_offset_t;
+typedef uint32_t vm_map_address_t;
typedef uint32_t vm_map_size_t;
#endif /* __LP64__ */
@@ -157,6 +154,4 @@ typedef vm_offset_t mach_port_context_t;
*/
#define MACH_MSG_TYPE_INTEGER_T MACH_MSG_TYPE_INTEGER_32
-#endif /* defined (__arm__) || defined (__arm64__) */
-
#endif /* _MACH_ARM_VM_TYPES_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos-any/db.h b/lib/libc/include/any-macos-any/db.h
new file mode 100644
index 0000000000..53ea611101
--- /dev/null
+++ b/lib/libc/include/any-macos-any/db.h
@@ -0,0 +1,219 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)db.h 8.7 (Berkeley) 6/16/94
+ * $FreeBSD: src/include/db.h,v 1.5 2002/03/26 01:35:05 bde Exp $
+ */
+
+#ifndef _DB_H_
+#define _DB_H_
+
+#include
+#include
+
+#include
+
+#define RET_ERROR -1 /* Return values. */
+#define RET_SUCCESS 0
+#define RET_SPECIAL 1
+
+#define MAX_PAGE_NUMBER 0xffffffff /* >= # of pages in a file */
+typedef u_int32_t pgno_t;
+#define MAX_PAGE_OFFSET 65535 /* >= # of bytes in a page */
+typedef u_int16_t indx_t;
+#define MAX_REC_NUMBER 0xffffffff /* >= # of records in a tree */
+typedef u_int32_t recno_t;
+
+/* Key/data structure -- a Data-Base Thang. */
+typedef struct {
+ void *data; /* data */
+ size_t size; /* data length */
+} DBT;
+
+/* Routine flags. */
+#define R_CURSOR 1 /* del, put, seq */
+#define __R_UNUSED 2 /* UNUSED */
+#define R_FIRST 3 /* seq */
+#define R_IAFTER 4 /* put (RECNO) */
+#define R_IBEFORE 5 /* put (RECNO) */
+#define R_LAST 6 /* seq (BTREE, RECNO) */
+#define R_NEXT 7 /* seq */
+#define R_NOOVERWRITE 8 /* put */
+#define R_PREV 9 /* seq (BTREE, RECNO) */
+#define R_SETCURSOR 10 /* put (RECNO) */
+#define R_RECNOSYNC 11 /* sync (RECNO) */
+
+typedef enum { DB_BTREE, DB_HASH, DB_RECNO } DBTYPE;
+
+/*
+ * !!!
+ * The following flags are included in the dbopen(3) call as part of the
+ * open(2) flags. In order to avoid conflicts with the open flags, start
+ * at the top of the 16 or 32-bit number space and work our way down. If
+ * the open flags were significantly expanded in the future, it could be
+ * a problem. Wish I'd left another flags word in the dbopen call.
+ *
+ * !!!
+ * None of this stuff is implemented yet. The only reason that it's here
+ * is so that the access methods can skip copying the key/data pair when
+ * the DB_LOCK flag isn't set.
+ */
+#if UINT_MAX > 65535
+#define DB_LOCK 0x20000000 /* Do locking. */
+#define DB_SHMEM 0x40000000 /* Use shared memory. */
+#define DB_TXN 0x80000000 /* Do transactions. */
+#else
+#define DB_LOCK 0x2000 /* Do locking. */
+#define DB_SHMEM 0x4000 /* Use shared memory. */
+#define DB_TXN 0x8000 /* Do transactions. */
+#endif
+
+/* Access method description structure. */
+typedef struct __db {
+ DBTYPE type; /* Underlying db type. */
+ int (*close)(struct __db *);
+ int (*del)(const struct __db *, const DBT *, unsigned int);
+ int (*get)(const struct __db *, const DBT *, DBT *, unsigned int);
+ int (*put)(const struct __db *, DBT *, const DBT *, unsigned int);
+ int (*seq)(const struct __db *, DBT *, DBT *, unsigned int);
+ int (*sync)(const struct __db *, unsigned int);
+ void *internal; /* Access method private. */
+ int (*fd)(const struct __db *);
+} DB;
+
+#define BTREEMAGIC 0x053162
+#define BTREEVERSION 3
+
+/* Structure used to pass parameters to the btree routines. */
+typedef struct {
+#define R_DUP 0x01 /* duplicate keys */
+ unsigned long flags;
+ unsigned int cachesize; /* bytes to cache */
+ int maxkeypage; /* maximum keys per page */
+ int minkeypage; /* minimum keys per page */
+ unsigned int psize; /* page size */
+ int (*compare) /* comparison function */
+ (const DBT *, const DBT *);
+ size_t (*prefix) /* prefix function */
+ (const DBT *, const DBT *);
+ int lorder; /* byte order */
+} BTREEINFO;
+
+#define HASHMAGIC 0x061561
+#define HASHVERSION 2
+
+/* Structure used to pass parameters to the hashing routines. */
+typedef struct {
+ unsigned int bsize; /* bucket size */
+ unsigned int ffactor; /* fill factor */
+ unsigned int nelem; /* number of elements */
+ unsigned int cachesize; /* bytes to cache */
+ u_int32_t /* hash function */
+ (*hash)(const void *, size_t);
+ int lorder; /* byte order */
+} HASHINFO;
+
+/* Structure used to pass parameters to the record routines. */
+typedef struct {
+#define R_FIXEDLEN 0x01 /* fixed-length records */
+#define R_NOKEY 0x02 /* key not required */
+#define R_SNAPSHOT 0x04 /* snapshot the input */
+ unsigned long flags;
+ unsigned int cachesize; /* bytes to cache */
+ unsigned int psize; /* page size */
+ int lorder; /* byte order */
+ size_t reclen; /* record length (fixed-length records) */
+ unsigned char bval; /* delimiting byte (variable-length records */
+ char *bfname; /* btree file name */
+} RECNOINFO;
+
+#ifdef __DBINTERFACE_PRIVATE
+/*
+ * Little endian <==> big endian 32-bit swap macros.
+ * M_32_SWAP swap a memory location
+ * P_32_SWAP swap a referenced memory location
+ * P_32_COPY swap from one location to another
+ */
+#define M_32_SWAP(a) { \
+ u_int32_t _tmp = a; \
+ ((char *)&a)[0] = ((char *)&_tmp)[3]; \
+ ((char *)&a)[1] = ((char *)&_tmp)[2]; \
+ ((char *)&a)[2] = ((char *)&_tmp)[1]; \
+ ((char *)&a)[3] = ((char *)&_tmp)[0]; \
+}
+#define P_32_SWAP(a) { \
+ u_int32_t _tmp = *(u_int32_t *)a; \
+ ((char *)a)[0] = ((char *)&_tmp)[3]; \
+ ((char *)a)[1] = ((char *)&_tmp)[2]; \
+ ((char *)a)[2] = ((char *)&_tmp)[1]; \
+ ((char *)a)[3] = ((char *)&_tmp)[0]; \
+}
+#define P_32_COPY(a, b) { \
+ ((char *)&(b))[0] = ((char *)&(a))[3]; \
+ ((char *)&(b))[1] = ((char *)&(a))[2]; \
+ ((char *)&(b))[2] = ((char *)&(a))[1]; \
+ ((char *)&(b))[3] = ((char *)&(a))[0]; \
+}
+
+/*
+ * Little endian <==> big endian 16-bit swap macros.
+ * M_16_SWAP swap a memory location
+ * P_16_SWAP swap a referenced memory location
+ * P_16_COPY swap from one location to another
+ */
+#define M_16_SWAP(a) { \
+ u_int16_t _tmp = a; \
+ ((char *)&a)[0] = ((char *)&_tmp)[1]; \
+ ((char *)&a)[1] = ((char *)&_tmp)[0]; \
+}
+#define P_16_SWAP(a) { \
+ u_int16_t _tmp = *(u_int16_t *)a; \
+ ((char *)a)[0] = ((char *)&_tmp)[1]; \
+ ((char *)a)[1] = ((char *)&_tmp)[0]; \
+}
+#define P_16_COPY(a, b) { \
+ ((char *)&(b))[0] = ((char *)&(a))[1]; \
+ ((char *)&(b))[1] = ((char *)&(a))[0]; \
+}
+#endif
+
+__BEGIN_DECLS
+DB *dbopen(const char *, int, int, DBTYPE, const void *);
+
+#ifdef __DBINTERFACE_PRIVATE
+DB *__bt_open(const char *, int, int, const BTREEINFO *, int);
+DB *__hash_open(const char *, int, int, const HASHINFO *, int);
+DB *__rec_open(const char *, int, int, const RECNOINFO *, int);
+void __dbpanic(DB *dbp);
+#endif
+__END_DECLS
+#endif /* !_DB_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos-any/err.h b/lib/libc/include/any-macos-any/err.h
new file mode 100644
index 0000000000..8ce50ded57
--- /dev/null
+++ b/lib/libc/include/any-macos-any/err.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2000, 2003, 2004, 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)err.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _ERR_H_
+#define _ERR_H_
+
+/*
+ * Don't use va_list in the err/warn prototypes. Va_list is typedef'd in two
+ * places ( and ), so if we include one
+ * of them here we may collide with the utility's includes. It's unreasonable
+ * for utilities to have to include one of them to include err.h, so we get
+ * __darwin_va_list from and use it.
+ */
+#include
+#include <_types.h>
+#include
+
+__BEGIN_DECLS
+void err(int, const char *, ...) __cold __dead2 __printflike(2, 3);
+void verr(int, const char *, __darwin_va_list) __cold __dead2 __printflike(2, 0);
+void errc(int, int, const char *, ...) __cold __dead2 __printflike(3, 4);
+void verrc(int, int, const char *, __darwin_va_list) __cold __dead2 __printflike(3, 0);
+void errx(int, const char *, ...) __cold __dead2 __printflike(2, 3);
+void verrx(int, const char *, __darwin_va_list) __cold __dead2 __printflike(2, 0);
+void warn(const char *, ...) __cold __printflike(1, 2);
+void vwarn(const char *, __darwin_va_list) __cold __printflike(1, 0);
+void warnc(int, const char *, ...) __cold __printflike(2, 3);
+void vwarnc(int, const char *, __darwin_va_list) __cold __printflike(2, 0);
+void warnx(const char *, ...) __cold __printflike(1, 2);
+void vwarnx(const char *, __darwin_va_list) __cold __printflike(1, 0);
+void err_set_file(void *);
+void err_set_exit(void (* _Nullable)(int));
+#ifdef __BLOCKS__
+void err_set_exit_b(void (^ _Nullable)(int)) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
+#endif /* __BLOCKS__ */
+
+__END_DECLS
+
+#endif /* !_ERR_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos-any/fts.h b/lib/libc/include/any-macos-any/fts.h
new file mode 100644
index 0000000000..ef48eda68b
--- /dev/null
+++ b/lib/libc/include/any-macos-any/fts.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2000, 2003-2006, 2008, 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fts.h 8.3 (Berkeley) 8/14/94
+ */
+
+#ifndef _FTS_H_
+#define _FTS_H_
+
+#include
+#include
+#include
+#include
+
+#include
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wstrict-prototypes"
+
+typedef struct {
+ struct _ftsent *fts_cur; /* current node */
+ struct _ftsent *fts_child; /* linked list of children */
+ struct _ftsent **fts_array; /* sort array */
+ dev_t fts_dev; /* starting device # */
+ char *fts_path; /* path for this descent */
+ int fts_rfd; /* fd for root */
+ int fts_pathlen; /* sizeof(path) */
+ int fts_nitems; /* elements in the sort array */
+#ifdef __BLOCKS__
+ union {
+#endif /* __BLOCKS__ */
+ int (*fts_compar)(); /* compare function */
+#ifdef __BLOCKS__
+ int (^fts_compar_b)(); /* compare block */
+ };
+#endif /* __BLOCKS__ */
+
+#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */
+#define FTS_LOGICAL 0x002 /* logical walk */
+#define FTS_NOCHDIR 0x004 /* don't change directories */
+#define FTS_NOSTAT 0x008 /* don't get stat info */
+#define FTS_PHYSICAL 0x010 /* physical walk */
+#define FTS_SEEDOT 0x020 /* return dot and dot-dot */
+#define FTS_XDEV 0x040 /* don't cross devices */
+#define FTS_WHITEOUT 0x080 /* (no longer supported) return whiteout information */
+#define FTS_COMFOLLOWDIR 0x400 /* (non-std) follow command line symlinks for directories only */
+#if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1090) || (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 70000)
+#define FTS_OPTIONMASK 0x4ff /* valid user option mask */
+#else
+#define FTS_NOSTAT_TYPE 0x800 /* (non-std) no stat, but use d_type in struct dirent when available */
+#define FTS_OPTIONMASK 0xcff /* valid user option mask */
+#endif
+
+#define FTS_NAMEONLY 0x100 /* (private) child names only */
+#define FTS_STOP 0x200 /* (private) unrecoverable error */
+#ifdef __BLOCKS__
+#define FTS_BLOCK_COMPAR 0x80000000 /* fts_compar is a block */
+#endif /* __BLOCKS__ */
+ int fts_options; /* fts_open options, global flags */
+} FTS;
+
+typedef struct _ftsent {
+ struct _ftsent *fts_cycle; /* cycle node */
+ struct _ftsent *fts_parent; /* parent directory */
+ struct _ftsent *fts_link; /* next file in directory */
+ long fts_number; /* local numeric value */
+ void *fts_pointer; /* local address value */
+ char *fts_accpath; /* access path */
+ char *fts_path; /* root path */
+ int fts_errno; /* errno for this node */
+ int fts_symfd; /* fd for symlink or chdir */
+ unsigned short fts_pathlen; /* strlen(fts_path) */
+ unsigned short fts_namelen; /* strlen(fts_name) */
+
+ ino_t fts_ino; /* inode */
+ dev_t fts_dev; /* device */
+ nlink_t fts_nlink; /* link count */
+
+#define FTS_ROOTPARENTLEVEL -1
+#define FTS_ROOTLEVEL 0
+#define FTS_MAXLEVEL 0x7fffffff
+ short fts_level; /* depth (-1 to N) */
+
+#define FTS_D 1 /* preorder directory */
+#define FTS_DC 2 /* directory that causes cycles */
+#define FTS_DEFAULT 3 /* none of the above */
+#define FTS_DNR 4 /* unreadable directory */
+#define FTS_DOT 5 /* dot or dot-dot */
+#define FTS_DP 6 /* postorder directory */
+#define FTS_ERR 7 /* error; errno is set */
+#define FTS_F 8 /* regular file */
+#define FTS_INIT 9 /* initialized only */
+#define FTS_NS 10 /* stat(2) failed */
+#define FTS_NSOK 11 /* no stat(2) requested */
+#define FTS_SL 12 /* symbolic link */
+#define FTS_SLNONE 13 /* symbolic link without target */
+#define FTS_W 14 /* whiteout object */
+ unsigned short fts_info; /* user flags for FTSENT structure */
+
+#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
+#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
+#define FTS_ISW 0x04 /* this is a whiteout object */
+#define FTS_CHDIRFD 0x08 /* indicates the fts_symfd field was set for chdir */
+ unsigned short fts_flags; /* private flags for FTSENT structure */
+
+#define FTS_AGAIN 1 /* read node again */
+#define FTS_FOLLOW 2 /* follow symbolic link */
+#define FTS_NOINSTR 3 /* no instructions */
+#define FTS_SKIP 4 /* discard node */
+ unsigned short fts_instr; /* fts_set() instructions */
+
+ struct stat *fts_statp; /* stat(2) information */
+ char fts_name[1]; /* file name */
+} FTSENT;
+
+#include
+#include
+
+__BEGIN_DECLS
+FTSENT *fts_children(FTS *, int) __DARWIN_INODE64(fts_children);
+int fts_close(FTS *) __DARWIN_INODE64(fts_close);
+FTS *fts_open(char * const *, int,
+ int (*)(const FTSENT **, const FTSENT **)) __DARWIN_INODE64(fts_open);
+#ifdef __BLOCKS__
+#if __has_attribute(noescape)
+#define __fts_noescape __attribute__((__noescape__))
+#else
+#define __fts_noescape
+#endif
+FTS *fts_open_b(char * const *, int,
+ int (^)(const FTSENT **, const FTSENT **) __fts_noescape)
+ __DARWIN_INODE64(fts_open_b) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
+#endif /* __BLOCKS__ */
+FTSENT *fts_read(FTS *) __DARWIN_INODE64(fts_read);
+int fts_set(FTS *, FTSENT *, int) __DARWIN_INODE64(fts_set);
+__END_DECLS
+
+#pragma clang diagnostic pop
+#endif /* !_FTS_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos-any/iso646.h b/lib/libc/include/any-macos-any/iso646.h
new file mode 100644
index 0000000000..8bde15b8c1
--- /dev/null
+++ b/lib/libc/include/any-macos-any/iso646.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 1998 Alex Nash
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/include/iso646.h,v 1.4 2002/09/18 22:23:59 mike Exp $
+ */
+
+#ifndef _ISO646_H_
+#define _ISO646_H_
+
+#include
+
+#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
+
+#ifndef __cplusplus
+#define and &&
+#define and_eq &=
+#define bitand &
+#define bitor |
+#define compl ~
+#define not !
+#define not_eq !=
+#define or ||
+#define or_eq |=
+#define xor ^
+#define xor_eq ^=
+#endif /* ! __cplusplus */
+
+#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
+
+#endif /* !_ISO646_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos-any/libkern/OSCacheControl.h b/lib/libc/include/any-macos-any/libkern/OSCacheControl.h
new file mode 100644
index 0000000000..aff4af84ae
--- /dev/null
+++ b/lib/libc/include/any-macos-any/libkern/OSCacheControl.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _OS_CACHE_CONTROL_H_
+#define _OS_CACHE_CONTROL_H_
+
+#include
+#include
+#include
+#include
+
+__BEGIN_DECLS
+
+
+/* Functions performed by sys_cache_control(): */
+
+/* Prepare memory for execution. This should be called
+ * after writing machine instructions to memory, before
+ * executing them. It syncs the dcache and icache.
+ * On IA32 processors this function is a NOP, because
+ * no synchronization is required.
+ */
+#define kCacheFunctionPrepareForExecution 1
+
+/* Flush data cache(s). This ensures that cached data
+ * makes it all the way out to DRAM, and then removes
+ * copies of the data from all processor caches.
+ * It can be useful when dealing with cache incoherent
+ * devices or DMA.
+ */
+#define kCacheFunctionFlushDcache 2
+
+
+/* perform one of the above cache functions: */
+int sys_cache_control( int function, void *start, size_t len) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+
+/* equivalent to sys_cache_control(kCacheFunctionPrepareForExecution): */
+void sys_icache_invalidate( void *start, size_t len) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+
+/* equivalent to sys_cache_control(kCacheFunctionFlushDcache): */
+void sys_dcache_flush( void *start, size_t len) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+
+
+__END_DECLS
+
+#endif /* _OS_CACHE_CONTROL_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos-any/libkern/OSDebug.h b/lib/libc/include/any-macos-any/libkern/OSDebug.h
new file mode 100644
index 0000000000..e0eb5d7c0b
--- /dev/null
+++ b/lib/libc/include/any-macos-any/libkern/OSDebug.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * HISTORY
+ *
+ */
+
+#ifndef _OS_OSDEBBUG_H
+#define _OS_OSDEBBUG_H
+
+#include
+#include
+
+__BEGIN_DECLS
+
+/* Report a message with a 4 entry backtrace - very slow */
+extern void OSReportWithBacktrace(const char *str, ...) __printflike(1, 2);
+extern unsigned OSBacktrace(void **bt, unsigned maxAddrs);
+
+/* Simple dump of 20 backtrace entries */
+extern void OSPrintBacktrace(void);
+
+/*! @function OSKernelStackRemaining
+ * @abstract Returns bytes available below the current stack frame.
+ * @discussion Returns bytes available below the current stack frame. Safe for interrupt or thread context.
+ * @result Approximate byte count available. */
+
+vm_offset_t OSKernelStackRemaining( void );
+
+__END_DECLS
+
+#endif /* !_OS_OSDEBBUG_H */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos-any/libkern/OSKextLib.h b/lib/libc/include/any-macos-any/libkern/OSKextLib.h
new file mode 100644
index 0000000000..d7e73577e9
--- /dev/null
+++ b/lib/libc/include/any-macos-any/libkern/OSKextLib.h
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#ifndef _LIBKERN_OSKEXTLIB_H
+#define _LIBKERN_OSKEXTLIB_H
+
+#include
+__BEGIN_DECLS
+
+#include
+#include
+#include
+#include
+
+#include
+
+/*!
+ * @header
+ *
+ * Declares functions, basic return values, and other constants
+ * related to kernel extensions (kexts).
+ */
+
+#if PRAGMA_MARK
+#pragma mark -
+/********************************************************************/
+#pragma mark OSReturn Values for Kernel Extensions
+/********************************************************************/
+#endif
+/*!
+ * @group OSReturn Values for Kernel Extensions
+ * Many kext-related functions return these values,
+ * as well as those defined under
+ * @link //apple_ref/c/tdef/OSReturn OSReturn@/link
+ * and other variants of kern_return_t.
+ */
+
+
+#define sub_libkern_kext err_sub(2)
+#define libkern_kext_err(code) (sys_libkern|sub_libkern_kext|(code))
+
+
+/*!
+ * @define kOSKextReturnInternalError
+ * @abstract An internal error in the kext library.
+ * Contrast with @link //apple_ref/c/econst/OSReturnError
+ * OSReturnError@/link.
+ */
+#define kOSKextReturnInternalError libkern_kext_err(0x1)
+
+/*!
+ * @define kOSKextReturnNoMemory
+ * @abstract Memory allocation failed.
+ */
+#define kOSKextReturnNoMemory libkern_kext_err(0x2)
+
+/*!
+ * @define kOSKextReturnNoResources
+ * @abstract Some resource other than memory (such as available load tags)
+ * is exhausted.
+ */
+#define kOSKextReturnNoResources libkern_kext_err(0x3)
+
+/*!
+ * @define kOSKextReturnNotPrivileged
+ * @abstract The caller lacks privileges to perform the requested operation.
+ */
+#define kOSKextReturnNotPrivileged libkern_kext_err(0x4)
+
+/*!
+ * @define kOSKextReturnInvalidArgument
+ * @abstract Invalid argument.
+ */
+#define kOSKextReturnInvalidArgument libkern_kext_err(0x5)
+
+/*!
+ * @define kOSKextReturnNotFound
+ * @abstract Search item not found.
+ */
+#define kOSKextReturnNotFound libkern_kext_err(0x6)
+
+/*!
+ * @define kOSKextReturnBadData
+ * @abstract Malformed data (not used for XML).
+ */
+#define kOSKextReturnBadData libkern_kext_err(0x7)
+
+/*!
+ * @define kOSKextReturnSerialization
+ * @abstract Error converting or (un)serializing URL, string, or XML.
+ */
+#define kOSKextReturnSerialization libkern_kext_err(0x8)
+
+/*!
+ * @define kOSKextReturnUnsupported
+ * @abstract Operation is no longer or not yet supported.
+ */
+#define kOSKextReturnUnsupported libkern_kext_err(0x9)
+
+/*!
+ * @define kOSKextReturnDisabled
+ * @abstract Operation is currently disabled.
+ */
+#define kOSKextReturnDisabled libkern_kext_err(0xa)
+
+/*!
+ * @define kOSKextReturnNotAKext
+ * @abstract Bundle is not a kernel extension.
+ */
+#define kOSKextReturnNotAKext libkern_kext_err(0xb)
+
+/*!
+ * @define kOSKextReturnValidation
+ * @abstract Validation failures encountered; check diagnostics for details.
+ */
+#define kOSKextReturnValidation libkern_kext_err(0xc)
+
+/*!
+ * @define kOSKextReturnAuthentication
+ * @abstract Authetication failures encountered; check diagnostics for details.
+ */
+#define kOSKextReturnAuthentication libkern_kext_err(0xd)
+
+/*!
+ * @define kOSKextReturnDependencies
+ * @abstract Dependency resolution failures encountered; check diagnostics for details.
+ */
+#define kOSKextReturnDependencies libkern_kext_err(0xe)
+
+/*!
+ * @define kOSKextReturnArchNotFound
+ * @abstract Kext does not contain code for the requested architecture.
+ */
+#define kOSKextReturnArchNotFound libkern_kext_err(0xf)
+
+/*!
+ * @define kOSKextReturnCache
+ * @abstract An error occurred processing a system kext cache.
+ */
+#define kOSKextReturnCache libkern_kext_err(0x10)
+
+/*!
+ * @define kOSKextReturnDeferred
+ * @abstract Operation has been posted asynchronously to user space (kernel only).
+ */
+#define kOSKextReturnDeferred libkern_kext_err(0x11)
+
+/*!
+ * @define kOSKextReturnBootLevel
+ * @abstract Kext not loadable or operation not allowed at current boot level.
+ */
+#define kOSKextReturnBootLevel libkern_kext_err(0x12)
+
+/*!
+ * @define kOSKextReturnNotLoadable
+ * @abstract Kext cannot be loaded; check diagnostics for details.
+ */
+#define kOSKextReturnNotLoadable libkern_kext_err(0x13)
+
+/*!
+ * @define kOSKextReturnLoadedVersionDiffers
+ * @abstract A different version (or executable UUID, or executable by checksum)
+ * of the requested kext is already loaded.
+ */
+#define kOSKextReturnLoadedVersionDiffers libkern_kext_err(0x14)
+
+/*!
+ * @define kOSKextReturnDependencyLoadError
+ * @abstract A load error occurred on a dependency of the kext being loaded.
+ */
+#define kOSKextReturnDependencyLoadError libkern_kext_err(0x15)
+
+/*!
+ * @define kOSKextReturnLinkError
+ * @abstract A link failure occured with this kext or a dependency.
+ */
+#define kOSKextReturnLinkError libkern_kext_err(0x16)
+
+/*!
+ * @define kOSKextReturnStartStopError
+ * @abstract The kext start or stop routine returned an error.
+ */
+#define kOSKextReturnStartStopError libkern_kext_err(0x17)
+
+/*!
+ * @define kOSKextReturnInUse
+ * @abstract The kext is currently in use or has outstanding references,
+ * and cannot be unloaded.
+ */
+#define kOSKextReturnInUse libkern_kext_err(0x18)
+
+/*!
+ * @define kOSKextReturnTimeout
+ * @abstract A kext request has timed out.
+ */
+#define kOSKextReturnTimeout libkern_kext_err(0x19)
+
+/*!
+ * @define kOSKextReturnStopping
+ * @abstract The kext is in the process of stopping; requests cannot be made.
+ */
+#define kOSKextReturnStopping libkern_kext_err(0x1a)
+
+/*!
+ * @define kOSKextReturnSystemPolicy
+ * @abstract The kext was prevented from loading due to system policy.
+ */
+#define kOSKextReturnSystemPolicy libkern_kext_err(0x1b)
+
+/*!
+ * @define kOSKextReturnKCLoadFailure
+ * @abstract Loading of the System KC failed
+ */
+#define kOSKextReturnKCLoadFailure libkern_kext_err(0x1c)
+
+/*!
+ * @define kOSKextReturnKCLoadFailureSystemKC
+ * @abstract Loading of the System KC failed
+ *
+ * This a sub-code of kOSKextReturnKCLoadFailure. It can be OR'd together
+ * with: kOSKextReturnKCLoadFailureAuxKC
+ *
+ * If both the System and Aux KCs fail to load, then the error code will be:
+ * libkern_kext_err(0x1f)
+ */
+#define kOSKextReturnKCLoadFailureSystemKC libkern_kext_err(0x1d)
+
+/*!
+ * @define kOSKextReturnKCLoadFailureAuxKC
+ * @abstract Loading of the Aux KC failed
+ *
+ * This a sub-code of kOSKextReturnKCLoadFailure. It can be OR'd together
+ * with: kOSKextReturnKCLoadFailureSystemKC
+ *
+ * If both the System and Aux KCs fail to load, then the error code will be:
+ * libkern_kext_err(0x1f)
+ */
+#define kOSKextReturnKCLoadFailureAuxKC libkern_kext_err(0x1e)
+
+/* next available error is: libkern_kext_err(0x20) */
+
+#if PRAGMA_MARK
+#pragma mark -
+/********************************************************************/
+#pragma mark Kext/OSBundle Property List Keys
+/********************************************************************/
+#endif
+/*!
+ * @group Kext Property List Keys
+ * These constants cover CFBundle properties defined for kernel extensions.
+ * Because they are used in the kernel, if you want to use one with
+ * CFBundle APIs you'll need to wrap it in a CFSTR() macro.
+ */
+
+
+/*!
+ * @define kOSBundleCompatibleVersionKey
+ * @abstract A string giving the backwards-compatible version of a library kext
+ * in extended Mac OS 'vers' format (####.##.##s{1-255} where 's'
+ * is a build stage 'd', 'a', 'b', 'f' or 'fc').
+ */
+#define kOSBundleCompatibleVersionKey "OSBundleCompatibleVersion"
+
+/*!
+ * @define kOSBundleEnableKextLoggingKey
+ * @abstract Set to true to have the kernel kext logging spec applied
+ * to the kext.
+ * See @link //apple_ref/c/econst/OSKextLogSpec
+ * OSKextLogSpec@/link.
+ */
+#define kOSBundleEnableKextLoggingKey "OSBundleEnableKextLogging"
+
+/*!
+ * @define kOSBundleIsInterfaceKey
+ * @abstract A boolean value indicating whether the kext executable
+ * contains only symbol references.
+ */
+#define kOSBundleIsInterfaceKey "OSBundleIsInterface"
+
+/*!
+ * @define kOSBundleLibrariesKey
+ * @abstract A dictionary listing link dependencies for this kext.
+ * Keys are bundle identifiers, values are version strings.
+ */
+#define kOSBundleLibrariesKey "OSBundleLibraries"
+
+/*!
+ * @define kOSBundleRequiredKey
+ * @abstract A string indicating in which kinds of startup this kext
+ * may need to load during early startup (before
+ * @link //apple_ref/doc/man/8/kextd kextcache(8)@/link).
+ * @discussion
+ * The value is one of:
+ *
+ * - @link kOSBundleRequiredRoot "OSBundleRequiredRoot"@/link
+ * - @link kOSBundleRequiredLocalRoot "OSBundleRequiredLocalRoot"@/link
+ * - @link kOSBundleRequiredNetworkRoot "OSBundleRequiredNetworkRoot"@/link
+ * - @link kOSBundleRequiredSafeBoot "OSBundleRequiredSafeBoot"@/link
+ * - @link kOSBundleRequiredConsole "OSBundleRequiredConsole"@/link
+ *
+ *
+ * Use this property judiciously.
+ * Every kext that declares a value other than "OSBundleRequiredSafeBoot"
+ * increases startup time, as the booter must read it into memory,
+ * or startup kext caches must include it.
+ */
+#define kOSBundleRequiredKey "OSBundleRequired"
+
+/*!
+ * @define kOSBundleRequireExplicitLoadKey
+ * @abstract A boolean value indicating whether the kext requires an
+ * explicit kextload in order to start/match.
+ */
+#define kOSBundleRequireExplicitLoadKey "OSBundleRequireExplicitLoad"
+
+/*!
+ * @define kOSBundleAllowUserLoadKey
+ * @abstract A boolean value indicating whether
+ * @link //apple_ref/doc/man/8/kextd kextcache(8)@/link
+ * will honor a non-root process's request to load a kext.
+ * @discussion
+ * See @link //apple_ref/doc/compositePage/c/func/KextManagerLoadKextWithURL
+ * KextManagerLoadKextWithURL@/link
+ * and @link //apple_ref/doc/compositePage/c/func/KextManagerLoadKextWithIdentifier
+ * KextManagerLoadKextWithIdentifier@/link.
+ */
+#define kOSBundleAllowUserLoadKey "OSBundleAllowUserLoad"
+
+/*!
+ * @define kOSBundleAllowUserTerminateKey
+ * @abstract A boolean value indicating whether the kextunload tool
+ * is allowed to issue IOService terminate to classes defined in this kext.
+ * @discussion A boolean value indicating whether the kextunload tool
+ * is allowed to issue IOService terminate to classes defined in this kext.
+ */
+#define kOSBundleAllowUserTerminateKey "OSBundleAllowUserTerminate"
+
+/*!
+ * @define kOSKernelResourceKey
+ * @abstract A boolean value indicating whether the kext represents a built-in
+ * component of the kernel.
+ */
+#define kOSKernelResourceKey "OSKernelResource"
+
+/*!
+ * @define kOSKextVariantOverrideKey
+ * @abstract A dictionary with target names as key and a target-specific variant
+ * name as value.
+ */
+#define kOSKextVariantOverrideKey "OSKextVariantOverride"
+
+/*!
+ * @define kIOKitPersonalitiesKey
+ * @abstract A dictionary of dictionaries used in matching for I/O Kit drivers.
+ */
+#define kIOKitPersonalitiesKey "IOKitPersonalities"
+
+/*
+ * @define kIOPersonalityPublisherKey
+ * @abstract Used in personalities sent to the I/O Kit,
+ * contains the CFBundleIdentifier of the kext
+ * that the personality originated in.
+ */
+#define kIOPersonalityPublisherKey "IOPersonalityPublisher"
+
+#if CONFIG_KEC_FIPS
+/*
+ * @define kAppleTextHashesKey
+ * @abstract A dictionary conataining hashes for corecrypto kext.
+ */
+#define kAppleTextHashesKey "AppleTextHashes"
+#endif
+
+/*!
+ * @define kOSMutableSegmentCopy
+ * @abstract A boolean value indicating whether the kext requires a copy of
+ * its mutable segments to be kept in memory, and then reset when the kext
+ * unloads. This should be used with caution as it will increase the
+ * amount of memory used by the kext.
+ */
+#define kOSMutableSegmentCopy "OSMutableSegmentCopy"
+
+
+#if PRAGMA_MARK
+/********************************************************************/
+#pragma mark Kext/OSBundle Property Deprecated Keys
+/********************************************************************/
+#endif
+/*
+ * @define kOSBundleDebugLevelKey
+ * @abstract
+ * Deprecated (used on some releases of Mac OS X prior to 10.6 Snow Leopard).
+ * Value is an integer from 1-6, corresponding to the verbose levels
+ * of kext tools on those releases.
+ * On 10.6 Snow Leopard, use @link OSKextEnableKextLogging
+ * OSKextEnableKextLogging@/link.
+ */
+#define kOSBundleDebugLevelKey "OSBundleDebugLevel"
+
+/*!
+ * @define kOSBundleSharedExecutableIdentifierKey
+ * @abstract Deprecated (used on some releases of Mac OS X
+ * prior to 10.6 Snow Leopard).
+ * Value is the bundle identifier of the pseudokext
+ * that contains an executable shared by this kext.
+ */
+#define kOSBundleSharedExecutableIdentifierKey "OSBundleSharedExecutableIdentifier"
+
+
+#if PRAGMA_MARK
+/********************************************************************/
+#pragma mark Kext/OSBundle Property List Values
+/********************************************************************/
+#endif
+
+/*!
+ * @group Kext Property List Values
+ * These constants encompass established values
+ * for kernel extension bundle properties.
+ */
+
+/*!
+ * @define kOSKextKernelIdentifier
+ * @abstract
+ * This is the CFBundleIdentifier user for the kernel itself.
+ */
+#define kOSKextKernelIdentifier "__kernel__"
+
+/*!
+ * @define kOSKextBundlePackageTypeKext
+ * @abstract
+ * The bundle type value for Kernel Extensions.
+ */
+#define kOSKextBundlePackageTypeKext "KEXT"
+
+/*!
+ * @define kOSKextBundlePackageTypeDriverKit
+ * @abstract
+ * The bundle type value for Driver Extensions.
+ */
+#define kOSKextBundlePackageTypeDriverKit "DEXT"
+
+/*!
+ * @define kOSBundleRequiredRoot
+ * @abstract
+ * This @link kOSBundleRequiredKey OSBundleRequired@/link
+ * value indicates that the kext may be needed to mount the root filesystem
+ * whether starting from a local or a network volume.
+ */
+#define kOSBundleRequiredRoot "Root"
+
+/*!
+ * @define kOSBundleRequiredLocalRoot
+ * @abstract
+ * This @link kOSBundleRequiredKey OSBundleRequired@/link
+ * value indicates that the kext may be needed to mount the root filesystem
+ * when starting from a local disk.
+ */
+#define kOSBundleRequiredLocalRoot "Local-Root"
+
+/*!
+ * @define kOSBundleRequiredNetworkRoot
+ * @abstract
+ * This @link kOSBundleRequiredKey OSBundleRequired@/link
+ * value indicates that the kext may be needed to mount the root filesystem
+ * when starting over a network connection.
+ */
+#define kOSBundleRequiredNetworkRoot "Network-Root"
+
+/*!
+ * @define kOSBundleRequiredSafeBoot
+ * @abstract
+ * This @link kOSBundleRequiredKey OSBundleRequired@/link
+ * value indicates that the kext can be loaded during a safe startup.
+ * This value does not normally cause the kext to be read by the booter
+ * or included in startup kext caches.
+ */
+#define kOSBundleRequiredSafeBoot "Safe Boot"
+
+/*!
+ * @define kOSBundleRequiredConsole
+ * @abstract
+ * This @link kOSBundleRequiredKey OSBundleRequired@/link
+ * value indicates that the kext may be needed for console access
+ * (specifically in a single-user startup when
+ * @link //apple_ref/doc/man/8/kextd kextd(8)@/link.
+ * does not run)
+ * and should be loaded during early startup.
+ */
+#define kOSBundleRequiredConsole "Console"
+
+/*!
+ * @define kOSBundleRequiredDriverKit
+ * @abstract
+ * This @link kOSBundleRequiredKey OSBundleRequired@/link
+ * value indicates that the driver extension's (DriverKit driver's)
+ * personalities must be present in the kernel at early boot (specifically
+ * before @link //apple_ref/doc/man/8/kextd kextd(8)@/link starts)
+ * in order to compete with kexts built into the prelinkedkernel. Note that
+ * kextd is still required to launch the user space driver binary. The IOKit
+ * matching will happen during early boot, and the actual driver launch
+ * will happen after kextd starts.
+ */
+#define kOSBundleRequiredDriverKit "DriverKit"
+
+#if PRAGMA_MARK
+#pragma mark -
+/********************************************************************/
+#pragma mark Kext Information
+/********************************************************************/
+#endif
+/*!
+ * @group Kext Information
+ * Types, constants, and macros providing a kext with information
+ * about itself.
+ */
+
+/*!
+ * @typedef OSKextLoadTag
+ *
+ * @abstract
+ * A unique identifier assigned to a loaded instanace of a kext.
+ *
+ * @discussion
+ * If a kext is unloaded and later reloaded, the new instance
+ * has a different load tag.
+ *
+ * A kext can get its own load tag in the kmod_info_t
+ * structure passed into its module start routine, as the
+ * id field (cast to this type).
+ */
+typedef uint32_t OSKextLoadTag;
+
+/*!
+ * @define kOSKextInvalidLoadTag
+ *
+ * @abstract
+ * A load tag value that will never be used for a loaded kext;
+ * indicates kext not found.
+ */
+#define kOSKextInvalidLoadTag ((OSKextLoadTag)(-1))
+
+
+__END_DECLS
+
+#endif /* _LIBKERN_OSKEXTLIB_H */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos-any/libkern/OSReturn.h b/lib/libc/include/any-macos-any/libkern/OSReturn.h
new file mode 100644
index 0000000000..e357300e89
--- /dev/null
+++ b/lib/libc/include/any-macos-any/libkern/OSReturn.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2000 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1998 Apple Inc. All rights reserved.
+ *
+ * HISTORY
+ *
+ */
+
+/*
+ * Core OSReturn values.
+ */
+
+#ifndef __LIBKERN_OSRETURN_H
+#define __LIBKERN_OSRETURN_H
+
+#include
+
+__BEGIN_DECLS
+
+#include
+
+
+/*!
+ * @header
+ *
+ * Declares functions, basic return values, and other constants
+ * related to kernel extensions (kexts).
+ */
+
+#if PRAGMA_MARK
+#pragma mark Core OSReturn Values for Libkern
+#endif
+/*********************************************************************
+* Core OSReturn Values for Libkern
+*********************************************************************/
+/*!
+ * @group Core OSReturn Values for Libkern
+ * Some kext and I/O Kit functions can return these values,
+ * as well as other values of
+ * kern_return_t.
+ *
+ * Many of these return values represent internal errors
+ * in the Libkern C++ run-time typing information system
+ * based on @link //apple_ref/doc/class/OSMetaClass OSMetaClass@/link;
+ * you are unlikely to ever see them.
+ *
+ */
+
+
+/*!
+ * @typedef OSReturn
+ * @abstract The return type for many Libkern functions.
+ */
+typedef kern_return_t OSReturn;
+
+#ifndef sys_libkern
+#define sys_libkern err_system(0x37)
+#endif /* sys_libkern */
+
+#define sub_libkern_common err_sub(0)
+#define sub_libkern_metaclass err_sub(1)
+#define sub_libkern_reserved err_sub(-1)
+
+#define libkern_common_err(return ) (sys_libkern|sub_libkern_common|(return))
+#define libkern_metaclass_err(return ) (sys_libkern|sub_libkern_metaclass|(return))
+
+/* See OSKextLib.h for these
+ * #define sub_libkern_kext err_sub(2)
+ * #define libkern_kext_err(code) (sys_libkern|sub_libkern_kext|(code))
+ */
+
+/*!
+ * @define kOSReturnSuccess
+ * @abstract Operation successful.
+ * Equal to @link //apple_ref/c/econst/KERN_SUCCESS
+ * KERN_SUCCESS@/link.
+ */
+#define kOSReturnSuccess KERN_SUCCESS
+
+/*!
+ * @define kOSReturnError
+ * @abstract Unspecified Libkern error.
+ * Not equal to
+ * @link //apple_ref/c/econst/KERN_FAILURE
+ * KERN_FAILURE@/link.
+ */
+#define kOSReturnError libkern_common_err(1)
+
+/*!
+ * @define kOSMetaClassInternal
+ * @abstract Internal OSMetaClass run-time error.
+ */
+#define kOSMetaClassInternal libkern_metaclass_err(1)
+
+/*!
+ * @define kOSMetaClassHasInstances
+ * @abstract A kext cannot be unloaded because there are instances
+ * derived from Libkern C++ classes that it defines.
+ */
+#define kOSMetaClassHasInstances libkern_metaclass_err(2)
+
+/*!
+ * @define kOSMetaClassNoInit
+ * @abstract Internal error: The Libkern C++ class registration system
+ * was not properly initialized during kext loading.
+ */
+#define kOSMetaClassNoInit libkern_metaclass_err(3)
+// OSMetaClass::preModLoad wasn't called, runtime internal error
+
+/*!
+ * @define kOSMetaClassNoTempData
+ * @abstract Internal error: An allocation failure occurred
+ * registering Libkern C++ classes during kext loading.
+ */
+#define kOSMetaClassNoTempData libkern_metaclass_err(4)
+// Allocation failure internal data
+
+/*!
+ * @define kOSMetaClassNoDicts
+ * @abstract Internal error: An allocation failure occurred
+ * registering Libkern C++ classes during kext loading.
+ */
+#define kOSMetaClassNoDicts libkern_metaclass_err(5)
+// Allocation failure for Metaclass internal dictionaries
+
+/*!
+ * @define kOSMetaClassNoKModSet
+ * @abstract Internal error: An allocation failure occurred
+ * registering Libkern C++ classes during kext loading.
+ */
+#define kOSMetaClassNoKModSet libkern_metaclass_err(6)
+// Allocation failure for internal kmodule set
+
+/*!
+ * @define kOSMetaClassNoInsKModSet
+ * @abstract Internal error: An error occurred registering
+ * a specific Libkern C++ class during kext loading.
+ */
+#define kOSMetaClassNoInsKModSet libkern_metaclass_err(7)
+// Can't insert the KMod set into the module dictionary
+
+/*!
+ * @define kOSMetaClassNoSuper
+ * @abstract Internal error: No superclass can be found
+ * for a specific Libkern C++ class during kext loading.
+ */
+#define kOSMetaClassNoSuper libkern_metaclass_err(8)
+
+/*!
+ * @define kOSMetaClassInstNoSuper
+ * @abstract Internal error: No superclass can be found when constructing
+ * an instance of a Libkern C++ class.
+ */
+#define kOSMetaClassInstNoSuper libkern_metaclass_err(9)
+
+/*!
+ * @define kOSMetaClassDuplicateClass
+ * @abstract A duplicate Libkern C++ classname was encountered
+ * during kext loading.
+ */
+#define kOSMetaClassDuplicateClass libkern_metaclass_err(10)
+
+/*!
+ * @define kOSMetaClassNoKext
+ * @abstract Internal error: The kext for a Libkern C++ class
+ * can't be found during kext loading.
+ */
+#define kOSMetaClassNoKext libkern_metaclass_err(11)
+
+__END_DECLS
+
+#endif /* ! __LIBKERN_OSRETURN_H */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos-any/libkern/OSThermalNotification.h b/lib/libc/include/any-macos-any/libkern/OSThermalNotification.h
new file mode 100644
index 0000000000..ca533a0204
--- /dev/null
+++ b/lib/libc/include/any-macos-any/libkern/OSThermalNotification.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _OSTHERMALNOTIFICATION_H_
+#define _OSTHERMALNOTIFICATION_H_
+
+#include
+#include
+
+/*
+** OSThermalNotification.h
+**
+** Notification mechanism to alert registered tasks when device thermal conditions
+** reach certain thresholds. Notifications are triggered in both directions
+** so clients can manage their memory usage more and less aggressively.
+**
+*/
+
+__BEGIN_DECLS
+
+/* Define pressure levels usable by OSThermalPressureLevel */
+typedef enum {
+#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
+ kOSThermalPressureLevelNominal = 0,
+ kOSThermalPressureLevelModerate,
+ kOSThermalPressureLevelHeavy,
+ kOSThermalPressureLevelTrapping,
+ kOSThermalPressureLevelSleeping
+#else
+ kOSThermalPressureLevelNominal = 0,
+ kOSThermalPressureLevelLight = 10,
+ kOSThermalPressureLevelModerate = 20,
+ kOSThermalPressureLevelHeavy = 30,
+ kOSThermalPressureLevelTrapping = 40,
+ kOSThermalPressureLevelSleeping = 50
+#endif
+} OSThermalPressureLevel;
+
+/*
+ ** External notify(3) string for thermal pressure level notification
+ */
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0)
+extern const char * const kOSThermalNotificationPressureLevelName;
+
+
+#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && \
+ __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_2_0
+
+typedef enum {
+ OSThermalNotificationLevelAny = -1,
+ OSThermalNotificationLevelNormal = 0,
+} OSThermalNotificationLevel;
+
+extern OSThermalNotificationLevel _OSThermalNotificationLevelForBehavior(int) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_4_2);
+extern void _OSThermalNotificationSetLevelForBehavior(int, int) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_4_2);
+
+enum {
+ kOSThermalMitigationNone,
+ kOSThermalMitigation70PercentTorch,
+ kOSThermalMitigation70PercentBacklight,
+ kOSThermalMitigation50PercentTorch,
+ kOSThermalMitigation50PercentBacklight,
+ kOSThermalMitigationDisableTorch,
+ kOSThermalMitigation25PercentBacklight,
+ kOSThermalMitigationDisableMapsHalo,
+ kOSThermalMitigationAppTerminate,
+ kOSThermalMitigationDeviceRestart,
+ kOSThermalMitigationThermalTableReady,
+ kOSThermalMitigationCount
+};
+
+#define OSThermalNotificationLevel70PercentTorch _OSThermalNotificationLevelForBehavior(kOSThermalMitigation70PercentTorch)
+#define OSThermalNotificationLevel70PercentBacklight _OSThermalNotificationLevelForBehavior(kOSThermalMitigation70PercentBacklight)
+#define OSThermalNotificationLevel50PercentTorch _OSThermalNotificationLevelForBehavior(kOSThermalMitigation50PercentTorch)
+#define OSThermalNotificationLevel50PercentBacklight _OSThermalNotificationLevelForBehavior(kOSThermalMitigation50PercentBacklight)
+#define OSThermalNotificationLevelDisableTorch _OSThermalNotificationLevelForBehavior(kOSThermalMitigationDisableTorch)
+#define OSThermalNotificationLevel25PercentBacklight _OSThermalNotificationLevelForBehavior(kOSThermalMitigation25PercentBacklight)
+#define OSThermalNotificationLevelDisableMapsHalo _OSThermalNotificationLevelForBehavior(kOSThermalMitigationDisableMapsHalo)
+#define OSThermalNotificationLevelAppTerminate _OSThermalNotificationLevelForBehavior(kOSThermalMitigationAppTerminate)
+#define OSThermalNotificationLevelDeviceRestart _OSThermalNotificationLevelForBehavior(kOSThermalMitigationDeviceRestart)
+
+/* Backwards compatibility */
+#define OSThermalNotificationLevelWarning OSThermalNotificationLevel70PercentBacklight
+#define OSThermalNotificationLevelUrgent OSThermalNotificationLevelAppTerminate
+#define OSThermalNotificationLevelCritical OSThermalNotificationLevelDeviceRestart
+
+/*
+** Simple polling interface to detect current thermal level
+*/
+__OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_2_0)
+extern OSThermalNotificationLevel OSThermalNotificationCurrentLevel(void);
+
+/*
+** External notify(3) string for manual notification setup
+*/
+__OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_2_0)
+extern const char * const kOSThermalNotificationName;
+
+/*
+** External notify(3) string for alerting user of a thermal condition
+*/
+__OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_6_0)
+extern const char * const kOSThermalNotificationAlert;
+
+/*
+** External notify(3) string for notifying system the options taken to resolve thermal condition
+*/
+__OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_6_0)
+extern const char * const kOSThermalNotificationDecision;
+
+#endif // __IPHONE_OS_VERSION_MIN_REQUIRED
+
+__END_DECLS
+
+#endif /* _OSTHERMALNOTIFICATION_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos-any/stddef.h b/lib/libc/include/any-macos-any/stddef.h
new file mode 100644
index 0000000000..eedc6f46a0
--- /dev/null
+++ b/lib/libc/include/any-macos-any/stddef.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/* $OpenBSD: stddef.h,v 1.2 1997/09/21 10:45:52 niklas Exp $ */
+/* $NetBSD: stddef.h,v 1.4 1994/10/26 00:56:26 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)stddef.h 5.5 (Berkeley) 4/3/91
+ */
+
+#ifndef __STDDEF_H__
+#define __STDDEF_H__
+
+#include <_types.h>
+
+#include
+#include
+#include
+#include
+
+#if defined(__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ >= 1
+#include
+#endif /* __STDC_WANT_LIB_EXT1__ >= 1 */
+
+/* DO NOT REMOVE THIS COMMENT: fixincludes needs to see:
+ * _GCC_SIZE_T */
+#include
+
+#include
+
+#if !defined(_ANSI_SOURCE) && (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
+#include
+#endif /* !_ANSI_SOURCE && (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
+
+#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
+ || (defined(__cplusplus) && __cplusplus >= 201103L)
+typedef long double max_align_t;
+#endif
+
+#endif /* __STDDEF_H__ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos-any/sys/_types/_offsetof.h b/lib/libc/include/any-macos-any/sys/_types/_offsetof.h
new file mode 100644
index 0000000000..05c5381d1d
--- /dev/null
+++ b/lib/libc/include/any-macos-any/sys/_types/_offsetof.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2003-2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+#ifndef offsetof
+#define offsetof(type, field) __offsetof(type, field)
+#endif /* offsetof */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos-any/sys/_types/_ptrdiff_t.h b/lib/libc/include/any-macos-any/sys/_types/_ptrdiff_t.h
new file mode 100644
index 0000000000..096dfd5cf1
--- /dev/null
+++ b/lib/libc/include/any-macos-any/sys/_types/_ptrdiff_t.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
+#include /* __darwin_ptrdiff_t */
+typedef __darwin_ptrdiff_t ptrdiff_t;
+#endif /* _PTRDIFF_T */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos-any/vis.h b/lib/libc/include/any-macos-any/vis.h
new file mode 100644
index 0000000000..6e06eb4e56
--- /dev/null
+++ b/lib/libc/include/any-macos-any/vis.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/* $NetBSD: vis.h,v 1.21 2013/02/20 17:01:15 christos Exp $ */
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)vis.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _VIS_H_
+#define _VIS_H_
+
+#include <_types.h>
+#include
+
+/*
+ * to select alternate encoding format
+ */
+#define VIS_OCTAL 0x0001 /* use octal \ddd format */
+#define VIS_CSTYLE 0x0002 /* use \[nrft0..] where appropiate */
+
+/*
+ * to alter set of characters encoded (default is to encode all
+ * non-graphic except space, tab, and newline).
+ */
+#define VIS_SP 0x0004 /* also encode space */
+#define VIS_TAB 0x0008 /* also encode tab */
+#define VIS_NL 0x0010 /* also encode newline */
+#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
+#define VIS_SAFE 0x0020 /* only encode "unsafe" characters */
+
+/*
+ * other
+ */
+#define VIS_NOSLASH 0x0040 /* inhibit printing '\' */
+#define VIS_HTTP1808 0x0080 /* http-style escape % hex hex */
+#define VIS_HTTPSTYLE 0x0080 /* http-style escape % hex hex */
+#define VIS_GLOB 0x0100 /* encode glob(3) magic characters */
+#define VIS_MIMESTYLE 0x0200 /* mime-style escape = HEX HEX */
+#define VIS_HTTP1866 0x0400 /* http-style num; or &string; */
+#define VIS_NOESCAPE 0x0800 /* don't decode `\' */
+#define _VIS_END 0x1000 /* for unvis */
+
+/*
+ * unvis return codes
+ */
+#define UNVIS_VALID 1 /* character valid */
+#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */
+#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */
+#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */
+#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */
+
+/*
+ * unvis flags
+ */
+#define UNVIS_END _VIS_END /* no more characters */
+
+#include
+
+__BEGIN_DECLS
+char *vis(char *, int, int, int);
+char *nvis(char *, size_t, int, int, int);
+
+char *svis(char *, int, int, int, const char *);
+char *snvis(char *, size_t, int, int, int, const char *);
+
+int strvis(char *, const char *, int);
+int strnvis(char *, size_t, const char *, int);
+
+int strsvis(char *, const char *, int, const char *);
+int strsnvis(char *, size_t, const char *, int, const char *);
+
+int strvisx(char *, const char *, size_t, int);
+int strnvisx(char *, size_t, const char *, size_t, int);
+int strenvisx(char *, size_t, const char *, size_t, int, int *);
+
+int strsvisx(char *, const char *, size_t, int, const char *);
+int strsnvisx(char *, size_t, const char *, size_t, int, const char *);
+int strsenvisx(char *, size_t, const char *, size_t , int, const char *,
+ int *);
+
+int strunvis(char *, const char *);
+int strnunvis(char *, size_t, const char *);
+
+int strunvisx(char *, const char *, int);
+int strnunvisx(char *, size_t, const char *, int);
+
+int unvis(char *, int, int *, int);
+__END_DECLS
+
+#endif /* !_VIS_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/AssertMacros.h b/lib/libc/include/any-macos.11-any/AssertMacros.h
new file mode 100644
index 0000000000..7dc2e589af
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/AssertMacros.h
@@ -0,0 +1,1441 @@
+/*
+ * Copyright (c) 2002-2017 by Apple Inc.. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+/*
+ File: AssertMacros.h
+
+ Contains: This file defines structured error handling and assertion macros for
+ programming in C. Originally used in QuickDraw GX and later enhanced.
+ These macros are used throughout Apple's software.
+
+ New code may not want to begin adopting these macros and instead use
+ existing language functionality.
+
+ See "Living In an Exceptional World" by Sean Parent
+ (develop, The Apple Technical Journal, Issue 11, August/September 1992)
+ or
+
+ for the methodology behind these error handling and assertion macros.
+
+ Bugs?: For bug reports, consult the following page on
+ the World Wide Web:
+
+ http://developer.apple.com/bugreporter/
+*/
+#ifndef __ASSERTMACROS__
+#define __ASSERTMACROS__
+
+#ifdef DEBUG_ASSERT_CONFIG_INCLUDE
+ #include DEBUG_ASSERT_CONFIG_INCLUDE
+#endif
+
+/*
+ * Macro overview:
+ *
+ * check(assertion)
+ * In production builds, pre-processed away
+ * In debug builds, if assertion evaluates to false, calls DEBUG_ASSERT_MESSAGE
+ *
+ * verify(assertion)
+ * In production builds, evaluates assertion and does nothing
+ * In debug builds, if assertion evaluates to false, calls DEBUG_ASSERT_MESSAGE
+ *
+ * require(assertion, exceptionLabel)
+ * In production builds, if the assertion expression evaluates to false, goto exceptionLabel
+ * In debug builds, if the assertion expression evaluates to false, calls DEBUG_ASSERT_MESSAGE
+ * and jumps to exceptionLabel
+ *
+ * In addition the following suffixes are available:
+ *
+ * _noerr Adds "!= 0" to assertion. Useful for asserting and OSStatus or OSErr is noErr (zero)
+ * _action Adds statement to be executued if assertion fails
+ * _quiet Suppress call to DEBUG_ASSERT_MESSAGE
+ * _string Allows you to add explanitory message to DEBUG_ASSERT_MESSAGE
+ *
+ * For instance, require_noerr_string(resultCode, label, msg) will do nothing if
+ * resultCode is zero, otherwise it will call DEBUG_ASSERT_MESSAGE with msg
+ * and jump to label.
+ *
+ * Configuration:
+ *
+ * By default all macros generate "production code" (i.e non-debug). If
+ * DEBUG_ASSERT_PRODUCTION_CODE is defined to zero or DEBUG is defined to non-zero
+ * while this header is included, the macros will generated debug code.
+ *
+ * If DEBUG_ASSERT_COMPONENT_NAME_STRING is defined, all debug messages will
+ * be prefixed with it.
+ *
+ * By default, all messages write to stderr. If you would like to write a custom
+ * error message formater, defined DEBUG_ASSERT_MESSAGE to your function name.
+ *
+ * Each individual macro will only be defined if it is not already defined, so
+ * you can redefine their behavior singly by providing your own definition before
+ * this file is included.
+ *
+ * If you define __ASSERTMACROS__ before this file is included, then nothing in
+ * this file will take effect.
+ *
+ * Prior to Mac OS X 10.6 the macro names used in this file conflicted with some
+ * user code, including libraries in boost and the proposed C++ standards efforts,
+ * and there was no way for a client of this header to resolve this conflict. Because
+ * of this, most of the macros have been changed so that they are prefixed with
+ * __ and contain at least one capital letter, which should alleviate the current
+ * and future conflicts. However, to allow current sources to continue to compile,
+ * compatibility macros are defined at the end with the old names. A tops script
+ * at the end of this file will convert all of the old macro names used in a directory
+ * to the new names. Clients are recommended to migrate over to these new macros as
+ * they update their sources because a future release of Mac OS X will remove the
+ * old macro definitions ( without the double-underscore prefix ). Clients who
+ * want to compile without the old macro definitions can define the macro
+ * __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES to 0 before this file is
+ * included.
+ */
+
+
+/*
+ * Before including this file, #define DEBUG_ASSERT_COMPONENT_NAME_STRING to
+ * a C-string containing the name of your client. This string will be passed to
+ * the DEBUG_ASSERT_MESSAGE macro for inclusion in any assertion messages.
+ *
+ * If you do not define DEBUG_ASSERT_COMPONENT_NAME_STRING, the default
+ * DEBUG_ASSERT_COMPONENT_NAME_STRING value, an empty string, will be used by
+ * the assertion macros.
+ */
+#ifndef DEBUG_ASSERT_COMPONENT_NAME_STRING
+ #define DEBUG_ASSERT_COMPONENT_NAME_STRING ""
+#endif
+
+
+/*
+ * To activate the additional assertion code and messages for non-production builds,
+ * #define DEBUG_ASSERT_PRODUCTION_CODE to zero before including this file.
+ *
+ * If you do not define DEBUG_ASSERT_PRODUCTION_CODE, the default value 1 will be used
+ * (production code = no assertion code and no messages).
+ */
+#ifndef DEBUG_ASSERT_PRODUCTION_CODE
+ #define DEBUG_ASSERT_PRODUCTION_CODE !DEBUG
+#endif
+
+
+/*
+ * DEBUG_ASSERT_MESSAGE(component, assertion, label, error, file, line, errorCode)
+ *
+ * Summary:
+ * All assertion messages are routed through this macro. If you wish to use your
+ * own routine to display assertion messages, you can override DEBUG_ASSERT_MESSAGE
+ * by #defining DEBUG_ASSERT_MESSAGE before including this file.
+ *
+ * Parameters:
+ *
+ * componentNameString:
+ * A pointer to a string constant containing the name of the
+ * component this code is part of. This must be a string constant
+ * (and not a string variable or NULL) because the preprocessor
+ * concatenates it with other string constants.
+ *
+ * assertionString:
+ * A pointer to a string constant containing the assertion.
+ * This must be a string constant (and not a string variable or
+ * NULL) because the Preprocessor concatenates it with other
+ * string constants.
+ *
+ * exceptionLabelString:
+ * A pointer to a string containing the exceptionLabel, or NULL.
+ *
+ * errorString:
+ * A pointer to the error string, or NULL. DEBUG_ASSERT_MESSAGE macros
+ * must not attempt to concatenate this string with constant
+ * character strings.
+ *
+ * fileName:
+ * A pointer to the fileName or pathname (generated by the
+ * preprocessor __FILE__ identifier), or NULL.
+ *
+ * lineNumber:
+ * The line number in the file (generated by the preprocessor
+ * __LINE__ identifier), or 0 (zero).
+ *
+ * errorCode:
+ * A value associated with the assertion, or 0.
+ *
+ * Here is an example of a DEBUG_ASSERT_MESSAGE macro and a routine which displays
+ * assertion messsages:
+ *
+ * #define DEBUG_ASSERT_COMPONENT_NAME_STRING "MyCoolProgram"
+ *
+ * #define DEBUG_ASSERT_MESSAGE(componentNameString, assertionString, \
+ * exceptionLabelString, errorString, fileName, lineNumber, errorCode) \
+ * MyProgramDebugAssert(componentNameString, assertionString, \
+ * exceptionLabelString, errorString, fileName, lineNumber, errorCode)
+ *
+ * static void
+ * MyProgramDebugAssert(const char *componentNameString, const char *assertionString,
+ * const char *exceptionLabelString, const char *errorString,
+ * const char *fileName, long lineNumber, int errorCode)
+ * {
+ * if ( (assertionString != NULL) && (*assertionString != '\0') )
+ * fprintf(stderr, "Assertion failed: %s: %s\n", componentNameString, assertionString);
+ * else
+ * fprintf(stderr, "Check failed: %s:\n", componentNameString);
+ * if ( exceptionLabelString != NULL )
+ * fprintf(stderr, " %s\n", exceptionLabelString);
+ * if ( errorString != NULL )
+ * fprintf(stderr, " %s\n", errorString);
+ * if ( fileName != NULL )
+ * fprintf(stderr, " file: %s\n", fileName);
+ * if ( lineNumber != 0 )
+ * fprintf(stderr, " line: %ld\n", lineNumber);
+ * if ( errorCode != 0 )
+ * fprintf(stderr, " error: %d\n", errorCode);
+ * }
+ *
+ * If you do not define DEBUG_ASSERT_MESSAGE, a simple printf to stderr will be used.
+ */
+#ifndef DEBUG_ASSERT_MESSAGE
+ #ifdef KERNEL
+ #include
+ #define DEBUG_ASSERT_MESSAGE(name, assertion, label, message, file, line, value) \
+ printf( "AssertMacros: %s, %s file: %s, line: %d, value: %ld\n", assertion, (message!=0) ? message : "", file, line, (long) (value));
+ #else
+ #include
+ #define DEBUG_ASSERT_MESSAGE(name, assertion, label, message, file, line, value) \
+ fprintf(stderr, "AssertMacros: %s, %s file: %s, line: %d, value: %ld\n", assertion, (message!=0) ? message : "", file, line, (long) (value));
+ #endif
+#endif
+
+
+
+
+
+/*
+ * __Debug_String(message)
+ *
+ * Summary:
+ * Production builds: does nothing and produces no code.
+ *
+ * Non-production builds: call DEBUG_ASSERT_MESSAGE.
+ *
+ * Parameters:
+ *
+ * message:
+ * The C string to display.
+ *
+ */
+#ifndef __Debug_String
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Debug_String(message)
+ #else
+ #define __Debug_String(message) \
+ do \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ "", \
+ 0, \
+ message, \
+ __FILE__, \
+ __LINE__, \
+ 0); \
+ } while ( 0 )
+ #endif
+#endif
+
+/*
+ * __Check(assertion)
+ *
+ * Summary:
+ * Production builds: does nothing and produces no code.
+ *
+ * Non-production builds: if the assertion expression evaluates to false,
+ * call DEBUG_ASSERT_MESSAGE.
+ *
+ * Parameters:
+ *
+ * assertion:
+ * The assertion expression.
+ */
+#ifndef __Check
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Check(assertion)
+ #else
+ #define __Check(assertion) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #assertion, 0, 0, __FILE__, __LINE__, 0 ); \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+#ifndef __nCheck
+ #define __nCheck(assertion) __Check(!(assertion))
+#endif
+
+/*
+ * __Check_String(assertion, message)
+ *
+ * Summary:
+ * Production builds: does nothing and produces no code.
+ *
+ * Non-production builds: if the assertion expression evaluates to false,
+ * call DEBUG_ASSERT_MESSAGE.
+ *
+ * Parameters:
+ *
+ * assertion:
+ * The assertion expression.
+ *
+ * message:
+ * The C string to display.
+ */
+#ifndef __Check_String
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Check_String(assertion, message)
+ #else
+ #define __Check_String(assertion, message) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #assertion, 0, message, __FILE__, __LINE__, 0 ); \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+#ifndef __nCheck_String
+ #define __nCheck_String(assertion, message) __Check_String(!(assertion), message)
+#endif
+
+/*
+ * __Check_noErr(errorCode)
+ *
+ * Summary:
+ * Production builds: does nothing and produces no code.
+ *
+ * Non-production builds: if the errorCode expression does not equal 0 (noErr),
+ * call DEBUG_ASSERT_MESSAGE.
+ *
+ * Parameters:
+ *
+ * errorCode:
+ * The errorCode expression to compare with 0.
+ */
+#ifndef __Check_noErr
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Check_noErr(errorCode)
+ #else
+ #define __Check_noErr(errorCode) \
+ do \
+ { \
+ long evalOnceErrorCode = (errorCode); \
+ if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #errorCode " == 0 ", 0, 0, __FILE__, __LINE__, evalOnceErrorCode ); \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+/*
+ * __Check_noErr_String(errorCode, message)
+ *
+ * Summary:
+ * Production builds: check_noerr_string() does nothing and produces
+ * no code.
+ *
+ * Non-production builds: if the errorCode expression does not equal 0 (noErr),
+ * call DEBUG_ASSERT_MESSAGE.
+ *
+ * Parameters:
+ *
+ * errorCode:
+ * The errorCode expression to compare to 0.
+ *
+ * message:
+ * The C string to display.
+ */
+#ifndef __Check_noErr_String
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Check_noErr_String(errorCode, message)
+ #else
+ #define __Check_noErr_String(errorCode, message) \
+ do \
+ { \
+ long evalOnceErrorCode = (errorCode); \
+ if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #errorCode " == 0 ", 0, message, __FILE__, __LINE__, evalOnceErrorCode ); \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+/*
+ * __Verify(assertion)
+ *
+ * Summary:
+ * Production builds: evaluate the assertion expression, but ignore
+ * the result.
+ *
+ * Non-production builds: if the assertion expression evaluates to false,
+ * call DEBUG_ASSERT_MESSAGE.
+ *
+ * Parameters:
+ *
+ * assertion:
+ * The assertion expression.
+ */
+#ifndef __Verify
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Verify(assertion) \
+ do \
+ { \
+ if ( !(assertion) ) \
+ { \
+ } \
+ } while ( 0 )
+ #else
+ #define __Verify(assertion) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #assertion, 0, 0, __FILE__, __LINE__, 0 ); \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+#ifndef __nVerify
+ #define __nVerify(assertion) __Verify(!(assertion))
+#endif
+
+/*
+ * __Verify_String(assertion, message)
+ *
+ * Summary:
+ * Production builds: evaluate the assertion expression, but ignore
+ * the result.
+ *
+ * Non-production builds: if the assertion expression evaluates to false,
+ * call DEBUG_ASSERT_MESSAGE.
+ *
+ * Parameters:
+ *
+ * assertion:
+ * The assertion expression.
+ *
+ * message:
+ * The C string to display.
+ */
+#ifndef __Verify_String
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Verify_String(assertion, message) \
+ do \
+ { \
+ if ( !(assertion) ) \
+ { \
+ } \
+ } while ( 0 )
+ #else
+ #define __Verify_String(assertion, message) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #assertion, 0, message, __FILE__, __LINE__, 0 ); \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+#ifndef __nVerify_String
+ #define __nVerify_String(assertion, message) __Verify_String(!(assertion), message)
+#endif
+
+/*
+ * __Verify_noErr(errorCode)
+ *
+ * Summary:
+ * Production builds: evaluate the errorCode expression, but ignore
+ * the result.
+ *
+ * Non-production builds: if the errorCode expression does not equal 0 (noErr),
+ * call DEBUG_ASSERT_MESSAGE.
+ *
+ * Parameters:
+ *
+ * errorCode:
+ * The expression to compare to 0.
+ */
+#ifndef __Verify_noErr
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Verify_noErr(errorCode) \
+ do \
+ { \
+ if ( 0 != (errorCode) ) \
+ { \
+ } \
+ } while ( 0 )
+ #else
+ #define __Verify_noErr(errorCode) \
+ do \
+ { \
+ long evalOnceErrorCode = (errorCode); \
+ if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #errorCode " == 0 ", 0, 0, __FILE__, __LINE__, evalOnceErrorCode ); \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+/*
+ * __Verify_noErr_String(errorCode, message)
+ *
+ * Summary:
+ * Production builds: evaluate the errorCode expression, but ignore
+ * the result.
+ *
+ * Non-production builds: if the errorCode expression does not equal 0 (noErr),
+ * call DEBUG_ASSERT_MESSAGE.
+ *
+ * Parameters:
+ *
+ * errorCode:
+ * The expression to compare to 0.
+ *
+ * message:
+ * The C string to display.
+ */
+#ifndef __Verify_noErr_String
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Verify_noErr_String(errorCode, message) \
+ do \
+ { \
+ if ( 0 != (errorCode) ) \
+ { \
+ } \
+ } while ( 0 )
+ #else
+ #define __Verify_noErr_String(errorCode, message) \
+ do \
+ { \
+ long evalOnceErrorCode = (errorCode); \
+ if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #errorCode " == 0 ", 0, message, __FILE__, __LINE__, evalOnceErrorCode ); \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+/*
+ * __Verify_noErr_Action(errorCode, action)
+ *
+ * Summary:
+ * Production builds: if the errorCode expression does not equal 0 (noErr),
+ * execute the action statement or compound statement (block).
+ *
+ * Non-production builds: if the errorCode expression does not equal 0 (noErr),
+ * call DEBUG_ASSERT_MESSAGE and then execute the action statement or compound
+ * statement (block).
+ *
+ * Parameters:
+ *
+ * errorCode:
+ * The expression to compare to 0.
+ *
+ * action:
+ * The statement or compound statement (block).
+ */
+#ifndef __Verify_noErr_Action
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Verify_noErr_Action(errorCode, action) \
+ if ( 0 != (errorCode) ) { \
+ action; \
+ } \
+ else do {} while (0)
+ #else
+ #define __Verify_noErr_Action(errorCode, action) \
+ do { \
+ long evalOnceErrorCode = (errorCode); \
+ if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #errorCode " == 0 ", 0, 0, __FILE__, __LINE__, evalOnceErrorCode ); \
+ action; \
+ } \
+ } while (0)
+ #endif
+#endif
+
+/*
+ * __Verify_Action(assertion, action)
+ *
+ * Summary:
+ * Production builds: if the assertion expression evaluates to false,
+ * then execute the action statement or compound statement (block).
+ *
+ * Non-production builds: if the assertion expression evaluates to false,
+ * call DEBUG_ASSERT_MESSAGE and then execute the action statement or compound
+ * statement (block).
+ *
+ * Parameters:
+ *
+ * assertion:
+ * The assertion expression.
+ *
+ * action:
+ * The statement or compound statement (block).
+ */
+#ifndef __Verify_Action
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Verify_Action(assertion, action) \
+ if ( __builtin_expect(!(assertion), 0) ) { \
+ action; \
+ } \
+ else do {} while (0)
+ #else
+ #define __Verify_Action(assertion, action) \
+ if ( __builtin_expect(!(assertion), 0) ) { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #assertion, 0, 0, __FILE__, __LINE__, 0 ); \
+ action; \
+ } \
+ else do {} while (0)
+ #endif
+#endif
+
+/*
+ * __Require(assertion, exceptionLabel)
+ *
+ * Summary:
+ * Production builds: if the assertion expression evaluates to false,
+ * goto exceptionLabel.
+ *
+ * Non-production builds: if the assertion expression evaluates to false,
+ * call DEBUG_ASSERT_MESSAGE and then goto exceptionLabel.
+ *
+ * Parameters:
+ *
+ * assertion:
+ * The assertion expression.
+ *
+ * exceptionLabel:
+ * The label.
+ */
+#ifndef __Require
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Require(assertion, exceptionLabel) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) \
+ { \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #else
+ #define __Require(assertion, exceptionLabel) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #assertion, #exceptionLabel, 0, __FILE__, __LINE__, 0); \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+#ifndef __nRequire
+ #define __nRequire(assertion, exceptionLabel) __Require(!(assertion), exceptionLabel)
+#endif
+
+/*
+ * __Require_Action(assertion, exceptionLabel, action)
+ *
+ * Summary:
+ * Production builds: if the assertion expression evaluates to false,
+ * execute the action statement or compound statement (block) and then
+ * goto exceptionLabel.
+ *
+ * Non-production builds: if the assertion expression evaluates to false,
+ * call DEBUG_ASSERT_MESSAGE, execute the action statement or compound
+ * statement (block), and then goto exceptionLabel.
+ *
+ * Parameters:
+ *
+ * assertion:
+ * The assertion expression.
+ *
+ * exceptionLabel:
+ * The label.
+ *
+ * action:
+ * The statement or compound statement (block).
+ */
+#ifndef __Require_Action
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Require_Action(assertion, exceptionLabel, action) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) \
+ { \
+ { \
+ action; \
+ } \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #else
+ #define __Require_Action(assertion, exceptionLabel, action) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #assertion, #exceptionLabel, 0, __FILE__, __LINE__, 0); \
+ { \
+ action; \
+ } \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+#ifndef __nRequire_Action
+ #define __nRequire_Action(assertion, exceptionLabel, action) \
+ __Require_Action(!(assertion), exceptionLabel, action)
+#endif
+
+/*
+ * __Require_Quiet(assertion, exceptionLabel)
+ *
+ * Summary:
+ * If the assertion expression evaluates to false, goto exceptionLabel.
+ *
+ * Parameters:
+ *
+ * assertion:
+ * The assertion expression.
+ *
+ * exceptionLabel:
+ * The label.
+ */
+#ifndef __Require_Quiet
+ #define __Require_Quiet(assertion, exceptionLabel) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) \
+ { \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+#endif
+
+#ifndef __nRequire_Quiet
+ #define __nRequire_Quiet(assertion, exceptionLabel) __Require_Quiet(!(assertion), exceptionLabel)
+#endif
+
+/*
+ * __Require_Action_Quiet(assertion, exceptionLabel, action)
+ *
+ * Summary:
+ * If the assertion expression evaluates to false, execute the action
+ * statement or compound statement (block), and goto exceptionLabel.
+ *
+ * Parameters:
+ *
+ * assertion:
+ * The assertion expression.
+ *
+ * exceptionLabel:
+ * The label.
+ *
+ * action:
+ * The statement or compound statement (block).
+ */
+#ifndef __Require_Action_Quiet
+ #define __Require_Action_Quiet(assertion, exceptionLabel, action) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) \
+ { \
+ { \
+ action; \
+ } \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+#endif
+
+#ifndef __nRequire_Action_Quiet
+ #define __nRequire_Action_Quiet(assertion, exceptionLabel, action) \
+ __Require_Action_Quiet(!(assertion), exceptionLabel, action)
+#endif
+
+/*
+ * __Require_String(assertion, exceptionLabel, message)
+ *
+ * Summary:
+ * Production builds: if the assertion expression evaluates to false,
+ * goto exceptionLabel.
+ *
+ * Non-production builds: if the assertion expression evaluates to false,
+ * call DEBUG_ASSERT_MESSAGE, and then goto exceptionLabel.
+ *
+ * Parameters:
+ *
+ * assertion:
+ * The assertion expression.
+ *
+ * exceptionLabel:
+ * The label.
+ *
+ * message:
+ * The C string to display.
+ */
+#ifndef __Require_String
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Require_String(assertion, exceptionLabel, message) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) \
+ { \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #else
+ #define __Require_String(assertion, exceptionLabel, message) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #assertion, #exceptionLabel, message, __FILE__, __LINE__, 0); \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+#ifndef __nRequire_String
+ #define __nRequire_String(assertion, exceptionLabel, string) \
+ __Require_String(!(assertion), exceptionLabel, string)
+#endif
+
+/*
+ * __Require_Action_String(assertion, exceptionLabel, action, message)
+ *
+ * Summary:
+ * Production builds: if the assertion expression evaluates to false,
+ * execute the action statement or compound statement (block), and then
+ * goto exceptionLabel.
+ *
+ * Non-production builds: if the assertion expression evaluates to false,
+ * call DEBUG_ASSERT_MESSAGE, execute the action statement or compound
+ * statement (block), and then goto exceptionLabel.
+ *
+ * Parameters:
+ *
+ * assertion:
+ * The assertion expression.
+ *
+ * exceptionLabel:
+ * The label.
+ *
+ * action:
+ * The statement or compound statement (block).
+ *
+ * message:
+ * The C string to display.
+ */
+#ifndef __Require_Action_String
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Require_Action_String(assertion, exceptionLabel, action, message) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) \
+ { \
+ { \
+ action; \
+ } \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #else
+ #define __Require_Action_String(assertion, exceptionLabel, action, message) \
+ do \
+ { \
+ if ( __builtin_expect(!(assertion), 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #assertion, #exceptionLabel, message, __FILE__, __LINE__, 0); \
+ { \
+ action; \
+ } \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+#ifndef __nRequire_Action_String
+ #define __nRequire_Action_String(assertion, exceptionLabel, action, message) \
+ __Require_Action_String(!(assertion), exceptionLabel, action, message)
+#endif
+
+/*
+ * __Require_noErr(errorCode, exceptionLabel)
+ *
+ * Summary:
+ * Production builds: if the errorCode expression does not equal 0 (noErr),
+ * goto exceptionLabel.
+ *
+ * Non-production builds: if the errorCode expression does not equal 0 (noErr),
+ * call DEBUG_ASSERT_MESSAGE and then goto exceptionLabel.
+ *
+ * Parameters:
+ *
+ * errorCode:
+ * The expression to compare to 0.
+ *
+ * exceptionLabel:
+ * The label.
+ */
+#ifndef __Require_noErr
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Require_noErr(errorCode, exceptionLabel) \
+ do \
+ { \
+ if ( __builtin_expect(0 != (errorCode), 0) ) \
+ { \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #else
+ #define __Require_noErr(errorCode, exceptionLabel) \
+ do \
+ { \
+ long evalOnceErrorCode = (errorCode); \
+ if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #errorCode " == 0 ", #exceptionLabel, 0, __FILE__, __LINE__, evalOnceErrorCode); \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+/*
+ * __Require_noErr_Action(errorCode, exceptionLabel, action)
+ *
+ * Summary:
+ * Production builds: if the errorCode expression does not equal 0 (noErr),
+ * execute the action statement or compound statement (block) and
+ * goto exceptionLabel.
+ *
+ * Non-production builds: if the errorCode expression does not equal 0 (noErr),
+ * call DEBUG_ASSERT_MESSAGE, execute the action statement or
+ * compound statement (block), and then goto exceptionLabel.
+ *
+ * Parameters:
+ *
+ * errorCode:
+ * The expression to compare to 0.
+ *
+ * exceptionLabel:
+ * The label.
+ *
+ * action:
+ * The statement or compound statement (block).
+ */
+#ifndef __Require_noErr_Action
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Require_noErr_Action(errorCode, exceptionLabel, action) \
+ do \
+ { \
+ if ( __builtin_expect(0 != (errorCode), 0) ) \
+ { \
+ { \
+ action; \
+ } \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #else
+ #define __Require_noErr_Action(errorCode, exceptionLabel, action) \
+ do \
+ { \
+ long evalOnceErrorCode = (errorCode); \
+ if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #errorCode " == 0 ", #exceptionLabel, 0, __FILE__, __LINE__, evalOnceErrorCode); \
+ { \
+ action; \
+ } \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+/*
+ * __Require_noErr_Quiet(errorCode, exceptionLabel)
+ *
+ * Summary:
+ * If the errorCode expression does not equal 0 (noErr),
+ * goto exceptionLabel.
+ *
+ * Parameters:
+ *
+ * errorCode:
+ * The expression to compare to 0.
+ *
+ * exceptionLabel:
+ * The label.
+ */
+#ifndef __Require_noErr_Quiet
+ #define __Require_noErr_Quiet(errorCode, exceptionLabel) \
+ do \
+ { \
+ if ( __builtin_expect(0 != (errorCode), 0) ) \
+ { \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+#endif
+
+/*
+ * __Require_noErr_Action_Quiet(errorCode, exceptionLabel, action)
+ *
+ * Summary:
+ * If the errorCode expression does not equal 0 (noErr),
+ * execute the action statement or compound statement (block) and
+ * goto exceptionLabel.
+ *
+ * Parameters:
+ *
+ * errorCode:
+ * The expression to compare to 0.
+ *
+ * exceptionLabel:
+ * The label.
+ *
+ * action:
+ * The statement or compound statement (block).
+ */
+#ifndef __Require_noErr_Action_Quiet
+ #define __Require_noErr_Action_Quiet(errorCode, exceptionLabel, action) \
+ do \
+ { \
+ if ( __builtin_expect(0 != (errorCode), 0) ) \
+ { \
+ { \
+ action; \
+ } \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+#endif
+
+/*
+ * __Require_noErr_String(errorCode, exceptionLabel, message)
+ *
+ * Summary:
+ * Production builds: if the errorCode expression does not equal 0 (noErr),
+ * goto exceptionLabel.
+ *
+ * Non-production builds: if the errorCode expression does not equal 0 (noErr),
+ * call DEBUG_ASSERT_MESSAGE, and then goto exceptionLabel.
+ *
+ * Parameters:
+ *
+ * errorCode:
+ * The expression to compare to 0.
+ *
+ * exceptionLabel:
+ * The label.
+ *
+ * message:
+ * The C string to display.
+ */
+#ifndef __Require_noErr_String
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Require_noErr_String(errorCode, exceptionLabel, message) \
+ do \
+ { \
+ if ( __builtin_expect(0 != (errorCode), 0) ) \
+ { \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #else
+ #define __Require_noErr_String(errorCode, exceptionLabel, message) \
+ do \
+ { \
+ long evalOnceErrorCode = (errorCode); \
+ if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #errorCode " == 0 ", #exceptionLabel, message, __FILE__, __LINE__, evalOnceErrorCode); \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+/*
+ * __Require_noErr_Action_String(errorCode, exceptionLabel, action, message)
+ *
+ * Summary:
+ * Production builds: if the errorCode expression does not equal 0 (noErr),
+ * execute the action statement or compound statement (block) and
+ * goto exceptionLabel.
+ *
+ * Non-production builds: if the errorCode expression does not equal 0 (noErr),
+ * call DEBUG_ASSERT_MESSAGE, execute the action statement or compound
+ * statement (block), and then goto exceptionLabel.
+ *
+ * Parameters:
+ *
+ * errorCode:
+ * The expression to compare to 0.
+ *
+ * exceptionLabel:
+ * The label.
+ *
+ * action:
+ * The statement or compound statement (block).
+ *
+ * message:
+ * The C string to display.
+ */
+#ifndef __Require_noErr_Action_String
+ #if DEBUG_ASSERT_PRODUCTION_CODE
+ #define __Require_noErr_Action_String(errorCode, exceptionLabel, action, message) \
+ do \
+ { \
+ if ( __builtin_expect(0 != (errorCode), 0) ) \
+ { \
+ { \
+ action; \
+ } \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #else
+ #define __Require_noErr_Action_String(errorCode, exceptionLabel, action, message) \
+ do \
+ { \
+ long evalOnceErrorCode = (errorCode); \
+ if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \
+ { \
+ DEBUG_ASSERT_MESSAGE( \
+ DEBUG_ASSERT_COMPONENT_NAME_STRING, \
+ #errorCode " == 0 ", #exceptionLabel, message, __FILE__, __LINE__, evalOnceErrorCode); \
+ { \
+ action; \
+ } \
+ goto exceptionLabel; \
+ } \
+ } while ( 0 )
+ #endif
+#endif
+
+/*
+ * __Check_Compile_Time(expr)
+ *
+ * Summary:
+ * any build: if the expression is not true, generated a compile time error.
+ *
+ * Parameters:
+ *
+ * expr:
+ * The compile time expression that should evaluate to non-zero.
+ *
+ * Discussion:
+ * This declares an array with a size that is determined by a compile-time expression.
+ * If false, it declares a negatively sized array, which generates a compile-time error.
+ *
+ * Examples:
+ * __Check_Compile_Time( sizeof( int ) == 4 );
+ * __Check_Compile_Time( offsetof( MyStruct, myField ) == 4 );
+ * __Check_Compile_Time( ( kMyBufferSize % 512 ) == 0 );
+ *
+ * Note: This only works with compile-time expressions.
+ * Note: This only works in places where extern declarations are allowed (e.g. global scope).
+ */
+#ifndef __Check_Compile_Time
+ #ifdef __GNUC__
+ #if (__cplusplus >= 201103L)
+ #define __Check_Compile_Time( expr ) static_assert( expr , "__Check_Compile_Time")
+ #elif (__STDC_VERSION__ >= 201112L)
+ #define __Check_Compile_Time( expr ) _Static_assert( expr , "__Check_Compile_Time")
+ #else
+ #define __Check_Compile_Time( expr ) \
+ extern int compile_time_assert_failed[ ( expr ) ? 1 : -1 ] __attribute__( ( unused ) )
+ #endif
+ #else
+ #define __Check_Compile_Time( expr ) \
+ extern int compile_time_assert_failed[ ( expr ) ? 1 : -1 ]
+ #endif
+#endif
+
+/*
+ * For time immemorial, Mac OS X has defined version of most of these macros without the __ prefix, which
+ * could collide with similarly named functions or macros in user code, including new functionality in
+ * Boost and the C++ standard library.
+ *
+ * macOS High Sierra and iOS 11 will now require that clients move to the new macros as defined above.
+ *
+ * If you would like to enable the macros for use within your own project, you can define the
+ * __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES macro via an Xcode Build Configuration.
+ * See "Add a build configuration (xcconfig) file" in Xcode Help.
+ *
+ * To aid users of these macros in converting their sources, the following tops script will convert usages
+ * of the old macros into the new equivalents. To do so, in Terminal go into the directory containing the
+ * sources to be converted and run this command.
+ *
+ find -E . -regex '.*\.(c|cc|cp|cpp|m|mm|h)' -print0 | xargs -0 tops -verbose \
+ replace "check()" with "__Check()" \
+ replace "check_noerr()" with "__Check_noErr()" \
+ replace "check_noerr_string()" with "__Check_noErr_String()" \
+ replace "check_string()" with "__Check_String()" \
+ replace "require()" with "__Require()" \
+ replace "require_action()" with "__Require_Action()" \
+ replace "require_action_string()" with "__Require_Action_String()" \
+ replace "require_noerr()" with "__Require_noErr()" \
+ replace "require_noerr_action()" with "__Require_noErr_Action()" \
+ replace "require_noerr_action_string()" with "__Require_noErr_Action_String()" \
+ replace "require_noerr_string()" with "__Require_noErr_String()" \
+ replace "require_string()" with "__Require_String()" \
+ replace "verify()" with "__Verify()" \
+ replace "verify_action()" with "__Verify_Action()" \
+ replace "verify_noerr()" with "__Verify_noErr()" \
+ replace "verify_noerr_action()" with "__Verify_noErr_Action()" \
+ replace "verify_noerr_string()" with "__Verify_noErr_String()" \
+ replace "verify_string()" with "__Verify_String()" \
+ replace "ncheck()" with "__nCheck()" \
+ replace "ncheck_string()" with "__nCheck_String()" \
+ replace "nrequire()" with "__nRequire()" \
+ replace "nrequire_action()" with "__nRequire_Action()" \
+ replace "nrequire_action_quiet()" with "__nRequire_Action_Quiet()" \
+ replace "nrequire_action_string()" with "__nRequire_Action_String()" \
+ replace "nrequire_quiet()" with "__nRequire_Quiet()" \
+ replace "nrequire_string()" with "__nRequire_String()" \
+ replace "nverify()" with "__nVerify()" \
+ replace "nverify_string()" with "__nVerify_String()" \
+ replace "require_action_quiet()" with "__Require_Action_Quiet()" \
+ replace "require_noerr_action_quiet()" with "__Require_noErr_Action_Quiet()" \
+ replace "require_noerr_quiet()" with "__Require_noErr_Quiet()" \
+ replace "require_quiet()" with "__Require_Quiet()" \
+ replace "check_compile_time()" with "__Check_Compile_Time()" \
+ replace "debug_string()" with "__Debug_String()"
+ *
+ */
+
+#ifndef __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES
+ #if __has_include()
+ #include
+ #else
+ /* In macOS High Sierra and iOS 11, if we haven't set this yet, it now defaults to off. */
+ #define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
+ #endif
+#endif
+
+#if __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES
+
+ #ifndef check
+ #define check(assertion) __Check(assertion)
+ #endif
+
+ #ifndef check_noerr
+ #define check_noerr(errorCode) __Check_noErr(errorCode)
+ #endif
+
+ #ifndef check_noerr_string
+ #define check_noerr_string(errorCode, message) __Check_noErr_String(errorCode, message)
+ #endif
+
+ #ifndef check_string
+ #define check_string(assertion, message) __Check_String(assertion, message)
+ #endif
+
+ #ifndef require
+ #define require(assertion, exceptionLabel) __Require(assertion, exceptionLabel)
+ #endif
+
+ #ifndef require_action
+ #define require_action(assertion, exceptionLabel, action) __Require_Action(assertion, exceptionLabel, action)
+ #endif
+
+ #ifndef require_action_string
+ #define require_action_string(assertion, exceptionLabel, action, message) __Require_Action_String(assertion, exceptionLabel, action, message)
+ #endif
+
+ #ifndef require_noerr
+ #define require_noerr(errorCode, exceptionLabel) __Require_noErr(errorCode, exceptionLabel)
+ #endif
+
+ #ifndef require_noerr_action
+ #define require_noerr_action(errorCode, exceptionLabel, action) __Require_noErr_Action(errorCode, exceptionLabel, action)
+ #endif
+
+ #ifndef require_noerr_action_string
+ #define require_noerr_action_string(errorCode, exceptionLabel, action, message) __Require_noErr_Action_String(errorCode, exceptionLabel, action, message)
+ #endif
+
+ #ifndef require_noerr_string
+ #define require_noerr_string(errorCode, exceptionLabel, message) __Require_noErr_String(errorCode, exceptionLabel, message)
+ #endif
+
+ #ifndef require_string
+ #define require_string(assertion, exceptionLabel, message) __Require_String(assertion, exceptionLabel, message)
+ #endif
+
+ #ifndef verify
+ #define verify(assertion) __Verify(assertion)
+ #endif
+
+ #ifndef verify_action
+ #define verify_action(assertion, action) __Verify_Action(assertion, action)
+ #endif
+
+ #ifndef verify_noerr
+ #define verify_noerr(errorCode) __Verify_noErr(errorCode)
+ #endif
+
+ #ifndef verify_noerr_action
+ #define verify_noerr_action(errorCode, action) __Verify_noErr_Action(errorCode, action)
+ #endif
+
+ #ifndef verify_noerr_string
+ #define verify_noerr_string(errorCode, message) __Verify_noErr_String(errorCode, message)
+ #endif
+
+ #ifndef verify_string
+ #define verify_string(assertion, message) __Verify_String(assertion, message)
+ #endif
+
+ #ifndef ncheck
+ #define ncheck(assertion) __nCheck(assertion)
+ #endif
+
+ #ifndef ncheck_string
+ #define ncheck_string(assertion, message) __nCheck_String(assertion, message)
+ #endif
+
+ #ifndef nrequire
+ #define nrequire(assertion, exceptionLabel) __nRequire(assertion, exceptionLabel)
+ #endif
+
+ #ifndef nrequire_action
+ #define nrequire_action(assertion, exceptionLabel, action) __nRequire_Action(assertion, exceptionLabel, action)
+ #endif
+
+ #ifndef nrequire_action_quiet
+ #define nrequire_action_quiet(assertion, exceptionLabel, action) __nRequire_Action_Quiet(assertion, exceptionLabel, action)
+ #endif
+
+ #ifndef nrequire_action_string
+ #define nrequire_action_string(assertion, exceptionLabel, action, message) __nRequire_Action_String(assertion, exceptionLabel, action, message)
+ #endif
+
+ #ifndef nrequire_quiet
+ #define nrequire_quiet(assertion, exceptionLabel) __nRequire_Quiet(assertion, exceptionLabel)
+ #endif
+
+ #ifndef nrequire_string
+ #define nrequire_string(assertion, exceptionLabel, string) __nRequire_String(assertion, exceptionLabel, string)
+ #endif
+
+ #ifndef nverify
+ #define nverify(assertion) __nVerify(assertion)
+ #endif
+
+ #ifndef nverify_string
+ #define nverify_string(assertion, message) __nVerify_String(assertion, message)
+ #endif
+
+ #ifndef require_action_quiet
+ #define require_action_quiet(assertion, exceptionLabel, action) __Require_Action_Quiet(assertion, exceptionLabel, action)
+ #endif
+
+ #ifndef require_noerr_action_quiet
+ #define require_noerr_action_quiet(errorCode, exceptionLabel, action) __Require_noErr_Action_Quiet(errorCode, exceptionLabel, action)
+ #endif
+
+ #ifndef require_noerr_quiet
+ #define require_noerr_quiet(errorCode, exceptionLabel) __Require_noErr_Quiet(errorCode, exceptionLabel)
+ #endif
+
+ #ifndef require_quiet
+ #define require_quiet(assertion, exceptionLabel) __Require_Quiet(assertion, exceptionLabel)
+ #endif
+
+ #ifndef check_compile_time
+ #define check_compile_time( expr ) __Check_Compile_Time( expr )
+ #endif
+
+ #ifndef debug_string
+ #define debug_string(message) __Debug_String(message)
+ #endif
+
+#endif /* ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES */
+
+
+#endif /* __ASSERTMACROS__ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/AvailabilityInternal.h b/lib/libc/include/any-macos.11-any/AvailabilityInternal.h
index 3eb79b6084..6a35a16782 100644
--- a/lib/libc/include/any-macos.11-any/AvailabilityInternal.h
+++ b/lib/libc/include/any-macos.11-any/AvailabilityInternal.h
@@ -55,7 +55,7 @@
#ifdef __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
/* compiler sets __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ when -mtvos-version-min is used */
#define __TV_OS_VERSION_MIN_REQUIRED __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
- #define __TV_OS_VERSION_MAX_ALLOWED __TVOS_15_2
+ #define __TV_OS_VERSION_MAX_ALLOWED __TVOS_14_5
/* for compatibility with existing code. New code should use platform specific checks */
#define __IPHONE_OS_VERSION_MIN_REQUIRED 90000
#endif
@@ -65,7 +65,7 @@
#ifdef __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__
/* compiler sets __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ when -mwatchos-version-min is used */
#define __WATCH_OS_VERSION_MIN_REQUIRED __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__
- #define __WATCH_OS_VERSION_MAX_ALLOWED __WATCHOS_8_3
+ #define __WATCH_OS_VERSION_MAX_ALLOWED __WATCHOS_7_4
/* for compatibility with existing code. New code should use platform specific checks */
#define __IPHONE_OS_VERSION_MIN_REQUIRED 90000
#endif
@@ -75,7 +75,7 @@
#ifdef __ENVIRONMENT_BRIDGE_OS_VERSION_MIN_REQUIRED__
#define __BRIDGE_OS_VERSION_MIN_REQUIRED __ENVIRONMENT_BRIDGE_OS_VERSION_MIN_REQUIRED__
- #define __BRIDGE_OS_VERSION_MAX_ALLOWED 60100
+ #define __BRIDGE_OS_VERSION_MAX_ALLOWED 50300
/* for compatibility with existing code. New code should use platform specific checks */
#define __IPHONE_OS_VERSION_MIN_REQUIRED 110000
#endif
@@ -90,14 +90,14 @@
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
/* make sure a default max version is set */
#ifndef __MAC_OS_X_VERSION_MAX_ALLOWED
- #define __MAC_OS_X_VERSION_MAX_ALLOWED __MAC_12_1
+ #define __MAC_OS_X_VERSION_MAX_ALLOWED __MAC_11_3
#endif
#endif /* __MAC_OS_X_VERSION_MIN_REQUIRED */
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
/* make sure a default max version is set */
#ifndef __IPHONE_OS_VERSION_MAX_ALLOWED
- #define __IPHONE_OS_VERSION_MAX_ALLOWED __IPHONE_15_2
+ #define __IPHONE_OS_VERSION_MAX_ALLOWED __IPHONE_14_5
#endif
/* make sure a valid min is set */
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_2_0
diff --git a/lib/libc/include/any-macos.11-any/AvailabilityMacros.h b/lib/libc/include/any-macos.11-any/AvailabilityMacros.h
new file mode 100644
index 0000000000..74537c5bd8
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/AvailabilityMacros.h
@@ -0,0 +1,4015 @@
+/*
+ * Copyright (c) 2001-2010 by Apple Inc.. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ File: AvailabilityMacros.h
+
+ More Info: See the SDK Compatibility Guide
+
+ Contains: Autoconfiguration of AVAILABLE_ macros for Mac OS X
+
+ This header enables a developer to specify build time
+ constraints on what Mac OS X versions the resulting
+ application will be run. There are two bounds a developer
+ can specify:
+
+ MAC_OS_X_VERSION_MIN_REQUIRED
+ MAC_OS_X_VERSION_MAX_ALLOWED
+
+ The lower bound controls which calls to OS functions will
+ be weak-importing (allowed to be unresolved at launch time).
+ The upper bound controls which OS functionality, if used,
+ will result in a compiler error because that functionality is
+ not available on any OS in the specifed range.
+
+ For example, suppose an application is compiled with:
+
+ MAC_OS_X_VERSION_MIN_REQUIRED = MAC_OS_X_VERSION_10_2
+ MAC_OS_X_VERSION_MAX_ALLOWED = MAC_OS_X_VERSION_10_3
+
+ and an OS header contains:
+
+ extern void funcA(void) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
+ extern void funcB(void) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_2;
+ extern void funcC(void) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+ extern void funcD(void) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER;
+ extern void funcE(void) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER;
+ extern void funcF(void) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER;
+ extern void funcG(void) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+
+ typedef long TypeA DEPRECATED_IN_MAC_OS_X_VERSION_10_0_AND_LATER;
+ typedef long TypeB DEPRECATED_IN_MAC_OS_X_VERSION_10_1_AND_LATER;
+ typedef long TypeC DEPRECATED_IN_MAC_OS_X_VERSION_10_2_AND_LATER;
+ typedef long TypeD DEPRECATED_IN_MAC_OS_X_VERSION_10_3_AND_LATER;
+ typedef long TypeE DEPRECATED_IN_MAC_OS_X_VERSION_10_4_AND_LATER;
+
+ Any application code which uses these declarations will get the following:
+
+ compile link run
+ ------- ------ -------
+ funcA: normal normal normal
+ funcB: warning normal normal
+ funcC: normal normal normal
+ funcD: normal normal normal
+ funcE: normal normal normal
+ funcF: normal weak on 10.3 normal, on 10.2 (&funcF == NULL)
+ funcG: error error n/a
+ typeA: warning
+ typeB: warning
+ typeC: warning
+ typeD: normal
+ typeE: normal
+
+
+*/
+#ifndef __AVAILABILITYMACROS__
+#define __AVAILABILITYMACROS__
+
+/*
+ * Set up standard Mac OS X versions
+ */
+#define MAC_OS_X_VERSION_10_0 1000
+#define MAC_OS_X_VERSION_10_1 1010
+#define MAC_OS_X_VERSION_10_2 1020
+#define MAC_OS_X_VERSION_10_3 1030
+#define MAC_OS_X_VERSION_10_4 1040
+#define MAC_OS_X_VERSION_10_5 1050
+#define MAC_OS_X_VERSION_10_6 1060
+#define MAC_OS_X_VERSION_10_7 1070
+#define MAC_OS_X_VERSION_10_8 1080
+#define MAC_OS_X_VERSION_10_9 1090
+#define MAC_OS_X_VERSION_10_10 101000
+#define MAC_OS_X_VERSION_10_10_2 101002
+#define MAC_OS_X_VERSION_10_10_3 101003
+#define MAC_OS_X_VERSION_10_11 101100
+#define MAC_OS_X_VERSION_10_11_2 101102
+#define MAC_OS_X_VERSION_10_11_3 101103
+#define MAC_OS_X_VERSION_10_11_4 101104
+#define MAC_OS_X_VERSION_10_12 101200
+#define MAC_OS_X_VERSION_10_12_1 101201
+#define MAC_OS_X_VERSION_10_12_2 101202
+#define MAC_OS_X_VERSION_10_12_4 101204
+#define MAC_OS_X_VERSION_10_13 101300
+#define MAC_OS_X_VERSION_10_13_1 101301
+#define MAC_OS_X_VERSION_10_13_2 101302
+#define MAC_OS_X_VERSION_10_13_4 101304
+#define MAC_OS_X_VERSION_10_14 101400
+#define MAC_OS_X_VERSION_10_14_1 101401
+#define MAC_OS_X_VERSION_10_14_4 101404
+#define MAC_OS_X_VERSION_10_15 101500
+#define MAC_OS_VERSION_11_0 110000
+#define MAC_OS_VERSION_11_1 110100
+#define MAC_OS_VERSION_11_3 110300
+
+/*
+ * If min OS not specified, assume 10.4 for intel
+ * Note: compiler driver may set _ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED_ based on MACOSX_DEPLOYMENT_TARGET environment variable
+ */
+#ifndef MAC_OS_X_VERSION_MIN_REQUIRED
+ #ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
+ #if (__i386__ || __x86_64__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < MAC_OS_X_VERSION_10_4)
+ #warning Building for Intel with Mac OS X Deployment Target < 10.4 is invalid.
+ #endif
+ #define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
+ #else
+ #if __i386__ || __x86_64__
+ #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_4
+ #elif __arm__ || __arm64__
+ #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_5
+ #else
+ #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_1
+ #endif
+ #endif
+#endif
+
+/*
+ * if max OS not specified, assume larger of (10.15, min)
+ */
+#ifndef MAC_OS_X_VERSION_MAX_ALLOWED
+ #if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_VERSION_11_3
+ #define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_MIN_REQUIRED
+ #else
+ #define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_VERSION_11_3
+ #endif
+#endif
+
+/*
+ * Error on bad values
+ */
+#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_MIN_REQUIRED
+ #error MAC_OS_X_VERSION_MAX_ALLOWED must be >= MAC_OS_X_VERSION_MIN_REQUIRED
+#endif
+#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_0
+ #error MAC_OS_X_VERSION_MIN_REQUIRED must be >= MAC_OS_X_VERSION_10_0
+#endif
+
+/*
+ * only certain compilers support __attribute__((weak_import))
+ */
+#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1020)
+ #define WEAK_IMPORT_ATTRIBUTE __attribute__((weak_import))
+#elif defined(__MWERKS__) && (__MWERKS__ >= 0x3205) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1020) && !defined(__INTEL__)
+ #define WEAK_IMPORT_ATTRIBUTE __attribute__((weak_import))
+#else
+ #define WEAK_IMPORT_ATTRIBUTE
+#endif
+
+/*
+ * only certain compilers support __attribute__((deprecated))
+ */
+#if defined(__has_feature) && defined(__has_attribute)
+ #if __has_attribute(deprecated)
+ #define DEPRECATED_ATTRIBUTE __attribute__((deprecated))
+ #if __has_feature(attribute_deprecated_with_message)
+ #define DEPRECATED_MSG_ATTRIBUTE(s) __attribute__((deprecated(s)))
+ #else
+ #define DEPRECATED_MSG_ATTRIBUTE(s) __attribute__((deprecated))
+ #endif
+ #else
+ #define DEPRECATED_ATTRIBUTE
+ #define DEPRECATED_MSG_ATTRIBUTE(s)
+ #endif
+#elif defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)))
+ #define DEPRECATED_ATTRIBUTE __attribute__((deprecated))
+ #if (__GNUC__ >= 5) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5))
+ #define DEPRECATED_MSG_ATTRIBUTE(s) __attribute__((deprecated(s)))
+ #else
+ #define DEPRECATED_MSG_ATTRIBUTE(s) __attribute__((deprecated))
+ #endif
+#else
+ #define DEPRECATED_ATTRIBUTE
+ #define DEPRECATED_MSG_ATTRIBUTE(s)
+#endif
+
+/*
+ * only certain compilers support __attribute__((unavailable))
+ */
+#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)))
+ #define UNAVAILABLE_ATTRIBUTE __attribute__((unavailable))
+#else
+ #define UNAVAILABLE_ATTRIBUTE
+#endif
+
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+ *
+ * Used on functions introduced in Mac OS X 10.0
+ */
+#define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on functions introduced in Mac OS X 10.0,
+ * and deprecated in Mac OS X 10.0
+ */
+#define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_0_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.0
+ */
+#define DEPRECATED_IN_MAC_OS_X_VERSION_10_0_AND_LATER DEPRECATED_ATTRIBUTE
+
+#ifndef __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #ifdef __has_attribute
+ #if __has_attribute(availability)
+ #include
+ #define __AVAILABILITY_MACROS_USES_AVAILABILITY 1
+ #endif
+ #endif
+#endif
+
+#if TARGET_OS_OSX
+#define __IPHONE_COMPAT_VERSION __IPHONE_NA
+#elif TARGET_OS_MACCATALYST
+#define __IPHONE_COMPAT_VERSION __IPHONE_NA
+#else
+#define __IPHONE_COMPAT_VERSION __IPHONE_4_0
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * and deprecated in Mac OS X 10.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_1
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_1 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * and deprecated in Mac OS X 10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_2
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_2 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_2
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_2 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * and deprecated in Mac OS X 10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * and deprecated in Mac OS X 10.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.5
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * and deprecated in Mac OS X 10.5
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_5, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.5
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_5, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.5
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_5, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.5
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_5, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.5
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_5, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.5
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_5, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.6
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * and deprecated in Mac OS X 10.6
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_6, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.6
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_6, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.6
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_6, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.6
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_6, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.6
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_6, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.6
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_6, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.6
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_6, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.7
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * and deprecated in Mac OS X 10.7
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_7, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.7
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_7, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.7
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_7, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.7
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.7
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_7, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.7
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_7, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.7
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_7, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.7
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_7, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_13
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.13
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+#define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_13 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_13, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+#define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_13 DEPRECATED_ATTRIBUTE
+#else
+#define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_13 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.8
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.8,
+ * and deprecated in Mac OS X 10.8
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_8, __MAC_10_8, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.8
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_8, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.8
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_8, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.8
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_8, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.8
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_8, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.8
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_8, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.8
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_8, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.8
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_8, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * but later deprecated in Mac OS X 10.8
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_8, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.9
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.9,
+ * and deprecated in Mac OS X 10.9
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_9, __MAC_10_9, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.9
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_9, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.9
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_9, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.9
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_9, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.9
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_9, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.9
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_9, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.9
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_9, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.9
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_9, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * but later deprecated in Mac OS X 10.9
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9
+ *
+ * Used on declarations introduced in Mac OS X 10.8,
+ * but later deprecated in Mac OS X 10.9
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_8, __MAC_10_9, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.10
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.10,
+ * and deprecated in Mac OS X 10.10
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_10, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.10
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_10, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.10
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_10, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.10
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_10, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.10
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_10, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.10
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.10
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_10, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.10
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_10, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * but later deprecated in Mac OS X 10.10
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_10, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10
+ *
+ * Used on declarations introduced in Mac OS X 10.8,
+ * but later deprecated in Mac OS X 10.10
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_8, __MAC_10_10, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10
+ *
+ * Used on declarations introduced in Mac OS X 10.9,
+ * but later deprecated in Mac OS X 10.10
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_9, __MAC_10_10, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_10_2, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.10.2,
+ * and deprecated in Mac OS X 10.10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_2, __MAC_10_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * but later deprecated in Mac OS X 10.10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2
+ *
+ * Used on declarations introduced in Mac OS X 10.8,
+ * but later deprecated in Mac OS X 10.10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_8, __MAC_10_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2
+ *
+ * Used on declarations introduced in Mac OS X 10.9,
+ * but later deprecated in Mac OS X 10.10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_9, __MAC_10_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2
+ *
+ * Used on declarations introduced in Mac OS X 10.10,
+ * but later deprecated in Mac OS X 10.10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_2 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_10_3, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.10.3,
+ * and deprecated in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_3, __MAC_10_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * but later deprecated in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.8,
+ * but later deprecated in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_8, __MAC_10_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.9,
+ * but later deprecated in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_9, __MAC_10_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.10,
+ * but later deprecated in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3
+ *
+ * Used on declarations introduced in Mac OS X 10.10.2,
+ * but later deprecated in Mac OS X 10.10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_2, __MAC_10_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_10_3 AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.11,
+ * and deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * but later deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11
+ *
+ * Used on declarations introduced in Mac OS X 10.8,
+ * but later deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_8, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11
+ *
+ * Used on declarations introduced in Mac OS X 10.9,
+ * but later deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_9, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11
+ *
+ * Used on declarations introduced in Mac OS X 10.10,
+ * but later deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11
+ *
+ * Used on declarations introduced in Mac OS X 10.10.2,
+ * but later deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_2, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11
+ *
+ * Used on declarations introduced in Mac OS X 10.10.3,
+ * but later deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_3, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11 AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_11_2, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.11.2,
+ * and deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_2, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.8,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_8, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.9,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_9, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.10,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.10.2,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_2, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.10.3,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_3, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2
+ *
+ * Used on declarations introduced in Mac OS X 10.11,
+ * but later deprecated in Mac OS X 10.11.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11, __MAC_10_11_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_2 AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_11_3, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.11.3,
+ * and deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_3, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.8,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_8, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.9,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_9, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.10,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.10.2,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_2, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.10.3,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_3, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.11,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3
+ *
+ * Used on declarations introduced in Mac OS X 10.11.2,
+ * but later deprecated in Mac OS X 10.11.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_2, __MAC_10_11_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_3
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_3 AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_11_4, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.11.4,
+ * and deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_4, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.8,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_8, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.9,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_9, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.10,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.10.2,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_2, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.10.3,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_3, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.11,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.11.2,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_2, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4
+ *
+ * Used on declarations introduced in Mac OS X 10.11.3,
+ * but later deprecated in Mac OS X 10.11.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_3, __MAC_10_11_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_11_4 AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.12,
+ * and deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.8,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_8, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.9,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_9, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.10,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.10.2,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_2, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.10.3,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_3, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.11,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.11.2,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_2, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.11.3,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_3, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12
+ *
+ * Used on declarations introduced in Mac OS X 10.11.4,
+ * but later deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_4, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12 AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_12_1, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.12.1,
+ * and deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12_1, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.8,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_8, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.9,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_9, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.10,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.10.2,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_2, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.10.3,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_3, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.11,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.11.2,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_2, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.11.3,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_3, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.11.4,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_4, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1
+ *
+ * Used on declarations introduced in Mac OS X 10.12,
+ * but later deprecated in Mac OS X 10.12.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_12_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_1
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_1 AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_12_2, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.12.2,
+ * and deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12_2, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.8,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_8, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.9,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_9, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.10,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.10.2,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_2, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.10.3,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_3, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.11,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.11.2,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_2, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.11.3,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_3, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.11.4,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_4, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.12,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2
+ *
+ * Used on declarations introduced in Mac OS X 10.12.1,
+ * but later deprecated in Mac OS X 10.12.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12_1, __MAC_10_12_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_2
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_2 AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_4_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_4_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_12_4, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_4_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_4_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_4_AND_LATER_BUT_DEPRECATED
+ *
+ * Used on declarations introduced in Mac OS X 10.12.4,
+ * and deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_4_AND_LATER_BUT_DEPRECATED __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12_4, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_4_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_4_AND_LATER_BUT_DEPRECATED AVAILABLE_MAC_OS_X_VERSION_10_12_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.0,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.1,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.2,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.3,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.4,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.5,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.6,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.7,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.8,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_8, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.9,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_9, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.10,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.10.2,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_2, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_10_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.10.3,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10_3, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.11,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.11.2,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_2, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_11_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.11.3,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_3, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_11_3_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.11.4,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_11_4, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_11_4_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.12,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.12.1,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12_1, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_12_1_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4
+ *
+ * Used on declarations introduced in Mac OS X 10.12.2,
+ * but later deprecated in Mac OS X 10.12.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12_2, __MAC_10_12_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12_4
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 DEPRECATED_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_12_4 AVAILABLE_MAC_OS_X_VERSION_10_12_2_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.13
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13
+ #define AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_13
+ #define AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_14_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.14
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_14_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_14, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_14
+ #define AVAILABLE_MAC_OS_X_VERSION_10_14_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_14
+ #define AVAILABLE_MAC_OS_X_VERSION_10_14_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_14_AND_LATER
+#endif
+
+/*
+ * AVAILABLE_MAC_OS_X_VERSION_10_15_AND_LATER
+ *
+ * Used on declarations introduced in Mac OS X 10.15
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define AVAILABLE_MAC_OS_X_VERSION_10_15_AND_LATER __OSX_AVAILABLE_STARTING(__MAC_10_15, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_15
+ #define AVAILABLE_MAC_OS_X_VERSION_10_15_AND_LATER UNAVAILABLE_ATTRIBUTE
+#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_15
+ #define AVAILABLE_MAC_OS_X_VERSION_10_15_AND_LATER WEAK_IMPORT_ATTRIBUTE
+#else
+ #define AVAILABLE_MAC_OS_X_VERSION_10_15_AND_LATER
+#endif
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_1_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.1
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_1_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_1, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_1
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_1_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_1_AND_LATER
+#endif
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_2_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.2
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_2_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_2, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_2
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_2_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_2_AND_LATER
+#endif
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_3_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.3
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_3_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_3, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_3_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_3_AND_LATER
+#endif
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_4_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_4_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_4_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_4_AND_LATER
+#endif
+
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_5_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.5
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_5_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_5, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_5_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_5_AND_LATER
+#endif
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.6
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_6, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER
+#endif
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.7
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_7, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_8_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.8
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_8_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_8, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_8_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_8_AND_LATER
+#endif
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_9_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.9
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_9_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_9, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_9_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_9_AND_LATER
+#endif
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_10_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.10
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_10_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_10, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_10_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_10_AND_LATER
+#endif
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_11_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.11
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_11_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_11, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_11_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_11_AND_LATER
+#endif
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_12_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.12
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_12_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_12, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_12_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_12_AND_LATER
+#endif
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_13_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.13
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_13_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_13, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_13_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_13_AND_LATER
+#endif
+
+/*
+ * DEPRECATED_IN_MAC_OS_X_VERSION_10_14_4_AND_LATER
+ *
+ * Used on types deprecated in Mac OS X 10.14.4
+ */
+#if __AVAILABILITY_MACROS_USES_AVAILABILITY
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_14_4_AND_LATER __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_14_4, __IPHONE_COMPAT_VERSION, __IPHONE_COMPAT_VERSION)
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14_4
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_14_4_AND_LATER DEPRECATED_ATTRIBUTE
+#else
+ #define DEPRECATED_IN_MAC_OS_X_VERSION_10_14_4_AND_LATER
+#endif
+
+#endif /* __AVAILABILITYMACROS__ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/AvailabilityVersions.h b/lib/libc/include/any-macos.11-any/AvailabilityVersions.h
index ed0bdfc91e..591e541d7f 100644
--- a/lib/libc/include/any-macos.11-any/AvailabilityVersions.h
+++ b/lib/libc/include/any-macos.11-any/AvailabilityVersions.h
@@ -60,11 +60,6 @@
#define __MAC_11_0 110000
#define __MAC_11_1 110100
#define __MAC_11_3 110300
-#define __MAC_11_4 110400
-#define __MAC_11_5 110500
-#define __MAC_11_6 110600
-#define __MAC_12_0 120000
-#define __MAC_12_1 120100
/* __MAC_NA is not defined to a value but is used as a token by macros to indicate that the API is unavailable */
#define __IPHONE_2_0 20000
@@ -119,12 +114,6 @@
#define __IPHONE_14_2 140200
#define __IPHONE_14_3 140300
#define __IPHONE_14_5 140500
-#define __IPHONE_14_6 140600
-#define __IPHONE_14_7 140700
-#define __IPHONE_14_8 140800
-#define __IPHONE_15_0 150000
-#define __IPHONE_15_1 150100
-#define __IPHONE_15_2 150200
/* __IPHONE_NA is not defined to a value but is used as a token by macros to indicate that the API is unavailable */
#define __TVOS_9_0 90000
@@ -153,11 +142,6 @@
#define __TVOS_14_2 140200
#define __TVOS_14_3 140300
#define __TVOS_14_5 140500
-#define __TVOS_14_6 140600
-#define __TVOS_14_7 140700
-#define __TVOS_15_0 150000
-#define __TVOS_15_1 150100
-#define __TVOS_15_2 150200
#define __WATCHOS_1_0 10000
#define __WATCHOS_2_0 20000
@@ -183,12 +167,6 @@
#define __WATCHOS_7_2 70200
#define __WATCHOS_7_3 70300
#define __WATCHOS_7_4 70400
-#define __WATCHOS_7_5 70500
-#define __WATCHOS_7_6 70600
-#define __WATCHOS_8_0 80000
-#define __WATCHOS_8_1 80100
-#define __WATCHOS_8_3 80300
-
/*
* Set up standard Mac OS X versions
@@ -229,12 +207,10 @@
#define MAC_OS_X_VERSION_10_15_1 101501
#define MAC_OS_X_VERSION_10_16 101600
#define MAC_OS_VERSION_11_0 110000
-#define MAC_OS_VERSION_12_0 120000
#endif /* #if (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) || defined(_DARWIN_C_SOURCE) */
#define __DRIVERKIT_19_0 190000
#define __DRIVERKIT_20_0 200000
-#define __DRIVERKIT_21_0 210000
#endif /* __AVAILABILITY_VERSIONS__ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/TargetConditionals.h b/lib/libc/include/any-macos.11-any/TargetConditionals.h
index 677604297d..e0a993f0ec 100644
--- a/lib/libc/include/any-macos.11-any/TargetConditionals.h
+++ b/lib/libc/include/any-macos.11-any/TargetConditionals.h
@@ -61,10 +61,8 @@
* The IOS/TV/WATCH conditionals are mutually exclusive.
*
*
- * TARGET_OS_WIN32 - Generated code will run under WIN32 API
- * TARGET_OS_WINDOWS - Generated code will run under Windows
+ * TARGET_OS_WIN32 - Generated code will run under 32-bit Windows
* TARGET_OS_UNIX - Generated code will run under some Unix (not OSX)
- * TARGET_OS_LINUX - Generated code will run under Linux
* TARGET_OS_MAC - Generated code will run under Mac OS X variant
* TARGET_OS_OSX - Generated code will run under OS X devices
* TARGET_OS_IPHONE - Generated code for firmware, devices, or simulator
@@ -180,7 +178,7 @@
/* -target=x86_64-apple-driverkit19.0 */
/* -target=arm64-apple-driverkit19.0 */
/* -target=arm64e-apple-driverkit19.0 */
- #if __is_target_vendor(apple) && __is_target_os(driverkit)
+ #if (__is_target_arch(x86_64) || __is_target_arch(arm64) || __is_target_arch(arm64e)) && __is_target_vendor(apple) && __is_target_os(driverkit)
#define TARGET_OS_OSX 0
#define TARGET_OS_IPHONE 0
#define TARGET_OS_IOS 0
@@ -216,9 +214,7 @@
#if defined(__GNUC__) && ( defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__) )
#define TARGET_OS_MAC 1
#define TARGET_OS_WIN32 0
- #define TARGET_OS_WINDOWS 0
#define TARGET_OS_UNIX 0
- #define TARGET_OS_LINUX 0
#if !DYNAMIC_TARGETS_ENABLED
#define TARGET_OS_OSX 1
@@ -359,9 +355,7 @@
#elif defined(__MWERKS__)
#define TARGET_OS_MAC 1
#define TARGET_OS_WIN32 0
- #define TARGET_OS_WINDOWS 0
#define TARGET_OS_UNIX 0
- #define TARGET_OS_LINUX 0
#define TARGET_OS_EMBEDDED 0
#if defined(__POWERPC__)
#define TARGET_CPU_PPC 1
@@ -487,9 +481,7 @@
#endif
#define TARGET_OS_MAC 1
#define TARGET_OS_WIN32 0
- #define TARGET_OS_WINDOWS 0
#define TARGET_OS_UNIX 0
- #define TARGET_OS_LINUX 0
#define TARGET_OS_EMBEDDED 0
#if TARGET_CPU_PPC || TARGET_CPU_PPC64
#define TARGET_RT_BIG_ENDIAN 1
diff --git a/lib/libc/include/any-macos.11-any/assert.h b/lib/libc/include/any-macos.11-any/assert.h
new file mode 100644
index 0000000000..e08d52cb28
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/assert.h
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)assert.h 8.2 (Berkeley) 1/21/94
+ * $FreeBSD: src/include/assert.h,v 1.4 2002/03/23 17:24:53 imp Exp $
+ */
+
+#include
+#ifdef __cplusplus
+#include
+#endif /* __cplusplus */
+
+/*
+ * Unlike other ANSI header files, may usefully be included
+ * multiple times, with and without NDEBUG defined.
+ */
+
+#undef assert
+#undef __assert
+
+#ifdef NDEBUG
+#define assert(e) ((void)0)
+#else
+
+#ifndef __GNUC__
+
+__BEGIN_DECLS
+#ifndef __cplusplus
+void abort(void) __dead2 __cold;
+#endif /* !__cplusplus */
+int printf(const char * __restrict, ...);
+__END_DECLS
+
+#define assert(e) \
+ ((void) ((e) ? ((void)0) : __assert (#e, __FILE__, __LINE__)))
+#define __assert(e, file, line) \
+ ((void)printf ("%s:%d: failed assertion `%s'\n", file, line, e), abort())
+
+#else /* __GNUC__ */
+
+__BEGIN_DECLS
+void __assert_rtn(const char *, const char *, int, const char *) __dead2 __cold __disable_tail_calls;
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && ((__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0) < 1070)
+void __eprintf(const char *, const char *, unsigned, const char *) __dead2 __cold;
+#endif
+__END_DECLS
+
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && ((__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0) < 1070)
+#define __assert(e, file, line) \
+ __eprintf ("%s:%d: failed assertion `%s'\n", file, line, e)
+#else
+/* 8462256: modified __assert_rtn() replaces deprecated __eprintf() */
+#define __assert(e, file, line) \
+ __assert_rtn ((const char *)-1L, file, line, e)
+#endif
+
+#if __DARWIN_UNIX03
+#define assert(e) \
+ (__builtin_expect(!(e), 0) ? __assert_rtn(__func__, __FILE__, __LINE__, #e) : (void)0)
+#else /* !__DARWIN_UNIX03 */
+#define assert(e) \
+ (__builtin_expect(!(e), 0) ? __assert (#e, __FILE__, __LINE__) : (void)0)
+#endif /* __DARWIN_UNIX03 */
+
+#endif /* __GNUC__ */
+#endif /* NDEBUG */
+
+#ifndef _ASSERT_H_
+#define _ASSERT_H_
+
+#ifndef __cplusplus
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+#define static_assert _Static_assert
+#endif /* __STDC_VERSION__ */
+#endif /* !__cplusplus */
+
+#endif /* _ASSERT_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/device/device_types.h b/lib/libc/include/any-macos.11-any/device/device_types.h
new file mode 100644
index 0000000000..2878666853
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/device/device_types.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * @OSF_COPYRIGHT@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 3/89
+ */
+
+#ifndef DEVICE_TYPES_H
+#define DEVICE_TYPES_H
+
+/*
+ * Types for device interface.
+ */
+#include
+#include
+#include
+#include
+
+
+
+/*
+ * IO buffer - out-of-line array of characters.
+ */
+typedef char * io_buf_ptr_t;
+
+/*
+ * Some types for IOKit.
+ */
+
+#ifdef IOKIT
+
+/* must match device_types.defs */
+typedef char io_name_t[128];
+typedef char io_string_t[512];
+typedef char io_string_inband_t[4096];
+typedef char io_struct_inband_t[4096];
+
+#if __LP64__
+typedef uint64_t io_user_scalar_t;
+typedef uint64_t io_user_reference_t;
+typedef io_user_scalar_t io_scalar_inband_t[16];
+typedef io_user_reference_t io_async_ref_t[8];
+typedef io_user_scalar_t io_scalar_inband64_t[16];
+typedef io_user_reference_t io_async_ref64_t[8];
+#else
+typedef int io_user_scalar_t;
+typedef natural_t io_user_reference_t;
+typedef io_user_scalar_t io_scalar_inband_t[16];
+typedef io_user_reference_t io_async_ref_t[8];
+typedef uint64_t io_scalar_inband64_t[16];
+typedef uint64_t io_async_ref64_t[8];
+#endif // __LP64__
+
+
+#ifndef __IOKIT_PORTS_DEFINED__
+#define __IOKIT_PORTS_DEFINED__
+typedef mach_port_t io_object_t;
+#endif /* __IOKIT_PORTS_DEFINED__ */
+
+
+#endif /* IOKIT */
+
+#endif /* DEVICE_TYPES_H */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/dispatch/base.h b/lib/libc/include/any-macos.11-any/dispatch/base.h
new file mode 100644
index 0000000000..86ed15d144
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/dispatch/base.h
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2008-2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+#ifndef __DISPATCH_BASE__
+#define __DISPATCH_BASE__
+
+#ifndef __DISPATCH_INDIRECT__
+#error "Please #include instead of this file directly."
+#endif
+
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+#ifndef __has_include
+#define __has_include(x) 0
+#endif
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+#ifndef __has_extension
+#define __has_extension(x) 0
+#endif
+
+#if __GNUC__
+#define DISPATCH_NORETURN __attribute__((__noreturn__))
+#define DISPATCH_NOTHROW __attribute__((__nothrow__))
+#define DISPATCH_NONNULL1 __attribute__((__nonnull__(1)))
+#define DISPATCH_NONNULL2 __attribute__((__nonnull__(2)))
+#define DISPATCH_NONNULL3 __attribute__((__nonnull__(3)))
+#define DISPATCH_NONNULL4 __attribute__((__nonnull__(4)))
+#define DISPATCH_NONNULL5 __attribute__((__nonnull__(5)))
+#define DISPATCH_NONNULL6 __attribute__((__nonnull__(6)))
+#define DISPATCH_NONNULL7 __attribute__((__nonnull__(7)))
+#if __clang__ && __clang_major__ < 3
+// rdar://problem/6857843
+#define DISPATCH_NONNULL_ALL
+#else
+#define DISPATCH_NONNULL_ALL __attribute__((__nonnull__))
+#endif
+#define DISPATCH_SENTINEL __attribute__((__sentinel__))
+#define DISPATCH_PURE __attribute__((__pure__))
+#define DISPATCH_CONST __attribute__((__const__))
+#define DISPATCH_WARN_RESULT __attribute__((__warn_unused_result__))
+#define DISPATCH_MALLOC __attribute__((__malloc__))
+#define DISPATCH_ALWAYS_INLINE __attribute__((__always_inline__))
+#define DISPATCH_UNAVAILABLE __attribute__((__unavailable__))
+#define DISPATCH_UNAVAILABLE_MSG(msg) __attribute__((__unavailable__(msg)))
+#elif defined(_MSC_VER)
+#define DISPATCH_NORETURN __declspec(noreturn)
+#define DISPATCH_NOTHROW __declspec(nothrow)
+#define DISPATCH_NONNULL1
+#define DISPATCH_NONNULL2
+#define DISPATCH_NONNULL3
+#define DISPATCH_NONNULL4
+#define DISPATCH_NONNULL5
+#define DISPATCH_NONNULL6
+#define DISPATCH_NONNULL7
+#define DISPATCH_NONNULL_ALL
+#define DISPATCH_SENTINEL
+#define DISPATCH_PURE
+#define DISPATCH_CONST
+#if (_MSC_VER >= 1700)
+#define DISPATCH_WARN_RESULT _Check_return_
+#else
+#define DISPATCH_WARN_RESULT
+#endif
+#define DISPATCH_MALLOC
+#define DISPATCH_ALWAYS_INLINE __forceinline
+#define DISPATCH_UNAVAILABLE
+#define DISPATCH_UNAVAILABLE_MSG(msg)
+#else
+/*! @parseOnly */
+#define DISPATCH_NORETURN
+/*! @parseOnly */
+#define DISPATCH_NOTHROW
+/*! @parseOnly */
+#define DISPATCH_NONNULL1
+/*! @parseOnly */
+#define DISPATCH_NONNULL2
+/*! @parseOnly */
+#define DISPATCH_NONNULL3
+/*! @parseOnly */
+#define DISPATCH_NONNULL4
+/*! @parseOnly */
+#define DISPATCH_NONNULL5
+/*! @parseOnly */
+#define DISPATCH_NONNULL6
+/*! @parseOnly */
+#define DISPATCH_NONNULL7
+/*! @parseOnly */
+#define DISPATCH_NONNULL_ALL
+/*! @parseOnly */
+#define DISPATCH_SENTINEL
+/*! @parseOnly */
+#define DISPATCH_PURE
+/*! @parseOnly */
+#define DISPATCH_CONST
+/*! @parseOnly */
+#define DISPATCH_WARN_RESULT
+/*! @parseOnly */
+#define DISPATCH_MALLOC
+/*! @parseOnly */
+#define DISPATCH_ALWAYS_INLINE
+/*! @parseOnly */
+#define DISPATCH_UNAVAILABLE
+/*! @parseOnly */
+#define DISPATCH_UNAVAILABLE_MSG(msg)
+#endif
+
+#define DISPATCH_LINUX_UNAVAILABLE()
+
+#ifdef __FreeBSD__
+#define DISPATCH_FREEBSD_UNAVAILABLE() \
+ DISPATCH_UNAVAILABLE_MSG( \
+ "This interface is unavailable on FreeBSD systems")
+#else
+#define DISPATCH_FREEBSD_UNAVAILABLE()
+#endif
+
+#ifndef DISPATCH_ALIAS_V2
+#if TARGET_OS_MAC
+#define DISPATCH_ALIAS_V2(sym) __asm__("_" #sym "$V2")
+#else
+#define DISPATCH_ALIAS_V2(sym)
+#endif
+#endif
+
+#if defined(_WIN32)
+#if defined(__cplusplus)
+#define DISPATCH_EXPORT extern "C" __declspec(dllimport)
+#else
+#define DISPATCH_EXPORT extern __declspec(dllimport)
+#endif
+#elif __GNUC__
+#define DISPATCH_EXPORT extern __attribute__((visibility("default")))
+#else
+#define DISPATCH_EXPORT extern
+#endif
+
+#if __GNUC__
+#define DISPATCH_INLINE static __inline__
+#else
+#define DISPATCH_INLINE static inline
+#endif
+
+#if __GNUC__
+#define DISPATCH_EXPECT(x, v) __builtin_expect((x), (v))
+#define dispatch_compiler_barrier() __asm__ __volatile__("" ::: "memory")
+#else
+#define DISPATCH_EXPECT(x, v) (x)
+#define dispatch_compiler_barrier() do { } while (0)
+#endif
+
+#if __has_attribute(not_tail_called)
+#define DISPATCH_NOT_TAIL_CALLED __attribute__((__not_tail_called__))
+#else
+#define DISPATCH_NOT_TAIL_CALLED
+#endif
+
+#if __has_builtin(__builtin_assume)
+#define DISPATCH_COMPILER_CAN_ASSUME(expr) __builtin_assume(expr)
+#else
+#define DISPATCH_COMPILER_CAN_ASSUME(expr) ((void)(expr))
+#endif
+
+#if __has_attribute(noescape)
+#define DISPATCH_NOESCAPE __attribute__((__noescape__))
+#else
+#define DISPATCH_NOESCAPE
+#endif
+
+#if __has_attribute(cold)
+#define DISPATCH_COLD __attribute__((__cold__))
+#else
+#define DISPATCH_COLD
+#endif
+
+#if __has_feature(assume_nonnull)
+#define DISPATCH_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
+#define DISPATCH_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end")
+#else
+#define DISPATCH_ASSUME_NONNULL_BEGIN
+#define DISPATCH_ASSUME_NONNULL_END
+#endif
+
+#if !__has_feature(nullability)
+#ifndef _Nullable
+#define _Nullable
+#endif
+#ifndef _Nonnull
+#define _Nonnull
+#endif
+#ifndef _Null_unspecified
+#define _Null_unspecified
+#endif
+#endif
+
+#ifndef DISPATCH_RETURNS_RETAINED_BLOCK
+#if __has_attribute(ns_returns_retained)
+#define DISPATCH_RETURNS_RETAINED_BLOCK __attribute__((__ns_returns_retained__))
+#else
+#define DISPATCH_RETURNS_RETAINED_BLOCK
+#endif
+#endif
+
+#if __has_attribute(enum_extensibility)
+#define __DISPATCH_ENUM_ATTR __attribute__((__enum_extensibility__(open)))
+#define __DISPATCH_ENUM_ATTR_CLOSED __attribute__((__enum_extensibility__(closed)))
+#else
+#define __DISPATCH_ENUM_ATTR
+#define __DISPATCH_ENUM_ATTR_CLOSED
+#endif // __has_attribute(enum_extensibility)
+
+#if __has_attribute(flag_enum)
+#define __DISPATCH_OPTIONS_ATTR __attribute__((__flag_enum__))
+#else
+#define __DISPATCH_OPTIONS_ATTR
+#endif // __has_attribute(flag_enum)
+
+
+#if __has_feature(objc_fixed_enum) || __has_extension(cxx_strong_enums) || \
+ __has_extension(cxx_fixed_enum) || defined(_WIN32)
+#define DISPATCH_ENUM(name, type, ...) \
+ typedef enum : type { __VA_ARGS__ } __DISPATCH_ENUM_ATTR name##_t
+#define DISPATCH_OPTIONS(name, type, ...) \
+ typedef enum : type { __VA_ARGS__ } __DISPATCH_OPTIONS_ATTR __DISPATCH_ENUM_ATTR name##_t
+#else
+#define DISPATCH_ENUM(name, type, ...) \
+ enum { __VA_ARGS__ } __DISPATCH_ENUM_ATTR; typedef type name##_t
+#define DISPATCH_OPTIONS(name, type, ...) \
+ enum { __VA_ARGS__ } __DISPATCH_OPTIONS_ATTR __DISPATCH_ENUM_ATTR; typedef type name##_t
+#endif // __has_feature(objc_fixed_enum) ...
+
+
+
+#if __has_feature(enumerator_attributes)
+#define DISPATCH_ENUM_API_AVAILABLE(...) API_AVAILABLE(__VA_ARGS__)
+#define DISPATCH_ENUM_API_DEPRECATED(...) API_DEPRECATED(__VA_ARGS__)
+#define DISPATCH_ENUM_API_DEPRECATED_WITH_REPLACEMENT(...) \
+ API_DEPRECATED_WITH_REPLACEMENT(__VA_ARGS__)
+#else
+#define DISPATCH_ENUM_API_AVAILABLE(...)
+#define DISPATCH_ENUM_API_DEPRECATED(...)
+#define DISPATCH_ENUM_API_DEPRECATED_WITH_REPLACEMENT(...)
+#endif
+
+#ifdef __swift__
+#define DISPATCH_SWIFT3_OVERLAY 1
+#else // __swift__
+#define DISPATCH_SWIFT3_OVERLAY 0
+#endif // __swift__
+
+#if __has_feature(attribute_availability_swift)
+#define DISPATCH_SWIFT_UNAVAILABLE(_msg) \
+ __attribute__((__availability__(swift, unavailable, message=_msg)))
+#else
+#define DISPATCH_SWIFT_UNAVAILABLE(_msg)
+#endif
+
+#if DISPATCH_SWIFT3_OVERLAY
+#define DISPATCH_SWIFT3_UNAVAILABLE(_msg) DISPATCH_SWIFT_UNAVAILABLE(_msg)
+#else
+#define DISPATCH_SWIFT3_UNAVAILABLE(_msg)
+#endif
+
+#if __has_attribute(swift_private)
+#define DISPATCH_REFINED_FOR_SWIFT __attribute__((__swift_private__))
+#else
+#define DISPATCH_REFINED_FOR_SWIFT
+#endif
+
+#if __has_attribute(swift_name)
+#define DISPATCH_SWIFT_NAME(_name) __attribute__((__swift_name__(#_name)))
+#else
+#define DISPATCH_SWIFT_NAME(_name)
+#endif
+
+#ifndef __cplusplus
+#define DISPATCH_TRANSPARENT_UNION __attribute__((__transparent_union__))
+#else
+#define DISPATCH_TRANSPARENT_UNION
+#endif
+
+typedef void (*dispatch_function_t)(void *_Nullable);
+
+#endif
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/dispatch/queue.h b/lib/libc/include/any-macos.11-any/dispatch/queue.h
index 8d08a30458..f4f8ab673e 100644
--- a/lib/libc/include/any-macos.11-any/dispatch/queue.h
+++ b/lib/libc/include/any-macos.11-any/dispatch/queue.h
@@ -480,7 +480,7 @@ DISPATCH_EXPORT DISPATCH_NONNULL3 DISPATCH_NOTHROW
void
dispatch_apply(size_t iterations,
dispatch_queue_t DISPATCH_APPLY_QUEUE_ARG_NULLABILITY queue,
- DISPATCH_NOESCAPE void (^block)(size_t iteration));
+ DISPATCH_NOESCAPE void (^block)(size_t));
#endif
/*!
@@ -515,7 +515,7 @@ DISPATCH_EXPORT DISPATCH_NONNULL4 DISPATCH_NOTHROW
void
dispatch_apply_f(size_t iterations,
dispatch_queue_t DISPATCH_APPLY_QUEUE_ARG_NULLABILITY queue,
- void *_Nullable context, void (*work)(void *_Nullable context, size_t iteration));
+ void *_Nullable context, void (*work)(void *_Nullable, size_t));
/*!
* @function dispatch_get_current_queue
diff --git a/lib/libc/include/any-macos.11-any/execinfo.h b/lib/libc/include/any-macos.11-any/execinfo.h
new file mode 100644
index 0000000000..65d9d20486
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/execinfo.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#ifndef _EXECINFO_H_
+#define _EXECINFO_H_ 1
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+__BEGIN_DECLS
+
+int backtrace(void**,int) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+
+API_AVAILABLE(macosx(10.14), ios(12.0), tvos(12.0), watchos(5.0))
+OS_EXPORT
+int backtrace_from_fp(void *startfp, void **array, int size);
+
+char** backtrace_symbols(void* const*,int) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+void backtrace_symbols_fd(void* const*,int,int) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+
+struct image_offset {
+ /*
+ * The UUID of the image.
+ */
+ uuid_t uuid;
+
+ /*
+ * The offset is relative to the __TEXT section of the image.
+ */
+ uint32_t offset;
+};
+
+API_AVAILABLE(macosx(10.14), ios(12.0), tvos(12.0), watchos(5.0))
+OS_EXPORT
+void backtrace_image_offsets(void* const* array,
+ struct image_offset *image_offsets, int size);
+
+__END_DECLS
+
+#endif /* !_EXECINFO_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/gethostuuid.h b/lib/libc/include/any-macos.11-any/gethostuuid.h
new file mode 100644
index 0000000000..cc7f473118
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/gethostuuid.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#ifndef __GETHOSTUUID_H
+#define __GETHOSTUUID_H
+
+#include
+#include
+#include
+
+#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0)
+int gethostuuid(uuid_t, const struct timespec *) __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_NA, __MAC_NA, __IPHONE_2_0, __IPHONE_5_0, "gethostuuid() is no longer supported");
+#else
+int gethostuuid(uuid_t, const struct timespec *) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA);
+#endif
+
+#endif /* __GETHOSTUUID_H */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/libkern/OSDebug.h b/lib/libc/include/any-macos.11-any/libkern/OSDebug.h
new file mode 100644
index 0000000000..a465b46326
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/libkern/OSDebug.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * HISTORY
+ *
+ */
+
+#ifndef _OS_OSDEBBUG_H
+#define _OS_OSDEBBUG_H
+
+#include
+#include
+
+__BEGIN_DECLS
+
+extern int log_leaks;
+
+/* Use kernel_debug() to log a backtrace */
+extern void trace_backtrace(unsigned int debugid, unsigned int debugid2, unsigned long size, unsigned long data);
+/* Report a message with a 4 entry backtrace - very slow */
+extern void OSReportWithBacktrace(const char *str, ...);
+extern unsigned OSBacktrace(void **bt, unsigned maxAddrs);
+
+/* Simple dump of 20 backtrace entries */
+extern void OSPrintBacktrace(void);
+
+/*! @function OSKernelStackRemaining
+ * @abstract Returns bytes available below the current stack frame.
+ * @discussion Returns bytes available below the current stack frame. Safe for interrupt or thread context.
+ * @result Approximate byte count available. */
+
+vm_offset_t OSKernelStackRemaining( void );
+
+__END_DECLS
+
+#define TRACE_MACHLEAKS(a, b, c, d) \
+do { \
+ if (__builtin_expect(!!log_leaks, 0)) \
+ trace_backtrace(a,b,c,d); \
+} while(0)
+
+#endif /* !_OS_OSDEBBUG_H */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/libkern/OSKextLib.h b/lib/libc/include/any-macos.11-any/libkern/OSKextLib.h
new file mode 100644
index 0000000000..7b2e1c2da2
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/libkern/OSKextLib.h
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#ifndef _LIBKERN_OSKEXTLIB_H
+#define _LIBKERN_OSKEXTLIB_H
+
+#include
+__BEGIN_DECLS
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+/*!
+ * @header
+ *
+ * Declares functions, basic return values, and other constants
+ * related to kernel extensions (kexts).
+ */
+
+#if PRAGMA_MARK
+#pragma mark -
+/********************************************************************/
+#pragma mark OSReturn Values for Kernel Extensions
+/********************************************************************/
+#endif
+/*!
+ * @group OSReturn Values for Kernel Extensions
+ * Many kext-related functions return these values,
+ * as well as those defined under
+ * @link //apple_ref/c/tdef/OSReturn OSReturn@/link
+ * and other variants of kern_return_t.
+ */
+
+
+#define sub_libkern_kext err_sub(2)
+#define libkern_kext_err(code) (sys_libkern|sub_libkern_kext|(code))
+
+
+/*!
+ * @define kOSKextReturnInternalError
+ * @abstract An internal error in the kext library.
+ * Contrast with @link //apple_ref/c/econst/OSReturnError
+ * OSReturnError@/link.
+ */
+#define kOSKextReturnInternalError libkern_kext_err(0x1)
+
+/*!
+ * @define kOSKextReturnNoMemory
+ * @abstract Memory allocation failed.
+ */
+#define kOSKextReturnNoMemory libkern_kext_err(0x2)
+
+/*!
+ * @define kOSKextReturnNoResources
+ * @abstract Some resource other than memory (such as available load tags)
+ * is exhausted.
+ */
+#define kOSKextReturnNoResources libkern_kext_err(0x3)
+
+/*!
+ * @define kOSKextReturnNotPrivileged
+ * @abstract The caller lacks privileges to perform the requested operation.
+ */
+#define kOSKextReturnNotPrivileged libkern_kext_err(0x4)
+
+/*!
+ * @define kOSKextReturnInvalidArgument
+ * @abstract Invalid argument.
+ */
+#define kOSKextReturnInvalidArgument libkern_kext_err(0x5)
+
+/*!
+ * @define kOSKextReturnNotFound
+ * @abstract Search item not found.
+ */
+#define kOSKextReturnNotFound libkern_kext_err(0x6)
+
+/*!
+ * @define kOSKextReturnBadData
+ * @abstract Malformed data (not used for XML).
+ */
+#define kOSKextReturnBadData libkern_kext_err(0x7)
+
+/*!
+ * @define kOSKextReturnSerialization
+ * @abstract Error converting or (un)serializing URL, string, or XML.
+ */
+#define kOSKextReturnSerialization libkern_kext_err(0x8)
+
+/*!
+ * @define kOSKextReturnUnsupported
+ * @abstract Operation is no longer or not yet supported.
+ */
+#define kOSKextReturnUnsupported libkern_kext_err(0x9)
+
+/*!
+ * @define kOSKextReturnDisabled
+ * @abstract Operation is currently disabled.
+ */
+#define kOSKextReturnDisabled libkern_kext_err(0xa)
+
+/*!
+ * @define kOSKextReturnNotAKext
+ * @abstract Bundle is not a kernel extension.
+ */
+#define kOSKextReturnNotAKext libkern_kext_err(0xb)
+
+/*!
+ * @define kOSKextReturnValidation
+ * @abstract Validation failures encountered; check diagnostics for details.
+ */
+#define kOSKextReturnValidation libkern_kext_err(0xc)
+
+/*!
+ * @define kOSKextReturnAuthentication
+ * @abstract Authetication failures encountered; check diagnostics for details.
+ */
+#define kOSKextReturnAuthentication libkern_kext_err(0xd)
+
+/*!
+ * @define kOSKextReturnDependencies
+ * @abstract Dependency resolution failures encountered; check diagnostics for details.
+ */
+#define kOSKextReturnDependencies libkern_kext_err(0xe)
+
+/*!
+ * @define kOSKextReturnArchNotFound
+ * @abstract Kext does not contain code for the requested architecture.
+ */
+#define kOSKextReturnArchNotFound libkern_kext_err(0xf)
+
+/*!
+ * @define kOSKextReturnCache
+ * @abstract An error occurred processing a system kext cache.
+ */
+#define kOSKextReturnCache libkern_kext_err(0x10)
+
+/*!
+ * @define kOSKextReturnDeferred
+ * @abstract Operation has been posted asynchronously to user space (kernel only).
+ */
+#define kOSKextReturnDeferred libkern_kext_err(0x11)
+
+/*!
+ * @define kOSKextReturnBootLevel
+ * @abstract Kext not loadable or operation not allowed at current boot level.
+ */
+#define kOSKextReturnBootLevel libkern_kext_err(0x12)
+
+/*!
+ * @define kOSKextReturnNotLoadable
+ * @abstract Kext cannot be loaded; check diagnostics for details.
+ */
+#define kOSKextReturnNotLoadable libkern_kext_err(0x13)
+
+/*!
+ * @define kOSKextReturnLoadedVersionDiffers
+ * @abstract A different version (or executable UUID, or executable by checksum)
+ * of the requested kext is already loaded.
+ */
+#define kOSKextReturnLoadedVersionDiffers libkern_kext_err(0x14)
+
+/*!
+ * @define kOSKextReturnDependencyLoadError
+ * @abstract A load error occurred on a dependency of the kext being loaded.
+ */
+#define kOSKextReturnDependencyLoadError libkern_kext_err(0x15)
+
+/*!
+ * @define kOSKextReturnLinkError
+ * @abstract A link failure occured with this kext or a dependency.
+ */
+#define kOSKextReturnLinkError libkern_kext_err(0x16)
+
+/*!
+ * @define kOSKextReturnStartStopError
+ * @abstract The kext start or stop routine returned an error.
+ */
+#define kOSKextReturnStartStopError libkern_kext_err(0x17)
+
+/*!
+ * @define kOSKextReturnInUse
+ * @abstract The kext is currently in use or has outstanding references,
+ * and cannot be unloaded.
+ */
+#define kOSKextReturnInUse libkern_kext_err(0x18)
+
+/*!
+ * @define kOSKextReturnTimeout
+ * @abstract A kext request has timed out.
+ */
+#define kOSKextReturnTimeout libkern_kext_err(0x19)
+
+/*!
+ * @define kOSKextReturnStopping
+ * @abstract The kext is in the process of stopping; requests cannot be made.
+ */
+#define kOSKextReturnStopping libkern_kext_err(0x1a)
+
+/*!
+ * @define kOSKextReturnSystemPolicy
+ * @abstract The kext was prevented from loading due to system policy.
+ */
+#define kOSKextReturnSystemPolicy libkern_kext_err(0x1b)
+
+/*!
+ * @define kOSKextReturnKCLoadFailure
+ * @abstract Loading of the System KC failed
+ */
+#define kOSKextReturnKCLoadFailure libkern_kext_err(0x1c)
+
+/*!
+ * @define kOSKextReturnKCLoadFailureSystemKC
+ * @abstract Loading of the System KC failed
+ *
+ * This a sub-code of kOSKextReturnKCLoadFailure. It can be OR'd together
+ * with: kOSKextReturnKCLoadFailureAuxKC
+ *
+ * If both the System and Aux KCs fail to load, then the error code will be:
+ * libkern_kext_err(0x1f)
+ */
+#define kOSKextReturnKCLoadFailureSystemKC libkern_kext_err(0x1d)
+
+/*!
+ * @define kOSKextReturnKCLoadFailureAuxKC
+ * @abstract Loading of the Aux KC failed
+ *
+ * This a sub-code of kOSKextReturnKCLoadFailure. It can be OR'd together
+ * with: kOSKextReturnKCLoadFailureSystemKC
+ *
+ * If both the System and Aux KCs fail to load, then the error code will be:
+ * libkern_kext_err(0x1f)
+ */
+#define kOSKextReturnKCLoadFailureAuxKC libkern_kext_err(0x1e)
+
+/* next available error is: libkern_kext_err(0x20) */
+
+#if PRAGMA_MARK
+#pragma mark -
+/********************************************************************/
+#pragma mark Kext/OSBundle Property List Keys
+/********************************************************************/
+#endif
+/*!
+ * @group Kext Property List Keys
+ * These constants cover CFBundle properties defined for kernel extensions.
+ * Because they are used in the kernel, if you want to use one with
+ * CFBundle APIs you'll need to wrap it in a CFSTR() macro.
+ */
+
+
+/*!
+ * @define kOSBundleCompatibleVersionKey
+ * @abstract A string giving the backwards-compatible version of a library kext
+ * in extended Mac OS 'vers' format (####.##.##s{1-255} where 's'
+ * is a build stage 'd', 'a', 'b', 'f' or 'fc').
+ */
+#define kOSBundleCompatibleVersionKey "OSBundleCompatibleVersion"
+
+/*!
+ * @define kOSBundleEnableKextLoggingKey
+ * @abstract Set to true to have the kernel kext logging spec applied
+ * to the kext.
+ * See @link //apple_ref/c/econst/OSKextLogSpec
+ * OSKextLogSpec@/link.
+ */
+#define kOSBundleEnableKextLoggingKey "OSBundleEnableKextLogging"
+
+/*!
+ * @define kOSBundleIsInterfaceKey
+ * @abstract A boolean value indicating whether the kext executable
+ * contains only symbol references.
+ */
+#define kOSBundleIsInterfaceKey "OSBundleIsInterface"
+
+/*!
+ * @define kOSBundleLibrariesKey
+ * @abstract A dictionary listing link dependencies for this kext.
+ * Keys are bundle identifiers, values are version strings.
+ */
+#define kOSBundleLibrariesKey "OSBundleLibraries"
+
+/*!
+ * @define kOSBundleRequiredKey
+ * @abstract A string indicating in which kinds of startup this kext
+ * may need to load during early startup (before
+ * @link //apple_ref/doc/man/8/kextd kextcache(8)@/link).
+ * @discussion
+ * The value is one of:
+ *
+ * - @link kOSBundleRequiredRoot "OSBundleRequiredRoot"@/link
+ * - @link kOSBundleRequiredLocalRoot "OSBundleRequiredLocalRoot"@/link
+ * - @link kOSBundleRequiredNetworkRoot "OSBundleRequiredNetworkRoot"@/link
+ * - @link kOSBundleRequiredSafeBoot "OSBundleRequiredSafeBoot"@/link
+ * - @link kOSBundleRequiredConsole "OSBundleRequiredConsole"@/link
+ *
+ *
+ * Use this property judiciously.
+ * Every kext that declares a value other than "OSBundleRequiredSafeBoot"
+ * increases startup time, as the booter must read it into memory,
+ * or startup kext caches must include it.
+ */
+#define kOSBundleRequiredKey "OSBundleRequired"
+
+/*!
+ * @define kOSBundleRequireExplicitLoadKey
+ * @abstract A boolean value indicating whether the kext requires an
+ * explicit kextload in order to start/match.
+ */
+#define kOSBundleRequireExplicitLoadKey "OSBundleRequireExplicitLoad"
+
+/*!
+ * @define kOSBundleAllowUserLoadKey
+ * @abstract A boolean value indicating whether
+ * @link //apple_ref/doc/man/8/kextd kextcache(8)@/link
+ * will honor a non-root process's request to load a kext.
+ * @discussion
+ * See @link //apple_ref/doc/compositePage/c/func/KextManagerLoadKextWithURL
+ * KextManagerLoadKextWithURL@/link
+ * and @link //apple_ref/doc/compositePage/c/func/KextManagerLoadKextWithIdentifier
+ * KextManagerLoadKextWithIdentifier@/link.
+ */
+#define kOSBundleAllowUserLoadKey "OSBundleAllowUserLoad"
+
+/*!
+ * @define kOSBundleAllowUserTerminateKey
+ * @abstract A boolean value indicating whether the kextunload tool
+ * is allowed to issue IOService terminate to classes defined in this kext.
+ * @discussion A boolean value indicating whether the kextunload tool
+ * is allowed to issue IOService terminate to classes defined in this kext.
+ */
+#define kOSBundleAllowUserTerminateKey "OSBundleAllowUserTerminate"
+
+/*!
+ * @define kOSKernelResourceKey
+ * @abstract A boolean value indicating whether the kext represents a built-in
+ * component of the kernel.
+ */
+#define kOSKernelResourceKey "OSKernelResource"
+
+/*!
+ * @define kOSKextVariantOverrideKey
+ * @abstract A dictionary with target names as key and a target-specific variant
+ * name as value.
+ */
+#define kOSKextVariantOverrideKey "OSKextVariantOverride"
+
+/*!
+ * @define kIOKitPersonalitiesKey
+ * @abstract A dictionary of dictionaries used in matching for I/O Kit drivers.
+ */
+#define kIOKitPersonalitiesKey "IOKitPersonalities"
+
+/*
+ * @define kIOPersonalityPublisherKey
+ * @abstract Used in personalities sent to the I/O Kit,
+ * contains the CFBundleIdentifier of the kext
+ * that the personality originated in.
+ */
+#define kIOPersonalityPublisherKey "IOPersonalityPublisher"
+
+#if CONFIG_KEC_FIPS
+/*
+ * @define kAppleTextHashesKey
+ * @abstract A dictionary conataining hashes for corecrypto kext.
+ */
+#define kAppleTextHashesKey "AppleTextHashes"
+#endif
+
+/*!
+ * @define kOSMutableSegmentCopy
+ * @abstract A boolean value indicating whether the kext requires a copy of
+ * its mutable segments to be kept in memory, and then reset when the kext
+ * unloads. This should be used with caution as it will increase the
+ * amount of memory used by the kext.
+ */
+#define kOSMutableSegmentCopy "OSMutableSegmentCopy"
+
+
+#if PRAGMA_MARK
+/********************************************************************/
+#pragma mark Kext/OSBundle Property Deprecated Keys
+/********************************************************************/
+#endif
+/*
+ * @define kOSBundleDebugLevelKey
+ * @abstract
+ * Deprecated (used on some releases of Mac OS X prior to 10.6 Snow Leopard).
+ * Value is an integer from 1-6, corresponding to the verbose levels
+ * of kext tools on those releases.
+ * On 10.6 Snow Leopard, use @link OSKextEnableKextLogging
+ * OSKextEnableKextLogging@/link.
+ */
+#define kOSBundleDebugLevelKey "OSBundleDebugLevel"
+
+/*!
+ * @define kOSBundleSharedExecutableIdentifierKey
+ * @abstract Deprecated (used on some releases of Mac OS X
+ * prior to 10.6 Snow Leopard).
+ * Value is the bundle identifier of the pseudokext
+ * that contains an executable shared by this kext.
+ */
+#define kOSBundleSharedExecutableIdentifierKey "OSBundleSharedExecutableIdentifier"
+
+
+#if PRAGMA_MARK
+/********************************************************************/
+#pragma mark Kext/OSBundle Property List Values
+/********************************************************************/
+#endif
+
+/*!
+ * @group Kext Property List Values
+ * These constants encompass established values
+ * for kernel extension bundle properties.
+ */
+
+/*!
+ * @define kOSKextKernelIdentifier
+ * @abstract
+ * This is the CFBundleIdentifier user for the kernel itself.
+ */
+#define kOSKextKernelIdentifier "__kernel__"
+
+/*!
+ * @define kOSKextBundlePackageTypeKext
+ * @abstract
+ * The bundle type value for Kernel Extensions.
+ */
+#define kOSKextBundlePackageTypeKext "KEXT"
+
+/*!
+ * @define kOSKextBundlePackageTypeDriverKit
+ * @abstract
+ * The bundle type value for Driver Extensions.
+ */
+#define kOSKextBundlePackageTypeDriverKit "DEXT"
+
+/*!
+ * @define kOSBundleRequiredRoot
+ * @abstract
+ * This @link kOSBundleRequiredKey OSBundleRequired@/link
+ * value indicates that the kext may be needed to mount the root filesystem
+ * whether starting from a local or a network volume.
+ */
+#define kOSBundleRequiredRoot "Root"
+
+/*!
+ * @define kOSBundleRequiredLocalRoot
+ * @abstract
+ * This @link kOSBundleRequiredKey OSBundleRequired@/link
+ * value indicates that the kext may be needed to mount the root filesystem
+ * when starting from a local disk.
+ */
+#define kOSBundleRequiredLocalRoot "Local-Root"
+
+/*!
+ * @define kOSBundleRequiredNetworkRoot
+ * @abstract
+ * This @link kOSBundleRequiredKey OSBundleRequired@/link
+ * value indicates that the kext may be needed to mount the root filesystem
+ * when starting over a network connection.
+ */
+#define kOSBundleRequiredNetworkRoot "Network-Root"
+
+/*!
+ * @define kOSBundleRequiredSafeBoot
+ * @abstract
+ * This @link kOSBundleRequiredKey OSBundleRequired@/link
+ * value indicates that the kext can be loaded during a safe startup.
+ * This value does not normally cause the kext to be read by the booter
+ * or included in startup kext caches.
+ */
+#define kOSBundleRequiredSafeBoot "Safe Boot"
+
+/*!
+ * @define kOSBundleRequiredConsole
+ * @abstract
+ * This @link kOSBundleRequiredKey OSBundleRequired@/link
+ * value indicates that the kext may be needed for console access
+ * (specifically in a single-user startup when
+ * @link //apple_ref/doc/man/8/kextd kextd(8)@/link.
+ * does not run)
+ * and should be loaded during early startup.
+ */
+#define kOSBundleRequiredConsole "Console"
+
+/*!
+ * @define kOSBundleRequiredDriverKit
+ * @abstract
+ * This @link kOSBundleRequiredKey OSBundleRequired@/link
+ * value indicates that the driver extension's (DriverKit driver's)
+ * personalities must be present in the kernel at early boot (specifically
+ * before @link //apple_ref/doc/man/8/kextd kextd(8)@/link starts)
+ * in order to compete with kexts built into the prelinkedkernel. Note that
+ * kextd is still required to launch the user space driver binary. The IOKit
+ * matching will happen during early boot, and the actual driver launch
+ * will happen after kextd starts.
+ */
+#define kOSBundleRequiredDriverKit "DriverKit"
+
+#if PRAGMA_MARK
+#pragma mark -
+/********************************************************************/
+#pragma mark Kext Information
+/********************************************************************/
+#endif
+/*!
+ * @group Kext Information
+ * Types, constants, and macros providing a kext with information
+ * about itself.
+ */
+
+/*!
+ * @typedef OSKextLoadTag
+ *
+ * @abstract
+ * A unique identifier assigned to a loaded instanace of a kext.
+ *
+ * @discussion
+ * If a kext is unloaded and later reloaded, the new instance
+ * has a different load tag.
+ *
+ * A kext can get its own load tag in the kmod_info_t
+ * structure passed into its module start routine, as the
+ * id field (cast to this type).
+ */
+typedef uint32_t OSKextLoadTag;
+
+/*!
+ * @define kOSKextInvalidLoadTag
+ *
+ * @abstract
+ * A load tag value that will never be used for a loaded kext;
+ * indicates kext not found.
+ */
+#define kOSKextInvalidLoadTag ((OSKextLoadTag)(-1))
+
+
+__END_DECLS
+
+#endif /* _LIBKERN_OSKEXTLIB_H */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/libproc.h b/lib/libc/include/any-macos.11-any/libproc.h
new file mode 100644
index 0000000000..de2c766c28
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/libproc.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2006, 2007, 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#ifndef _LIBPROC_H_
+#define _LIBPROC_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include /* for audit_token_t */
+
+#include
+
+#include
+#include
+
+/*
+ * This header file contains private interfaces to obtain process information.
+ * These interfaces are subject to change in future releases.
+ */
+
+/*!
+ * @define PROC_LISTPIDSPATH_PATH_IS_VOLUME
+ * @discussion This flag indicates that all processes that hold open
+ * file references on the volume associated with the specified
+ * path should be returned.
+ */
+#define PROC_LISTPIDSPATH_PATH_IS_VOLUME 1
+
+
+/*!
+ * @define PROC_LISTPIDSPATH_EXCLUDE_EVTONLY
+ * @discussion This flag indicates that file references that were opened
+ * with the O_EVTONLY flag should be excluded from the matching
+ * criteria.
+ */
+#define PROC_LISTPIDSPATH_EXCLUDE_EVTONLY 2
+
+__BEGIN_DECLS
+
+
+/*!
+ * @function proc_listpidspath
+ * @discussion A function which will search through the current
+ * processes looking for open file references which match
+ * a specified path or volume.
+ * @param type types of processes to be searched (see proc_listpids)
+ * @param typeinfo adjunct information for type
+ * @param path file or volume path
+ * @param pathflags flags to control which files should be considered
+ * during the process search.
+ * @param buffer a C array of int-sized values to be filled with
+ * process identifiers that hold an open file reference
+ * matching the specified path or volume. Pass NULL to
+ * obtain the minimum buffer size needed to hold the
+ * currently active processes.
+ * @param buffersize the size (in bytes) of the provided buffer.
+ * @result the number of bytes of data returned in the provided buffer;
+ * -1 if an error was encountered;
+ */
+int proc_listpidspath(uint32_t type,
+ uint32_t typeinfo,
+ const char *path,
+ uint32_t pathflags,
+ void *buffer,
+ int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+
+int proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+int proc_listallpids(void * buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_1);
+int proc_listpgrppids(pid_t pgrpid, void * buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_1);
+int proc_listchildpids(pid_t ppid, void * buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_1);
+int proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+int proc_pidfdinfo(int pid, int fd, int flavor, void * buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+int proc_pidfileportinfo(int pid, uint32_t fileport, int flavor, void *buffer, int buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
+int proc_name(int pid, void * buffer, uint32_t buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+int proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+int proc_kmsgbuf(void * buffer, uint32_t buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+int proc_pidpath(int pid, void * buffer, uint32_t buffersize) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+int proc_pidpath_audittoken(audit_token_t *audittoken, void * buffer, uint32_t buffersize) API_AVAILABLE(macos(11.0), ios(14.0), watchos(7.0), tvos(14.0));
+int proc_libversion(int *major, int * minor) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+
+/*
+ * Return resource usage information for the given pid, which can be a live process or a zombie.
+ *
+ * Returns 0 on success; or -1 on failure, with errno set to indicate the specific error.
+ */
+int proc_pid_rusage(int pid, int flavor, rusage_info_t *buffer) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
+
+/*
+ * A process can use the following api to set its own process control
+ * state on resoure starvation. The argument can have one of the PROC_SETPC_XX values
+ */
+#define PROC_SETPC_NONE 0
+#define PROC_SETPC_THROTTLEMEM 1
+#define PROC_SETPC_SUSPEND 2
+#define PROC_SETPC_TERMINATE 3
+
+int proc_setpcontrol(const int control) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);
+int proc_setpcontrol(const int control);
+
+int proc_track_dirty(pid_t pid, uint32_t flags);
+int proc_set_dirty(pid_t pid, bool dirty);
+int proc_get_dirty(pid_t pid, uint32_t *flags);
+int proc_clear_dirty(pid_t pid, uint32_t flags);
+
+int proc_terminate(pid_t pid, int *sig);
+
+/*
+ * NO_SMT means that on an SMT CPU, this thread must be scheduled alone,
+ * with the paired CPU idle.
+ *
+ * Set NO_SMT on the current proc (all existing and future threads)
+ * This attribute is inherited on fork and exec
+ */
+int proc_set_no_smt(void) __API_AVAILABLE(macos(11.0));
+
+/* Set NO_SMT on the current thread */
+int proc_setthread_no_smt(void) __API_AVAILABLE(macos(11.0));
+
+/*
+ * CPU Security Mitigation APIs
+ *
+ * Set CPU security mitigation on the current proc (all existing and future threads)
+ * This attribute is inherited on fork and exec
+ */
+int proc_set_csm(uint32_t flags) __API_AVAILABLE(macos(11.0));
+
+/* Set CPU security mitigation on the current thread */
+int proc_setthread_csm(uint32_t flags) __API_AVAILABLE(macos(11.0));
+
+/*
+ * flags for CPU Security Mitigation APIs
+ * PROC_CSM_ALL should be used in most cases,
+ * the individual flags are provided only for performance evaluation etc
+ */
+#define PROC_CSM_ALL 0x0001 /* Set all available mitigations */
+#define PROC_CSM_NOSMT 0x0002 /* Set NO_SMT - see above */
+#define PROC_CSM_TECS 0x0004 /* Execute VERW on every return to user mode */
+
+#ifdef PRIVATE
+#include
+/*
+ * Enumerate potential userspace pointers embedded in kernel data structures.
+ * Currently inspects kqueues only.
+ *
+ * NOTE: returned "pointers" are opaque user-supplied values and thus not
+ * guaranteed to address valid objects or be pointers at all.
+ *
+ * Returns the number of pointers found (which may exceed buffersize), or -1 on
+ * failure and errno set appropriately.
+ */
+int proc_list_uptrs(pid_t pid, uint64_t *buffer, uint32_t buffersize);
+
+int proc_list_dynkqueueids(int pid, kqueue_id_t *buf, uint32_t bufsz);
+int proc_piddynkqueueinfo(int pid, int flavor, kqueue_id_t kq_id, void *buffer,
+ int buffersize);
+#endif /* PRIVATE */
+
+int proc_udata_info(int pid, int flavor, void *buffer, int buffersize);
+
+__END_DECLS
+
+#endif /*_LIBPROC_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/mach-o/loader.h b/lib/libc/include/any-macos.11-any/mach-o/loader.h
index a65dad7aa1..d1520d52cb 100644
--- a/lib/libc/include/any-macos.11-any/mach-o/loader.h
+++ b/lib/libc/include/any-macos.11-any/mach-o/loader.h
@@ -1274,8 +1274,6 @@ struct build_tool_version {
#define PLATFORM_WATCHOSSIMULATOR 9
#define PLATFORM_DRIVERKIT 10
-
-
/* Known values for the tool field above. */
#define TOOL_CLANG 1
#define TOOL_SWIFT 2
@@ -1458,8 +1456,6 @@ struct dyld_info_command {
#define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04
#define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08
#define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10
-#define EXPORT_SYMBOL_FLAGS_STATIC_RESOLVER 0x20
-
/*
* The linker_option_command contains linker options embedded in object files.
diff --git a/lib/libc/include/any-macos.11-any/mach/clock.h b/lib/libc/include/any-macos.11-any/mach/clock.h
new file mode 100644
index 0000000000..ec293fc9c1
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/mach/clock.h
@@ -0,0 +1,245 @@
+#ifndef _clock_user_
+#define _clock_user_
+
+/* Module clock */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* BEGIN MIG_STRNCPY_ZEROFILL CODE */
+
+#if defined(__has_include)
+#if __has_include()
+#ifndef USING_MIG_STRNCPY_ZEROFILL
+#define USING_MIG_STRNCPY_ZEROFILL
+#endif
+#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
+#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import));
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */
+#endif /* __has_include() */
+#endif /* __has_include */
+
+/* END MIG_STRNCPY_ZEROFILL CODE */
+
+
+#ifdef AUTOTEST
+#ifndef FUNCTION_PTR_T
+#define FUNCTION_PTR_T
+typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);
+typedef struct {
+ char *name;
+ function_ptr_t function;
+} function_table_entry;
+typedef function_table_entry *function_table_t;
+#endif /* FUNCTION_PTR_T */
+#endif /* AUTOTEST */
+
+#ifndef clock_MSG_COUNT
+#define clock_MSG_COUNT 3
+#endif /* clock_MSG_COUNT */
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef __BeforeMigUserHeader
+__BeforeMigUserHeader
+#endif /* __BeforeMigUserHeader */
+
+#include
+__BEGIN_DECLS
+
+
+/* Routine clock_get_time */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif /* mig_external */
+kern_return_t clock_get_time
+(
+ clock_serv_t clock_serv,
+ mach_timespec_t *cur_time
+);
+
+/* Routine clock_get_attributes */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif /* mig_external */
+kern_return_t clock_get_attributes
+(
+ clock_serv_t clock_serv,
+ clock_flavor_t flavor,
+ clock_attr_t clock_attr,
+ mach_msg_type_number_t *clock_attrCnt
+);
+
+/* Routine clock_alarm */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif /* mig_external */
+kern_return_t clock_alarm
+(
+ clock_serv_t clock_serv,
+ alarm_type_t alarm_type,
+ mach_timespec_t alarm_time,
+ clock_reply_t alarm_port
+);
+
+__END_DECLS
+
+/********************** Caution **************************/
+/* The following data types should be used to calculate */
+/* maximum message sizes only. The actual message may be */
+/* smaller, and the position of the arguments within the */
+/* message layout may vary from what is presented here. */
+/* For example, if any of the arguments are variable- */
+/* sized, and less than the maximum is sent, the data */
+/* will be packed tight in the actual message to reduce */
+/* the presence of holes. */
+/********************** Caution **************************/
+
+/* typedefs for all requests */
+
+#ifndef __Request__clock_subsystem__defined
+#define __Request__clock_subsystem__defined
+
+#ifdef __MigPackStructs
+#pragma pack(push, 4)
+#endif
+ typedef struct {
+ mach_msg_header_t Head;
+ } __Request__clock_get_time_t __attribute__((unused));
+#ifdef __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef __MigPackStructs
+#pragma pack(push, 4)
+#endif
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ clock_flavor_t flavor;
+ mach_msg_type_number_t clock_attrCnt;
+ } __Request__clock_get_attributes_t __attribute__((unused));
+#ifdef __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef __MigPackStructs
+#pragma pack(push, 4)
+#endif
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t alarm_port;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ alarm_type_t alarm_type;
+ mach_timespec_t alarm_time;
+ } __Request__clock_alarm_t __attribute__((unused));
+#ifdef __MigPackStructs
+#pragma pack(pop)
+#endif
+#endif /* !__Request__clock_subsystem__defined */
+
+/* union of all requests */
+
+#ifndef __RequestUnion__clock_subsystem__defined
+#define __RequestUnion__clock_subsystem__defined
+union __RequestUnion__clock_subsystem {
+ __Request__clock_get_time_t Request_clock_get_time;
+ __Request__clock_get_attributes_t Request_clock_get_attributes;
+ __Request__clock_alarm_t Request_clock_alarm;
+};
+#endif /* !__RequestUnion__clock_subsystem__defined */
+/* typedefs for all replies */
+
+#ifndef __Reply__clock_subsystem__defined
+#define __Reply__clock_subsystem__defined
+
+#ifdef __MigPackStructs
+#pragma pack(push, 4)
+#endif
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_timespec_t cur_time;
+ } __Reply__clock_get_time_t __attribute__((unused));
+#ifdef __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef __MigPackStructs
+#pragma pack(push, 4)
+#endif
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_msg_type_number_t clock_attrCnt;
+ int clock_attr[1];
+ } __Reply__clock_get_attributes_t __attribute__((unused));
+#ifdef __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef __MigPackStructs
+#pragma pack(push, 4)
+#endif
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ } __Reply__clock_alarm_t __attribute__((unused));
+#ifdef __MigPackStructs
+#pragma pack(pop)
+#endif
+#endif /* !__Reply__clock_subsystem__defined */
+
+/* union of all replies */
+
+#ifndef __ReplyUnion__clock_subsystem__defined
+#define __ReplyUnion__clock_subsystem__defined
+union __ReplyUnion__clock_subsystem {
+ __Reply__clock_get_time_t Reply_clock_get_time;
+ __Reply__clock_get_attributes_t Reply_clock_get_attributes;
+ __Reply__clock_alarm_t Reply_clock_alarm;
+};
+#endif /* !__RequestUnion__clock_subsystem__defined */
+
+#ifndef subsystem_to_name_map_clock
+#define subsystem_to_name_map_clock \
+ { "clock_get_time", 1000 },\
+ { "clock_get_attributes", 1001 },\
+ { "clock_alarm", 1002 }
+#endif
+
+#ifdef __AfterMigUserHeader
+__AfterMigUserHeader
+#endif /* __AfterMigUserHeader */
+
+#endif /* _clock_user_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/mach/clock_priv.h b/lib/libc/include/any-macos.11-any/mach/clock_priv.h
new file mode 100644
index 0000000000..0c9d11d9c6
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/mach/clock_priv.h
@@ -0,0 +1,199 @@
+#ifndef _clock_priv_user_
+#define _clock_priv_user_
+
+/* Module clock_priv */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* BEGIN MIG_STRNCPY_ZEROFILL CODE */
+
+#if defined(__has_include)
+#if __has_include()
+#ifndef USING_MIG_STRNCPY_ZEROFILL
+#define USING_MIG_STRNCPY_ZEROFILL
+#endif
+#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
+#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import));
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */
+#endif /* __has_include() */
+#endif /* __has_include */
+
+/* END MIG_STRNCPY_ZEROFILL CODE */
+
+
+#ifdef AUTOTEST
+#ifndef FUNCTION_PTR_T
+#define FUNCTION_PTR_T
+typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);
+typedef struct {
+ char *name;
+ function_ptr_t function;
+} function_table_entry;
+typedef function_table_entry *function_table_t;
+#endif /* FUNCTION_PTR_T */
+#endif /* AUTOTEST */
+
+#ifndef clock_priv_MSG_COUNT
+#define clock_priv_MSG_COUNT 2
+#endif /* clock_priv_MSG_COUNT */
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef __BeforeMigUserHeader
+__BeforeMigUserHeader
+#endif /* __BeforeMigUserHeader */
+
+#include
+__BEGIN_DECLS
+
+
+/* Routine clock_set_time */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif /* mig_external */
+kern_return_t clock_set_time
+(
+ clock_ctrl_t clock_ctrl,
+ mach_timespec_t new_time
+);
+
+/* Routine clock_set_attributes */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif /* mig_external */
+kern_return_t clock_set_attributes
+(
+ clock_ctrl_t clock_ctrl,
+ clock_flavor_t flavor,
+ clock_attr_t clock_attr,
+ mach_msg_type_number_t clock_attrCnt
+);
+
+__END_DECLS
+
+/********************** Caution **************************/
+/* The following data types should be used to calculate */
+/* maximum message sizes only. The actual message may be */
+/* smaller, and the position of the arguments within the */
+/* message layout may vary from what is presented here. */
+/* For example, if any of the arguments are variable- */
+/* sized, and less than the maximum is sent, the data */
+/* will be packed tight in the actual message to reduce */
+/* the presence of holes. */
+/********************** Caution **************************/
+
+/* typedefs for all requests */
+
+#ifndef __Request__clock_priv_subsystem__defined
+#define __Request__clock_priv_subsystem__defined
+
+#ifdef __MigPackStructs
+#pragma pack(push, 4)
+#endif
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_timespec_t new_time;
+ } __Request__clock_set_time_t __attribute__((unused));
+#ifdef __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef __MigPackStructs
+#pragma pack(push, 4)
+#endif
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ clock_flavor_t flavor;
+ mach_msg_type_number_t clock_attrCnt;
+ int clock_attr[1];
+ } __Request__clock_set_attributes_t __attribute__((unused));
+#ifdef __MigPackStructs
+#pragma pack(pop)
+#endif
+#endif /* !__Request__clock_priv_subsystem__defined */
+
+/* union of all requests */
+
+#ifndef __RequestUnion__clock_priv_subsystem__defined
+#define __RequestUnion__clock_priv_subsystem__defined
+union __RequestUnion__clock_priv_subsystem {
+ __Request__clock_set_time_t Request_clock_set_time;
+ __Request__clock_set_attributes_t Request_clock_set_attributes;
+};
+#endif /* !__RequestUnion__clock_priv_subsystem__defined */
+/* typedefs for all replies */
+
+#ifndef __Reply__clock_priv_subsystem__defined
+#define __Reply__clock_priv_subsystem__defined
+
+#ifdef __MigPackStructs
+#pragma pack(push, 4)
+#endif
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ } __Reply__clock_set_time_t __attribute__((unused));
+#ifdef __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef __MigPackStructs
+#pragma pack(push, 4)
+#endif
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ } __Reply__clock_set_attributes_t __attribute__((unused));
+#ifdef __MigPackStructs
+#pragma pack(pop)
+#endif
+#endif /* !__Reply__clock_priv_subsystem__defined */
+
+/* union of all replies */
+
+#ifndef __ReplyUnion__clock_priv_subsystem__defined
+#define __ReplyUnion__clock_priv_subsystem__defined
+union __ReplyUnion__clock_priv_subsystem {
+ __Reply__clock_set_time_t Reply_clock_set_time;
+ __Reply__clock_set_attributes_t Reply_clock_set_attributes;
+};
+#endif /* !__RequestUnion__clock_priv_subsystem__defined */
+
+#ifndef subsystem_to_name_map_clock_priv
+#define subsystem_to_name_map_clock_priv \
+ { "clock_set_time", 1200 },\
+ { "clock_set_attributes", 1201 }
+#endif
+
+#ifdef __AfterMigUserHeader
+__AfterMigUserHeader
+#endif /* __AfterMigUserHeader */
+
+#endif /* _clock_priv_user_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/mach/exception_types.h b/lib/libc/include/any-macos.11-any/mach/exception_types.h
new file mode 100644
index 0000000000..12a12615f2
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/mach/exception_types.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * @OSF_COPYRIGHT@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ */
+
+#ifndef _MACH_EXCEPTION_TYPES_H_
+#define _MACH_EXCEPTION_TYPES_H_
+
+#include
+
+/*
+ * Machine-independent exception definitions.
+ */
+
+#define EXC_BAD_ACCESS 1 /* Could not access memory */
+/* Code contains kern_return_t describing error. */
+/* Subcode contains bad memory address. */
+
+#define EXC_BAD_INSTRUCTION 2 /* Instruction failed */
+/* Illegal or undefined instruction or operand */
+
+#define EXC_ARITHMETIC 3 /* Arithmetic exception */
+/* Exact nature of exception is in code field */
+
+#define EXC_EMULATION 4 /* Emulation instruction */
+/* Emulation support instruction encountered */
+/* Details in code and subcode fields */
+
+#define EXC_SOFTWARE 5 /* Software generated exception */
+/* Exact exception is in code field. */
+/* Codes 0 - 0xFFFF reserved to hardware */
+/* Codes 0x10000 - 0x1FFFF reserved for OS emulation (Unix) */
+
+#define EXC_BREAKPOINT 6 /* Trace, breakpoint, etc. */
+/* Details in code field. */
+
+#define EXC_SYSCALL 7 /* System calls. */
+
+#define EXC_MACH_SYSCALL 8 /* Mach system calls. */
+
+#define EXC_RPC_ALERT 9 /* RPC alert */
+
+#define EXC_CRASH 10 /* Abnormal process exit */
+
+#define EXC_RESOURCE 11 /* Hit resource consumption limit */
+/* Exact resource is in code field. */
+
+#define EXC_GUARD 12 /* Violated guarded resource protections */
+
+#define EXC_CORPSE_NOTIFY 13 /* Abnormal process exited to corpse state */
+
+#define EXC_CORPSE_VARIANT_BIT 0x100 /* bit set for EXC_*_CORPSE variants of EXC_* */
+
+
+/*
+ * Machine-independent exception behaviors
+ */
+
+# define EXCEPTION_DEFAULT 1
+/* Send a catch_exception_raise message including the identity.
+ */
+
+# define EXCEPTION_STATE 2
+/* Send a catch_exception_raise_state message including the
+ * thread state.
+ */
+
+# define EXCEPTION_STATE_IDENTITY 3
+/* Send a catch_exception_raise_state_identity message including
+ * the thread identity and state.
+ */
+
+#define MACH_EXCEPTION_ERRORS 0x40000000
+/* include additional exception specific errors, not used yet. */
+
+#define MACH_EXCEPTION_CODES 0x80000000
+/* Send 64-bit code and subcode in the exception header */
+
+#define MACH_EXCEPTION_MASK (MACH_EXCEPTION_CODES | MACH_EXCEPTION_ERRORS)
+/*
+ * Masks for exception definitions, above
+ * bit zero is unused, therefore 1 word = 31 exception types
+ */
+
+#define EXC_MASK_BAD_ACCESS (1 << EXC_BAD_ACCESS)
+#define EXC_MASK_BAD_INSTRUCTION (1 << EXC_BAD_INSTRUCTION)
+#define EXC_MASK_ARITHMETIC (1 << EXC_ARITHMETIC)
+#define EXC_MASK_EMULATION (1 << EXC_EMULATION)
+#define EXC_MASK_SOFTWARE (1 << EXC_SOFTWARE)
+#define EXC_MASK_BREAKPOINT (1 << EXC_BREAKPOINT)
+#define EXC_MASK_SYSCALL (1 << EXC_SYSCALL)
+#define EXC_MASK_MACH_SYSCALL (1 << EXC_MACH_SYSCALL)
+#define EXC_MASK_RPC_ALERT (1 << EXC_RPC_ALERT)
+#define EXC_MASK_CRASH (1 << EXC_CRASH)
+#define EXC_MASK_RESOURCE (1 << EXC_RESOURCE)
+#define EXC_MASK_GUARD (1 << EXC_GUARD)
+#define EXC_MASK_CORPSE_NOTIFY (1 << EXC_CORPSE_NOTIFY)
+
+#define EXC_MASK_ALL (EXC_MASK_BAD_ACCESS | \
+ EXC_MASK_BAD_INSTRUCTION | \
+ EXC_MASK_ARITHMETIC | \
+ EXC_MASK_EMULATION | \
+ EXC_MASK_SOFTWARE | \
+ EXC_MASK_BREAKPOINT | \
+ EXC_MASK_SYSCALL | \
+ EXC_MASK_MACH_SYSCALL | \
+ EXC_MASK_RPC_ALERT | \
+ EXC_MASK_RESOURCE | \
+ EXC_MASK_GUARD | \
+ EXC_MASK_MACHINE)
+
+
+#define FIRST_EXCEPTION 1 /* ZERO is illegal */
+
+/*
+ * Machine independent codes for EXC_SOFTWARE
+ * Codes 0x10000 - 0x1FFFF reserved for OS emulation (Unix)
+ * 0x10000 - 0x10002 in use for unix signals
+ * 0x20000 - 0x2FFFF reserved for MACF
+ */
+#define EXC_SOFT_SIGNAL 0x10003 /* Unix signal exceptions */
+
+#define EXC_MACF_MIN 0x20000 /* MACF exceptions */
+#define EXC_MACF_MAX 0x2FFFF
+
+#ifndef ASSEMBLER
+
+#include
+#include
+#include
+#include
+/*
+ * Exported types
+ */
+
+typedef int exception_type_t;
+typedef integer_t exception_data_type_t;
+typedef int64_t mach_exception_data_type_t;
+typedef int exception_behavior_t;
+typedef exception_data_type_t *exception_data_t;
+typedef mach_exception_data_type_t *mach_exception_data_t;
+typedef unsigned int exception_mask_t;
+typedef exception_mask_t *exception_mask_array_t;
+typedef exception_behavior_t *exception_behavior_array_t;
+typedef thread_state_flavor_t *exception_flavor_array_t;
+typedef mach_port_t *exception_port_array_t;
+typedef ipc_info_port_t *exception_port_info_array_t;
+typedef mach_exception_data_type_t mach_exception_code_t;
+typedef mach_exception_data_type_t mach_exception_subcode_t;
+
+#endif /* ASSEMBLER */
+
+#endif /* _MACH_EXCEPTION_TYPES_H_ */
\ No newline at end of file
diff --git a/lib/libc/include/any-macos.11-any/mach/host_priv.h b/lib/libc/include/any-macos.11-any/mach/host_priv.h
new file mode 100644
index 0000000000..9445ae5d93
--- /dev/null
+++ b/lib/libc/include/any-macos.11-any/mach/host_priv.h
@@ -0,0 +1,1163 @@
+#ifndef _host_priv_user_
+#define _host_priv_user_
+
+/* Module host_priv */
+
+#include
+#include
+#include
+#include
+#include