authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-15 21:44:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-15 21:44:38-07:00
log597082adf45cebbf2c6a81c3f732b6d2ce4a1435
tree9309977e204cceaac2c18efbea2153a69f86d1f4
parent07606d12daabe8c201dba3d5b27e702ce58d0ffb
parentd98e39fa6864f287bc50f265f98b7195849afa68

Merge remote-tracking branch 'origin/master' into stage2-whole-file-astgen

Conflicts: * build.zig * src/Compilation.zig * src/codegen/spirv/spec.zig * src/link/SpirV.zig * test/stage2/darwin.zig - this one might be problematic; start.zig looks for `main` in the root source file, not `_main`. Not sure why there is an underscore there in master branch.

48 files changed, 3668 insertions(+), 907 deletions(-)

build.zig+70-22
......@@ -228,6 +228,7 @@ pub fn build(b: *Builder) !void {
228228 const is_wine_enabled = b.option(bool, "enable-wine", "Use Wine to run cross compiled Windows tests") orelse false;
229229 const is_qemu_enabled = b.option(bool, "enable-qemu", "Use QEMU to run cross compiled foreign architecture tests") orelse false;
230230 const is_wasmtime_enabled = b.option(bool, "enable-wasmtime", "Use Wasmtime to enable and run WASI libstd tests") orelse false;
231 const is_darling_enabled = b.option(bool, "enable-darling", "[Experimental] Use Darling to run cross compiled macOS tests") orelse false;
231232 const glibc_multi_dir = b.option([]const u8, "enable-foreign-glibc", "Provide directory with glibc installations to run cross compiled tests that link glibc");
232233
233234 test_stage2.addBuildOption(bool, "skip_non_native", skip_non_native);
......@@ -238,6 +239,7 @@ pub fn build(b: *Builder) !void {
238239 test_stage2.addBuildOption(bool, "enable_wine", is_wine_enabled);
239240 test_stage2.addBuildOption(bool, "enable_wasmtime", is_wasmtime_enabled);
240241 test_stage2.addBuildOption(u32, "mem_leak_frames", mem_leak_frames * 2);
242 test_stage2.addBuildOption(bool, "enable_darling", is_darling_enabled);
241243 test_stage2.addBuildOption(?[]const u8, "glibc_multi_install_dir", glibc_multi_dir);
242244 test_stage2.addBuildOption([]const u8, "version", version);
243245
......@@ -272,11 +274,56 @@ pub fn build(b: *Builder) !void {
272274 const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works");
273275 fmt_step.dependOn(&fmt_build_zig.step);
274276
275 // TODO for the moment, skip wasm32-wasi until bugs are sorted out.
276 toolchain_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
277
278 toolchain_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
279 toolchain_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/special/c.zig", "minilibc", "Run the mini libc tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
277 toolchain_step.dependOn(tests.addPkgTests(
278 b,
279 test_filter,
280 "test/behavior.zig",
281 "behavior",
282 "Run the behavior tests",
283 modes,
284 false,
285 skip_non_native,
286 skip_libc,
287 is_wine_enabled,
288 is_qemu_enabled,
289 is_wasmtime_enabled,
290 is_darling_enabled,
291 glibc_multi_dir,
292 ));
293
294 toolchain_step.dependOn(tests.addPkgTests(
295 b,
296 test_filter,
297 "lib/std/special/compiler_rt.zig",
298 "compiler-rt",
299 "Run the compiler_rt tests",
300 modes,
301 true,
302 skip_non_native,
303 true,
304 is_wine_enabled,
305 is_qemu_enabled,
306 is_wasmtime_enabled,
307 is_darling_enabled,
308 glibc_multi_dir,
309 ));
310
311 toolchain_step.dependOn(tests.addPkgTests(
312 b,
313 test_filter,
314 "lib/std/special/c.zig",
315 "minilibc",
316 "Run the mini libc tests",
317 modes,
318 true,
319 skip_non_native,
320 true,
321 is_wine_enabled,
322 is_qemu_enabled,
323 is_wasmtime_enabled,
324 is_darling_enabled,
325 glibc_multi_dir,
326 ));
280327
281328 toolchain_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
282329 toolchain_step.dependOn(tests.addStandaloneTests(b, test_filter, modes));
......@@ -294,7 +341,22 @@ pub fn build(b: *Builder) !void {
294341 toolchain_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes));
295342 }
296343
297 const std_step = tests.addPkgTests(b, test_filter, "lib/std/std.zig", "std", "Run the standard library tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir);
344 const std_step = tests.addPkgTests(
345 b,
346 test_filter,
347 "lib/std/std.zig",
348 "std",
349 "Run the standard library tests",
350 modes,
351 false,
352 skip_non_native,
353 skip_libc,
354 is_wine_enabled,
355 is_qemu_enabled,
356 is_wasmtime_enabled,
357 is_darling_enabled,
358 glibc_multi_dir,
359 );
298360
299361 const test_step = b.step("test", "Run all the tests");
300362 test_step.dependOn(toolchain_step);
......@@ -346,8 +408,7 @@ fn addCmakeCfgOptionsToExe(
346408 },
347409 else => |e| return e,
348410 };
349
350 exe.linkSystemLibrary("pthread");
411 exe.linkSystemLibrary("unwind");
351412 } else if (exe.target.isFreeBSD()) {
352413 try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
353414 exe.linkSystemLibrary("pthread");
......@@ -355,20 +416,7 @@ fn addCmakeCfgOptionsToExe(
355416 try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
356417 try addCxxKnownPath(b, cfg, exe, "libc++abi.a", null, need_cpp_includes);
357418 } else if (exe.target.isDarwin()) {
358 if (addCxxKnownPath(b, cfg, exe, "libgcc_eh.a", "", need_cpp_includes)) {
359 // Compiler is GCC.
360 try addCxxKnownPath(b, cfg, exe, "libstdc++.a", null, need_cpp_includes);
361 exe.linkSystemLibrary("pthread");
362 // TODO LLD cannot perform this link.
363 // Set ZIG_SYSTEM_LINKER_HACK env var to use system linker ld instead.
364 // See https://github.com/ziglang/zig/issues/1535
365 } else |err| switch (err) {
366 error.RequiredLibraryNotFound => {
367 // System compiler, not gcc.
368 exe.linkSystemLibrary("c++");
369 },
370 else => |e| return e,
371 }
419 exe.linkSystemLibrary("c++");
372420 }
373421
374422 if (cfg.dia_guids_lib.len != 0) {
lib/libc/glibc/sysdeps/sparc/nptl/bits/pthreadtypes-arch.h deleted-81
......@@ -1,81 +0,0 @@
1/* Machine-specific pthread type layouts. SPARC version.
2 Copyright (C) 2003-2019 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19#ifndef _BITS_PTHREADTYPES_ARCH_H
20#define _BITS_PTHREADTYPES_ARCH_H 1
21
22#include <bits/wordsize.h>
23
24#if __WORDSIZE == 64
25# define __SIZEOF_PTHREAD_ATTR_T 56
26# define __SIZEOF_PTHREAD_MUTEX_T 40
27# define __SIZEOF_PTHREAD_CONDATTR_T 4
28# define __SIZEOF_PTHREAD_RWLOCK_T 56
29# define __SIZEOF_PTHREAD_BARRIER_T 32
30#else
31# define __SIZEOF_PTHREAD_ATTR_T 36
32# define __SIZEOF_PTHREAD_MUTEX_T 24
33# define __SIZEOF_PTHREAD_CONDATTR_T 4
34# define __SIZEOF_PTHREAD_RWLOCK_T 32
35# define __SIZEOF_PTHREAD_BARRIER_T 20
36#endif
37#define __SIZEOF_PTHREAD_MUTEXATTR_T 4
38#define __SIZEOF_PTHREAD_COND_T 48
39#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
40#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
41
42/* Definitions for internal mutex struct. */
43#define __PTHREAD_COMPAT_PADDING_MID
44#define __PTHREAD_COMPAT_PADDING_END
45#define __PTHREAD_MUTEX_LOCK_ELISION 0
46#define __PTHREAD_MUTEX_NUSERS_AFTER_KIND (__WORDSIZE != 64)
47#define __PTHREAD_MUTEX_USE_UNION (__WORDSIZE != 64)
48
49#define __LOCK_ALIGNMENT
50#define __ONCE_ALIGNMENT
51
52struct __pthread_rwlock_arch_t
53{
54 unsigned int __readers;
55 unsigned int __writers;
56 unsigned int __wrphase_futex;
57 unsigned int __writers_futex;
58 unsigned int __pad3;
59 unsigned int __pad4;
60#if __WORDSIZE == 64
61 int __cur_writer;
62 int __shared;
63 unsigned long int __pad1;
64 unsigned long int __pad2;
65 /* FLAGS must stay at this position in the structure to maintain
66 binary compatibility. */
67 unsigned int __flags;
68#else
69 unsigned char __pad1;
70 unsigned char __pad2;
71 unsigned char __shared;
72 /* FLAGS must stay at this position in the structure to maintain
73 binary compatibility. */
74 unsigned char __flags;
75 int __cur_writer;
76#endif
77};
78
79#define __PTHREAD_RWLOCK_ELISION_EXTRA 0
80
81#endif /* bits/pthreadtypes.h */
lib/std/build.zig+8
......@@ -1398,6 +1398,9 @@ pub const LibExeObjStep = struct {
13981398 /// Uses system Wasmtime installation to run cross compiled wasm/wasi build artifacts.
13991399 enable_wasmtime: bool = false,
14001400
1401 /// Experimental. Uses system Darling installation to run cross compiled macOS build artifacts.
1402 enable_darling: bool = false,
1403
14011404 /// After following the steps in https://github.com/ziglang/zig/wiki/Updating-libc#glibc,
14021405 /// this will be the directory $glibc-build-dir/install/glibcs
14031406 /// Given the example of the aarch64 target, this is the directory
......@@ -2514,6 +2517,11 @@ pub const LibExeObjStep = struct {
25142517 try zig_args.append("--dir=.");
25152518 try zig_args.append("--test-cmd-bin");
25162519 },
2520 .darling => |bin_name| if (self.enable_darling) {
2521 try zig_args.append("--test-cmd");
2522 try zig_args.append(bin_name);
2523 try zig_args.append("--test-cmd-bin");
2524 },
25172525 }
25182526
25192527 for (self.packages.items) |pkg| {
lib/std/debug.zig+4-2
......@@ -309,6 +309,7 @@ const RED = "\x1b[31;1m";
309309const GREEN = "\x1b[32;1m";
310310const CYAN = "\x1b[36;1m";
311311const WHITE = "\x1b[37;1m";
312const BOLD = "\x1b[1m";
312313const DIM = "\x1b[2m";
313314const RESET = "\x1b[0m";
314315
......@@ -479,8 +480,9 @@ pub const TTY = struct {
479480 .Red => out_stream.writeAll(RED) catch return,
480481 .Green => out_stream.writeAll(GREEN) catch return,
481482 .Cyan => out_stream.writeAll(CYAN) catch return,
482 .White, .Bold => out_stream.writeAll(WHITE) catch return,
483 .White => out_stream.writeAll(WHITE) catch return,
483484 .Dim => out_stream.writeAll(DIM) catch return,
485 .Bold => out_stream.writeAll(BOLD) catch return,
484486 .Reset => out_stream.writeAll(RESET) catch return,
485487 },
486488 .windows_api => if (native_os == .windows) {
......@@ -632,7 +634,7 @@ fn printLineInfo(
632634 comptime printLineFromFile: anytype,
633635) !void {
634636 nosuspend {
635 tty_config.setColor(out_stream, .White);
637 tty_config.setColor(out_stream, .Bold);
636638
637639 if (line_info) |*li| {
638640 try out_stream.print("{s}:{d}:{d}", .{ li.file_name, li.line, li.column });
lib/std/fs.zig+3-1
......@@ -501,7 +501,9 @@ pub const Dir = struct {
501501 },
502502 .linux => struct {
503503 dir: Dir,
504 buf: [8192]u8, // TODO align(@alignOf(os.dirent64)),
504 // The if guard is solely there to prevent compile errors from missing `os.linux.dirent64`
505 // definition when compiling for other OSes. It doesn't do anything when compiling for Linux.
506 buf: [8192]u8 align(if (builtin.os.tag != .linux) 1 else @alignOf(os.linux.dirent64)),
505507 index: usize,
506508 end_index: usize,
507509
lib/std/hash_map.zig+13-12
......@@ -303,29 +303,32 @@ pub fn HashMapUnmanaged(
303303 /// Metadata for a slot. It can be in three states: empty, used or
304304 /// tombstone. Tombstones indicate that an entry was previously used,
305305 /// they are a simple way to handle removal.
306 /// To this state, we add 6 bits from the slot's key hash. These are
306 /// To this state, we add 7 bits from the slot's key hash. These are
307307 /// used as a fast way to disambiguate between entries without
308308 /// having to use the equality function. If two fingerprints are
309309 /// different, we know that we don't have to compare the keys at all.
310 /// The 6 bits are the highest ones from a 64 bit hash. This way, not
310 /// The 7 bits are the highest ones from a 64 bit hash. This way, not
311311 /// only we use the `log2(capacity)` lowest bits from the hash to determine
312 /// a slot index, but we use 6 more bits to quickly resolve collisions
313 /// when multiple elements with different hashes end up wanting to be in / the same slot.
312 /// a slot index, but we use 7 more bits to quickly resolve collisions
313 /// when multiple elements with different hashes end up wanting to be in the same slot.
314314 /// Not using the equality function means we don't have to read into
315 /// the entries array, avoiding a likely cache miss.
315 /// the entries array, likely avoiding a cache miss and a potentially
316 /// costly function call.
316317 const Metadata = packed struct {
317 const FingerPrint = u6;
318 const FingerPrint = u7;
318319
320 const free: FingerPrint = 0;
321 const tombstone: FingerPrint = 1;
322
323 fingerprint: FingerPrint = free,
319324 used: u1 = 0,
320 tombstone: u1 = 0,
321 fingerprint: FingerPrint = 0,
322325
323326 pub fn isUsed(self: Metadata) bool {
324327 return self.used == 1;
325328 }
326329
327330 pub fn isTombstone(self: Metadata) bool {
328 return self.tombstone == 1;
331 return !self.isUsed() and self.fingerprint == tombstone;
329332 }
330333
331334 pub fn takeFingerprint(hash: Hash) FingerPrint {
......@@ -336,14 +339,12 @@ pub fn HashMapUnmanaged(
336339
337340 pub fn fill(self: *Metadata, fp: FingerPrint) void {
338341 self.used = 1;
339 self.tombstone = 0;
340342 self.fingerprint = fp;
341343 }
342344
343345 pub fn remove(self: *Metadata) void {
344346 self.used = 0;
345 self.tombstone = 1;
346 self.fingerprint = 0;
347 self.fingerprint = tombstone;
347348 }
348349 };
349350
lib/std/json.zig+45-10
......@@ -623,7 +623,7 @@ pub const StreamingParser = struct {
623623
624624 .ObjectSeparator => switch (c) {
625625 ':' => {
626 p.state = .ValueBegin;
626 p.state = .ValueBeginNoClosing;
627627 p.after_string_state = .ValueEnd;
628628 },
629629 0x09, 0x0A, 0x0D, 0x20 => {
......@@ -1205,6 +1205,13 @@ test "json.token mismatched close" {
12051205 try testing.expectError(error.UnexpectedClosingBrace, p.next());
12061206}
12071207
1208test "json.token premature object close" {
1209 var p = TokenStream.init("{ \"key\": }");
1210 try checkNext(&p, .ObjectBegin);
1211 try checkNext(&p, .String);
1212 try testing.expectError(error.InvalidValueBegin, p.next());
1213}
1214
12081215/// Validate a JSON string. This does not limit number precision so a decoder may not necessarily
12091216/// be able to decode the string even if this returns true.
12101217pub fn validate(s: []const u8) bool {
......@@ -1566,11 +1573,16 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:
15661573 // .UseLast => {},
15671574 // }
15681575 if (options.duplicate_field_behavior == .UseFirst) {
1576 // unconditonally ignore value. for comptime fields, this skips check against default_value
1577 parseFree(field.field_type, try parse(field.field_type, tokens, options), options);
1578 found = true;
15691579 break;
15701580 } else if (options.duplicate_field_behavior == .Error) {
15711581 return error.DuplicateJSONField;
15721582 } else if (options.duplicate_field_behavior == .UseLast) {
1573 parseFree(field.field_type, @field(r, field.name), options);
1583 if (!field.is_comptime) {
1584 parseFree(field.field_type, @field(r, field.name), options);
1585 }
15741586 fields_seen[i] = false;
15751587 }
15761588 }
......@@ -1724,7 +1736,9 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void {
17241736 },
17251737 .Struct => |structInfo| {
17261738 inline for (structInfo.fields) |field| {
1727 parseFree(field.field_type, @field(value, field.name), options);
1739 if (!field.is_comptime) {
1740 parseFree(field.field_type, @field(value, field.name), options);
1741 }
17281742 }
17291743 },
17301744 .Array => |arrayInfo| {
......@@ -1901,14 +1915,19 @@ test "parse with comptime field" {
19011915 },
19021916 };
19031917
1904 const r = try std.json.parse(T, &std.json.TokenStream.init(
1918 const options = ParseOptions{
1919 .allocator = std.testing.allocator,
1920 };
1921
1922 const r = try parse(T, &TokenStream.init(
19051923 \\{
19061924 \\ "kind": "float",
19071925 \\ "b": 1.0
19081926 \\}
1909 ), .{
1910 .allocator = std.testing.allocator,
1911 });
1927 ), options);
1928
1929 // check that parseFree doesn't try to free comptime fields
1930 parseFree(T, r, options);
19121931 }
19131932}
19141933
......@@ -1995,17 +2014,33 @@ test "parse into struct with duplicate field" {
19952014 const ballast = try testing.allocator.alloc(u64, 1);
19962015 defer testing.allocator.free(ballast);
19972016
1998 const options = ParseOptions{
2017 const options_first = ParseOptions{
2018 .allocator = testing.allocator,
2019 .duplicate_field_behavior = .UseFirst
2020 };
2021
2022 const options_last = ParseOptions{
19992023 .allocator = testing.allocator,
20002024 .duplicate_field_behavior = .UseLast,
20012025 };
2026
20022027 const str = "{ \"a\": 1, \"a\": 0.25 }";
20032028
20042029 const T1 = struct { a: *u64 };
2005 try testing.expectError(error.UnexpectedToken, parse(T1, &TokenStream.init(str), options));
2030 // both .UseFirst and .UseLast should fail because second "a" value isn't a u64
2031 try testing.expectError(error.UnexpectedToken, parse(T1, &TokenStream.init(str), options_first));
2032 try testing.expectError(error.UnexpectedToken, parse(T1, &TokenStream.init(str), options_last));
20062033
20072034 const T2 = struct { a: f64 };
2008 try testing.expectEqual(T2{ .a = 0.25 }, try parse(T2, &TokenStream.init(str), options));
2035 try testing.expectEqual(T2{ .a = 1.0 }, try parse(T2, &TokenStream.init(str), options_first));
2036 try testing.expectEqual(T2{ .a = 0.25 }, try parse(T2, &TokenStream.init(str), options_last));
2037
2038 const T3 = struct { comptime a: f64 = 1.0 };
2039 // .UseFirst should succeed because second "a" value is unconditionally ignored (even though != 1.0)
2040 const t3 = T3{ .a = 1.0 };
2041 try testing.expectEqual(t3, try parse(T3, &TokenStream.init(str), options_first));
2042 // .UseLast should fail because second "a" value is 0.25 which is not equal to default value of 1.0
2043 try testing.expectError(error.UnexpectedValue, parse(T3, &TokenStream.init(str), options_last));
20092044}
20102045
20112046/// A non-stream JSON parser which constructs a tree of Value's.
lib/std/json/test.zig+6
......@@ -76,6 +76,12 @@ test "y_trailing_comma_after_empty" {
7676 );
7777}
7878
79test "n_object_closed_missing_value" {
80 try err(
81 \\{"a":}
82 );
83}
84
7985////////////////////////////////////////////////////////////////////////////////////////////////////
8086
8187test "y_array_arraysWithSpaces" {
lib/std/math/isnormal.zig+9-2
......@@ -14,16 +14,20 @@ pub fn isNormal(x: anytype) bool {
1414 switch (T) {
1515 f16 => {
1616 const bits = @bitCast(u16, x);
17 return (bits + 1024) & 0x7FFF >= 2048;
17 return (bits + (1 << 10)) & (maxInt(u16) >> 1) >= (1 << 11);
1818 },
1919 f32 => {
2020 const bits = @bitCast(u32, x);
21 return (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000;
21 return (bits + (1 << 23)) & (maxInt(u32) >> 1) >= (1 << 24);
2222 },
2323 f64 => {
2424 const bits = @bitCast(u64, x);
2525 return (bits + (1 << 52)) & (maxInt(u64) >> 1) >= (1 << 53);
2626 },
27 f128 => {
28 const bits = @bitCast(u128, x);
29 return (bits + (1 << 112)) & (maxInt(u128) >> 1) >= (1 << 113);
30 },
2731 else => {
2832 @compileError("isNormal not implemented for " ++ @typeName(T));
2933 },
......@@ -34,10 +38,13 @@ test "math.isNormal" {
3438 try expect(!isNormal(math.nan(f16)));
3539 try expect(!isNormal(math.nan(f32)));
3640 try expect(!isNormal(math.nan(f64)));
41 try expect(!isNormal(math.nan(f128)));
3742 try expect(!isNormal(@as(f16, 0)));
3843 try expect(!isNormal(@as(f32, 0)));
3944 try expect(!isNormal(@as(f64, 0)));
45 try expect(!isNormal(@as(f128, 0)));
4046 try expect(isNormal(@as(f16, 1.0)));
4147 try expect(isNormal(@as(f32, 1.0)));
4248 try expect(isNormal(@as(f64, 1.0)));
49 try expect(isNormal(@as(f128, 1.0)));
4350}
lib/std/math/scalbn.zig+66-66
......@@ -9,89 +9,89 @@
99// https://git.musl-libc.org/cgit/musl/tree/src/math/scalbnf.c
1010// https://git.musl-libc.org/cgit/musl/tree/src/math/scalbn.c
1111
12const std = @import("../std.zig");
12const std = @import("std");
1313const math = std.math;
14const assert = std.debug.assert;
1415const expect = std.testing.expect;
1516
1617/// Returns x * 2^n.
1718pub fn scalbn(x: anytype, n: i32) @TypeOf(x) {
18 const T = @TypeOf(x);
19 return switch (T) {
20 f32 => scalbn32(x, n),
21 f64 => scalbn64(x, n),
22 else => @compileError("scalbn not implemented for " ++ @typeName(T)),
23 };
24}
25
26fn scalbn32(x: f32, n_: i32) f32 {
27 var y = x;
28 var n = n_;
19 var base = x;
20 var shift = n;
2921
30 if (n > 127) {
31 y *= 0x1.0p127;
32 n -= 127;
33 if (n > 1023) {
34 y *= 0x1.0p127;
35 n -= 127;
36 if (n > 127) {
37 n = 127;
38 }
39 }
40 } else if (n < -126) {
41 y *= 0x1.0p-126 * 0x1.0p24;
42 n += 126 - 24;
43 if (n < -126) {
44 y *= 0x1.0p-126 * 0x1.0p24;
45 n += 126 - 24;
46 if (n < -126) {
47 n = -126;
48 }
49 }
22 const T = @TypeOf(base);
23 const IntT = std.meta.Int(.unsigned, @bitSizeOf(T));
24 if (@typeInfo(T) != .Float) {
25 @compileError("scalbn not implemented for " ++ @typeName(T));
5026 }
5127
52 const u = @intCast(u32, n +% 0x7F) << 23;
53 return y * @bitCast(f32, u);
54}
28 const mantissa_bits = math.floatMantissaBits(T);
29 const exponent_bits = math.floatExponentBits(T);
30 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
31 const exponent_min = 1 - exponent_bias;
32 const exponent_max = exponent_bias;
5533
56fn scalbn64(x: f64, n_: i32) f64 {
57 var y = x;
58 var n = n_;
34 // fix double rounding errors in subnormal ranges
35 // https://git.musl-libc.org/cgit/musl/commit/src/math/scalbn.c?id=8c44a060243f04283ca68dad199aab90336141db
36 const scale_min_expo = exponent_min + mantissa_bits + 1;
37 const scale_min = @bitCast(T, @as(IntT, scale_min_expo + exponent_bias) << mantissa_bits);
38 const scale_max = @bitCast(T, @intCast(IntT, exponent_max + exponent_bias) << mantissa_bits);
5939
60 if (n > 1023) {
61 y *= 0x1.0p1023;
62 n -= 1023;
63 if (n > 1023) {
64 y *= 0x1.0p1023;
65 n -= 1023;
66 if (n > 1023) {
67 n = 1023;
68 }
40 // scale `shift` within floating point limits, if possible
41 // second pass is possible due to subnormal range
42 // third pass always results in +/-0.0 or +/-inf
43 if (shift > exponent_max) {
44 base *= scale_max;
45 shift -= exponent_max;
46 if (shift > exponent_max) {
47 base *= scale_max;
48 shift -= exponent_max;
49 if (shift > exponent_max) shift = exponent_max;
6950 }
70 } else if (n < -1022) {
71 y *= 0x1.0p-1022 * 0x1.0p53;
72 n += 1022 - 53;
73 if (n < -1022) {
74 y *= 0x1.0p-1022 * 0x1.0p53;
75 n += 1022 - 53;
76 if (n < -1022) {
77 n = -1022;
78 }
51 } else if (shift < exponent_min) {
52 base *= scale_min;
53 shift -= scale_min_expo;
54 if (shift < exponent_min) {
55 base *= scale_min;
56 shift -= scale_min_expo;
57 if (shift < exponent_min) shift = exponent_min;
7958 }
8059 }
8160
82 const u = @intCast(u64, n +% 0x3FF) << 52;
83 return y * @bitCast(f64, u);
61 return base * @bitCast(T, @intCast(IntT, shift + exponent_bias) << mantissa_bits);
8462}
8563
8664test "math.scalbn" {
87 try expect(scalbn(@as(f32, 1.5), 4) == scalbn32(1.5, 4));
88 try expect(scalbn(@as(f64, 1.5), 4) == scalbn64(1.5, 4));
89}
65 // basic usage
66 try expect(scalbn(@as(f16, 1.5), 4) == 24.0);
67 try expect(scalbn(@as(f32, 1.5), 4) == 24.0);
68 try expect(scalbn(@as(f64, 1.5), 4) == 24.0);
69 try expect(scalbn(@as(f128, 1.5), 4) == 24.0);
9070
91test "math.scalbn32" {
92 try expect(scalbn32(1.5, 4) == 24.0);
93}
71 // subnormals
72 try expect(math.isNormal(scalbn(@as(f16, 1.0), -14)));
73 try expect(!math.isNormal(scalbn(@as(f16, 1.0), -15)));
74 try expect(math.isNormal(scalbn(@as(f32, 1.0), -126)));
75 try expect(!math.isNormal(scalbn(@as(f32, 1.0), -127)));
76 try expect(math.isNormal(scalbn(@as(f64, 1.0), -1022)));
77 try expect(!math.isNormal(scalbn(@as(f64, 1.0), -1023)));
78 try expect(math.isNormal(scalbn(@as(f128, 1.0), -16382)));
79 try expect(!math.isNormal(scalbn(@as(f128, 1.0), -16383)));
80 // unreliable due to lack of native f16 support, see talk on PR #8733
81 // try expect(scalbn(@as(f16, 0x1.1FFp-1), -14 - 9) == math.f16_true_min);
82 try expect(scalbn(@as(f32, 0x1.3FFFFFp-1), -126 - 22) == math.f32_true_min);
83 try expect(scalbn(@as(f64, 0x1.7FFFFFFFFFFFFp-1), -1022 - 51) == math.f64_true_min);
84 try expect(scalbn(@as(f128, 0x1.7FFFFFFFFFFFFFFFFFFFFFFFFFFFp-1), -16382 - 111) == math.f128_true_min);
9485
95test "math.scalbn64" {
96 try expect(scalbn64(1.5, 4) == 24.0);
86 // float limits
87 try expect(scalbn(@as(f32, math.f32_max), -128 - 149) > 0.0);
88 try expect(scalbn(@as(f32, math.f32_max), -128 - 149 - 1) == 0.0);
89 try expect(!math.isPositiveInf(scalbn(@as(f16, math.f16_true_min), 15 + 24)));
90 try expect(math.isPositiveInf(scalbn(@as(f16, math.f16_true_min), 15 + 24 + 1)));
91 try expect(!math.isPositiveInf(scalbn(@as(f32, math.f32_true_min), 127 + 149)));
92 try expect(math.isPositiveInf(scalbn(@as(f32, math.f32_true_min), 127 + 149 + 1)));
93 try expect(!math.isPositiveInf(scalbn(@as(f64, math.f64_true_min), 1023 + 1074)));
94 try expect(math.isPositiveInf(scalbn(@as(f64, math.f64_true_min), 1023 + 1074 + 1)));
95 try expect(!math.isPositiveInf(scalbn(@as(f128, math.f128_true_min), 16383 + 16494)));
96 try expect(math.isPositiveInf(scalbn(@as(f128, math.f128_true_min), 16383 + 16494 + 1)));
9797}
lib/std/os/bits/linux/errno-sparc.zig+1
......@@ -52,6 +52,7 @@ pub const ENOPROTOOPT = 42;
5252pub const EPROTONOSUPPORT = 43;
5353pub const ESOCKTNOSUPPORT = 44;
5454pub const EOPNOTSUPP = 45;
55pub const ENOTSUP = EOPNOTSUPP;
5556pub const EPFNOSUPPORT = 46;
5657pub const EAFNOSUPPORT = 47;
5758pub const EADDRINUSE = 48;
lib/std/special/compiler_rt.zig+10
......@@ -297,7 +297,17 @@ comptime {
297297 @export(@import("compiler_rt/sparc.zig")._Qp_fgt, .{ .name = "_Qp_fgt", .linkage = linkage });
298298 @export(@import("compiler_rt/sparc.zig")._Qp_fge, .{ .name = "_Qp_fge", .linkage = linkage });
299299
300 @export(@import("compiler_rt/sparc.zig")._Qp_itoq, .{ .name = "_Qp_itoq", .linkage = linkage });
301 @export(@import("compiler_rt/sparc.zig")._Qp_uitoq, .{ .name = "_Qp_uitoq", .linkage = linkage });
302 @export(@import("compiler_rt/sparc.zig")._Qp_xtoq, .{ .name = "_Qp_xtoq", .linkage = linkage });
303 @export(@import("compiler_rt/sparc.zig")._Qp_uxtoq, .{ .name = "_Qp_uxtoq", .linkage = linkage });
304 @export(@import("compiler_rt/sparc.zig")._Qp_stoq, .{ .name = "_Qp_stoq", .linkage = linkage });
300305 @export(@import("compiler_rt/sparc.zig")._Qp_dtoq, .{ .name = "_Qp_dtoq", .linkage = linkage });
306 @export(@import("compiler_rt/sparc.zig")._Qp_qtoi, .{ .name = "_Qp_qtoi", .linkage = linkage });
307 @export(@import("compiler_rt/sparc.zig")._Qp_qtoui, .{ .name = "_Qp_qtoui", .linkage = linkage });
308 @export(@import("compiler_rt/sparc.zig")._Qp_qtox, .{ .name = "_Qp_qtox", .linkage = linkage });
309 @export(@import("compiler_rt/sparc.zig")._Qp_qtoux, .{ .name = "_Qp_qtoux", .linkage = linkage });
310 @export(@import("compiler_rt/sparc.zig")._Qp_qtos, .{ .name = "_Qp_qtos", .linkage = linkage });
301311 @export(@import("compiler_rt/sparc.zig")._Qp_qtod, .{ .name = "_Qp_qtod", .linkage = linkage });
302312 }
303313
lib/std/special/compiler_rt/mulXf3.zig+6-6
......@@ -98,8 +98,8 @@ fn mulXf3(comptime T: type, a: T, b: T) T {
9898 // one or both of a or b is denormal, the other (if applicable) is a
9999 // normal number. Renormalize one or both of a and b, and set scale to
100100 // include the necessary exponent adjustment.
101 if (aAbs < implicitBit) scale +%= normalize(T, &aSignificand);
102 if (bAbs < implicitBit) scale +%= normalize(T, &bSignificand);
101 if (aAbs < implicitBit) scale += normalize(T, &aSignificand);
102 if (bAbs < implicitBit) scale += normalize(T, &bSignificand);
103103 }
104104
105105 // Or in the implicit significand bit. (If we fell through from the
......@@ -277,7 +277,7 @@ fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeInfo(T
277277
278278 const shift = @clz(Z, significand.*) - @clz(Z, implicitBit);
279279 significand.* <<= @intCast(std.math.Log2Int(Z), shift);
280 return 1 - shift;
280 return @as(i32, 1) - shift;
281281}
282282
283283fn wideRightShiftWithSticky(comptime Z: type, hi: *Z, lo: *Z, count: u32) void {
......@@ -285,15 +285,15 @@ fn wideRightShiftWithSticky(comptime Z: type, hi: *Z, lo: *Z, count: u32) void {
285285 const typeWidth = @typeInfo(Z).Int.bits;
286286 const S = std.math.Log2Int(Z);
287287 if (count < typeWidth) {
288 const sticky = @truncate(u8, lo.* << @intCast(S, typeWidth -% count));
288 const sticky = @boolToInt((lo.* << @intCast(S, typeWidth -% count)) != 0);
289289 lo.* = (hi.* << @intCast(S, typeWidth -% count)) | (lo.* >> @intCast(S, count)) | sticky;
290290 hi.* = hi.* >> @intCast(S, count);
291291 } else if (count < 2 * typeWidth) {
292 const sticky = @truncate(u8, hi.* << @intCast(S, 2 * typeWidth -% count) | lo.*);
292 const sticky = @boolToInt((hi.* << @intCast(S, 2 * typeWidth -% count) | lo.*) != 0);
293293 lo.* = hi.* >> @intCast(S, count -% typeWidth) | sticky;
294294 hi.* = 0;
295295 } else {
296 const sticky = @truncate(u8, hi.* | lo.*);
296 const sticky = @boolToInt((hi.* | lo.*) != 0);
297297 lo.* = sticky;
298298 hi.* = 0;
299299 }
lib/std/special/compiler_rt/mulXf3_test.zig+14
......@@ -88,4 +88,18 @@ test "multf3" {
8888 );
8989
9090 try test__multf3(0x1.23456734245345p-10000, 0x1.edcba524498724p-6497, 0x0, 0x0);
91
92 // Denormal operands.
93 try test__multf3(
94 0x0.0000000000000000000000000001p-16382,
95 0x1.p16383,
96 0x3f90000000000000,
97 0x0,
98 );
99 try test__multf3(
100 0x1.p16383,
101 0x0.0000000000000000000000000001p-16382,
102 0x3f90000000000000,
103 0x0,
104 );
91105}
lib/std/special/compiler_rt/sparc.zig+41-1
......@@ -68,12 +68,52 @@ pub fn _Qp_fge(a: *f128, b: *f128) callconv(.C) bool {
6868 return cmp == @enumToInt(FCMP.Greater) or cmp == @enumToInt(FCMP.Equal);
6969}
7070
71// Casting
71// Conversion
72
73pub fn _Qp_itoq(c: *f128, a: i32) callconv(.C) void {
74 c.* = @import("floatsiXf.zig").__floatsitf(a);
75}
76
77pub fn _Qp_uitoq(c: *f128, a: u32) callconv(.C) void {
78 c.* = @import("floatunsitf.zig").__floatunsitf(a);
79}
80
81pub fn _Qp_xtoq(c: *f128, a: i64) callconv(.C) void {
82 c.* = @import("floatditf.zig").__floatditf(a);
83}
84
85pub fn _Qp_uxtoq(c: *f128, a: u64) callconv(.C) void {
86 c.* = @import("floatunditf.zig").__floatunditf(a);
87}
88
89pub fn _Qp_stoq(c: *f128, a: f32) callconv(.C) void {
90 c.* = @import("extendXfYf2.zig").__extendsftf2(a);
91}
7292
7393pub fn _Qp_dtoq(c: *f128, a: f64) callconv(.C) void {
7494 c.* = @import("extendXfYf2.zig").__extenddftf2(a);
7595}
7696
97pub fn _Qp_qtoi(a: *f128) callconv(.C) i32 {
98 return @import("fixtfsi.zig").__fixtfsi(a.*);
99}
100
101pub fn _Qp_qtoui(a: *f128) callconv(.C) u32 {
102 return @import("fixunstfsi.zig").__fixunstfsi(a.*);
103}
104
105pub fn _Qp_qtox(a: *f128) callconv(.C) i64 {
106 return @import("fixtfdi.zig").__fixtfdi(a.*);
107}
108
109pub fn _Qp_qtoux(a: *f128) callconv(.C) u64 {
110 return @import("fixunstfdi.zig").__fixunstfdi(a.*);
111}
112
113pub fn _Qp_qtos(a: *f128) callconv(.C) f32 {
114 return @import("truncXfYf2.zig").__trunctfsf2(a.*);
115}
116
77117pub fn _Qp_qtod(a: *f128) callconv(.C) f64 {
78118 return @import("truncXfYf2.zig").__trunctfdf2(a.*);
79119}
lib/std/start.zig+1-1
......@@ -46,7 +46,7 @@ comptime {
4646 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {
4747 if (builtin.link_libc and @hasDecl(root, "main")) {
4848 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
49 @export(main, .{ .name = "main", .linkage = .Weak });
49 @export(main, .{ .name = "main" });
5050 }
5151 } else if (native_os == .windows) {
5252 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
lib/std/target.zig+13-1
......@@ -431,6 +431,7 @@ pub const Target = struct {
431431 pub const powerpc = @import("target/powerpc.zig");
432432 pub const riscv = @import("target/riscv.zig");
433433 pub const sparc = @import("target/sparc.zig");
434 pub const spirv = @import("target/spirv.zig");
434435 pub const systemz = @import("target/systemz.zig");
435436 pub const ve = @import("target/ve.zig");
436437 pub const wasm = @import("target/wasm.zig");
......@@ -594,7 +595,7 @@ pub const Target = struct {
594595 pub const Set = struct {
595596 ints: [usize_count]usize,
596597
597 pub const needed_bit_count = 172;
598 pub const needed_bit_count = 288;
598599 pub const byte_count = (needed_bit_count + 7) / 8;
599600 pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize);
600601 pub const Index = std.math.Log2Int(std.meta.Int(.unsigned, usize_count * @bitSizeOf(usize)));
......@@ -822,6 +823,13 @@ pub const Target = struct {
822823 };
823824 }
824825
826 pub fn isSPIRV(arch: Arch) bool {
827 return switch (arch) {
828 .spirv32, .spirv64 => true,
829 else => false,
830 };
831 }
832
825833 pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model {
826834 for (arch.allCpuModels()) |cpu| {
827835 if (mem.eql(u8, cpu_name, cpu.name)) {
......@@ -1116,6 +1124,7 @@ pub const Target = struct {
11161124 .amdgcn => &amdgpu.all_features,
11171125 .riscv32, .riscv64 => &riscv.all_features,
11181126 .sparc, .sparcv9, .sparcel => &sparc.all_features,
1127 .spirv32, .spirv64 => &spirv.all_features,
11191128 .s390x => &systemz.all_features,
11201129 .i386, .x86_64 => &x86.all_features,
11211130 .nvptx, .nvptx64 => &nvptx.all_features,
......@@ -1320,6 +1329,9 @@ pub const Target = struct {
13201329 if (cpu_arch.isWasm()) {
13211330 return .wasm;
13221331 }
1332 if (cpu_arch.isSPIRV()) {
1333 return .spirv;
1334 }
13231335 return .elf;
13241336 }
13251337
lib/std/target/spirv.zig created+2135
......@@ -0,0 +1,2135 @@
1//! This file is auto-generated by tools/update_spirv_features.zig.
2//! TODO: Dependencies of capabilities on extensions.
3//! TODO: Dependencies of extensions on extensions.
4//! TODO: Dependencies of extensions on versions.
5
6const std = @import("../std.zig");
7const CpuFeature = std.Target.Cpu.Feature;
8const CpuModel = std.Target.Cpu.Model;
9
10pub const Feature = enum {
11 v1_1,
12 v1_2,
13 v1_3,
14 v1_4,
15 v1_5,
16 SPV_AMD_shader_fragment_mask,
17 SPV_AMD_gpu_shader_int16,
18 SPV_AMD_gpu_shader_half_float,
19 SPV_AMD_texture_gather_bias_lod,
20 SPV_AMD_shader_ballot,
21 SPV_AMD_gcn_shader,
22 SPV_AMD_shader_image_load_store_lod,
23 SPV_AMD_shader_explicit_vertex_parameter,
24 SPV_AMD_shader_trinary_minmax,
25 SPV_AMD_gpu_shader_half_float_fetch,
26 SPV_GOOGLE_hlsl_functionality1,
27 SPV_GOOGLE_user_type,
28 SPV_GOOGLE_decorate_string,
29 SPV_EXT_demote_to_helper_invocation,
30 SPV_EXT_descriptor_indexing,
31 SPV_EXT_fragment_fully_covered,
32 SPV_EXT_shader_stencil_export,
33 SPV_EXT_physical_storage_buffer,
34 SPV_EXT_shader_atomic_float_add,
35 SPV_EXT_shader_atomic_float_min_max,
36 SPV_EXT_shader_image_int64,
37 SPV_EXT_fragment_shader_interlock,
38 SPV_EXT_fragment_invocation_density,
39 SPV_EXT_shader_viewport_index_layer,
40 SPV_INTEL_loop_fuse,
41 SPV_INTEL_fpga_dsp_control,
42 SPV_INTEL_fpga_reg,
43 SPV_INTEL_fpga_memory_accesses,
44 SPV_INTEL_fpga_loop_controls,
45 SPV_INTEL_io_pipes,
46 SPV_INTEL_unstructured_loop_controls,
47 SPV_INTEL_blocking_pipes,
48 SPV_INTEL_device_side_avc_motion_estimation,
49 SPV_INTEL_fpga_memory_attributes,
50 SPV_INTEL_fp_fast_math_mode,
51 SPV_INTEL_media_block_io,
52 SPV_INTEL_shader_integer_functions2,
53 SPV_INTEL_subgroups,
54 SPV_INTEL_fpga_cluster_attributes,
55 SPV_INTEL_kernel_attributes,
56 SPV_INTEL_arbitrary_precision_integers,
57 SPV_KHR_8bit_storage,
58 SPV_KHR_shader_clock,
59 SPV_KHR_device_group,
60 SPV_KHR_16bit_storage,
61 SPV_KHR_variable_pointers,
62 SPV_KHR_no_integer_wrap_decoration,
63 SPV_KHR_subgroup_vote,
64 SPV_KHR_multiview,
65 SPV_KHR_shader_ballot,
66 SPV_KHR_vulkan_memory_model,
67 SPV_KHR_physical_storage_buffer,
68 SPV_KHR_workgroup_memory_explicit_layout,
69 SPV_KHR_fragment_shading_rate,
70 SPV_KHR_shader_atomic_counter_ops,
71 SPV_KHR_shader_draw_parameters,
72 SPV_KHR_storage_buffer_storage_class,
73 SPV_KHR_linkonce_odr,
74 SPV_KHR_terminate_invocation,
75 SPV_KHR_non_semantic_info,
76 SPV_KHR_post_depth_coverage,
77 SPV_KHR_expect_assume,
78 SPV_KHR_ray_tracing,
79 SPV_KHR_ray_query,
80 SPV_KHR_float_controls,
81 SPV_NV_viewport_array2,
82 SPV_NV_shader_subgroup_partitioned,
83 SPV_NVX_multiview_per_view_attributes,
84 SPV_NV_ray_tracing,
85 SPV_NV_shader_image_footprint,
86 SPV_NV_shading_rate,
87 SPV_NV_stereo_view_rendering,
88 SPV_NV_compute_shader_derivatives,
89 SPV_NV_shader_sm_builtins,
90 SPV_NV_mesh_shader,
91 SPV_NV_geometry_shader_passthrough,
92 SPV_NV_fragment_shader_barycentric,
93 SPV_NV_cooperative_matrix,
94 SPV_NV_sample_mask_override_coverage,
95 Matrix,
96 Shader,
97 Geometry,
98 Tessellation,
99 Addresses,
100 Linkage,
101 Kernel,
102 Vector16,
103 Float16Buffer,
104 Float16,
105 Float64,
106 Int64,
107 Int64Atomics,
108 ImageBasic,
109 ImageReadWrite,
110 ImageMipmap,
111 Pipes,
112 Groups,
113 DeviceEnqueue,
114 LiteralSampler,
115 AtomicStorage,
116 Int16,
117 TessellationPointSize,
118 GeometryPointSize,
119 ImageGatherExtended,
120 StorageImageMultisample,
121 UniformBufferArrayDynamicIndexing,
122 SampledImageArrayDynamicIndexing,
123 StorageBufferArrayDynamicIndexing,
124 StorageImageArrayDynamicIndexing,
125 ClipDistance,
126 CullDistance,
127 ImageCubeArray,
128 SampleRateShading,
129 ImageRect,
130 SampledRect,
131 GenericPointer,
132 Int8,
133 InputAttachment,
134 SparseResidency,
135 MinLod,
136 Sampled1D,
137 Image1D,
138 SampledCubeArray,
139 SampledBuffer,
140 ImageBuffer,
141 ImageMSArray,
142 StorageImageExtendedFormats,
143 ImageQuery,
144 DerivativeControl,
145 InterpolationFunction,
146 TransformFeedback,
147 GeometryStreams,
148 StorageImageReadWithoutFormat,
149 StorageImageWriteWithoutFormat,
150 MultiViewport,
151 SubgroupDispatch,
152 NamedBarrier,
153 PipeStorage,
154 GroupNonUniform,
155 GroupNonUniformVote,
156 GroupNonUniformArithmetic,
157 GroupNonUniformBallot,
158 GroupNonUniformShuffle,
159 GroupNonUniformShuffleRelative,
160 GroupNonUniformClustered,
161 GroupNonUniformQuad,
162 ShaderLayer,
163 ShaderViewportIndex,
164 FragmentShadingRateKHR,
165 SubgroupBallotKHR,
166 DrawParameters,
167 WorkgroupMemoryExplicitLayoutKHR,
168 WorkgroupMemoryExplicitLayout8BitAccessKHR,
169 WorkgroupMemoryExplicitLayout16BitAccessKHR,
170 SubgroupVoteKHR,
171 StorageBuffer16BitAccess,
172 StorageUniformBufferBlock16,
173 UniformAndStorageBuffer16BitAccess,
174 StorageUniform16,
175 StoragePushConstant16,
176 StorageInputOutput16,
177 DeviceGroup,
178 MultiView,
179 VariablePointersStorageBuffer,
180 VariablePointers,
181 AtomicStorageOps,
182 SampleMaskPostDepthCoverage,
183 StorageBuffer8BitAccess,
184 UniformAndStorageBuffer8BitAccess,
185 StoragePushConstant8,
186 DenormPreserve,
187 DenormFlushToZero,
188 SignedZeroInfNanPreserve,
189 RoundingModeRTE,
190 RoundingModeRTZ,
191 RayQueryProvisionalKHR,
192 RayQueryKHR,
193 RayTraversalPrimitiveCullingKHR,
194 RayTracingKHR,
195 Float16ImageAMD,
196 ImageGatherBiasLodAMD,
197 FragmentMaskAMD,
198 StencilExportEXT,
199 ImageReadWriteLodAMD,
200 Int64ImageEXT,
201 ShaderClockKHR,
202 SampleMaskOverrideCoverageNV,
203 GeometryShaderPassthroughNV,
204 ShaderViewportIndexLayerEXT,
205 ShaderViewportIndexLayerNV,
206 ShaderViewportMaskNV,
207 ShaderStereoViewNV,
208 PerViewAttributesNV,
209 FragmentFullyCoveredEXT,
210 MeshShadingNV,
211 ImageFootprintNV,
212 FragmentBarycentricNV,
213 ComputeDerivativeGroupQuadsNV,
214 FragmentDensityEXT,
215 ShadingRateNV,
216 GroupNonUniformPartitionedNV,
217 ShaderNonUniform,
218 ShaderNonUniformEXT,
219 RuntimeDescriptorArray,
220 RuntimeDescriptorArrayEXT,
221 InputAttachmentArrayDynamicIndexing,
222 InputAttachmentArrayDynamicIndexingEXT,
223 UniformTexelBufferArrayDynamicIndexing,
224 UniformTexelBufferArrayDynamicIndexingEXT,
225 StorageTexelBufferArrayDynamicIndexing,
226 StorageTexelBufferArrayDynamicIndexingEXT,
227 UniformBufferArrayNonUniformIndexing,
228 UniformBufferArrayNonUniformIndexingEXT,
229 SampledImageArrayNonUniformIndexing,
230 SampledImageArrayNonUniformIndexingEXT,
231 StorageBufferArrayNonUniformIndexing,
232 StorageBufferArrayNonUniformIndexingEXT,
233 StorageImageArrayNonUniformIndexing,
234 StorageImageArrayNonUniformIndexingEXT,
235 InputAttachmentArrayNonUniformIndexing,
236 InputAttachmentArrayNonUniformIndexingEXT,
237 UniformTexelBufferArrayNonUniformIndexing,
238 UniformTexelBufferArrayNonUniformIndexingEXT,
239 StorageTexelBufferArrayNonUniformIndexing,
240 StorageTexelBufferArrayNonUniformIndexingEXT,
241 RayTracingNV,
242 VulkanMemoryModel,
243 VulkanMemoryModelKHR,
244 VulkanMemoryModelDeviceScope,
245 VulkanMemoryModelDeviceScopeKHR,
246 PhysicalStorageBufferAddresses,
247 PhysicalStorageBufferAddressesEXT,
248 ComputeDerivativeGroupLinearNV,
249 RayTracingProvisionalKHR,
250 CooperativeMatrixNV,
251 FragmentShaderSampleInterlockEXT,
252 FragmentShaderShadingRateInterlockEXT,
253 ShaderSMBuiltinsNV,
254 FragmentShaderPixelInterlockEXT,
255 DemoteToHelperInvocationEXT,
256 SubgroupShuffleINTEL,
257 SubgroupBufferBlockIOINTEL,
258 SubgroupImageBlockIOINTEL,
259 SubgroupImageMediaBlockIOINTEL,
260 RoundToInfinityINTEL,
261 FloatingPointModeINTEL,
262 IntegerFunctions2INTEL,
263 FunctionPointersINTEL,
264 IndirectReferencesINTEL,
265 AsmINTEL,
266 AtomicFloat32MinMaxEXT,
267 AtomicFloat64MinMaxEXT,
268 AtomicFloat16MinMaxEXT,
269 VectorComputeINTEL,
270 VectorAnyINTEL,
271 ExpectAssumeKHR,
272 SubgroupAvcMotionEstimationINTEL,
273 SubgroupAvcMotionEstimationIntraINTEL,
274 SubgroupAvcMotionEstimationChromaINTEL,
275 VariableLengthArrayINTEL,
276 FunctionFloatControlINTEL,
277 FPGAMemoryAttributesINTEL,
278 FPFastMathModeINTEL,
279 ArbitraryPrecisionIntegersINTEL,
280 UnstructuredLoopControlsINTEL,
281 FPGALoopControlsINTEL,
282 KernelAttributesINTEL,
283 FPGAKernelAttributesINTEL,
284 FPGAMemoryAccessesINTEL,
285 FPGAClusterAttributesINTEL,
286 LoopFuseINTEL,
287 FPGABufferLocationINTEL,
288 USMStorageClassesINTEL,
289 IOPipesINTEL,
290 BlockingPipesINTEL,
291 FPGARegINTEL,
292 AtomicFloat32AddEXT,
293 AtomicFloat64AddEXT,
294 LongConstantCompositeINTEL,
295};
296
297pub usingnamespace CpuFeature.feature_set_fns(Feature);
298
299pub const all_features = blk: {
300 @setEvalBranchQuota(2000);
301 const len = @typeInfo(Feature).Enum.fields.len;
302 std.debug.assert(len <= CpuFeature.Set.needed_bit_count);
303 var result: [len]CpuFeature = undefined;
304 result[@enumToInt(Feature.v1_1)] = .{
305 .llvm_name = null,
306 .description = "SPIR-V version 1.1",
307 .dependencies = featureSet(&[_]Feature{}),
308 };
309 result[@enumToInt(Feature.v1_2)] = .{
310 .llvm_name = null,
311 .description = "SPIR-V version 1.2",
312 .dependencies = featureSet(&[_]Feature{
313 .v1_1,
314 }),
315 };
316 result[@enumToInt(Feature.v1_3)] = .{
317 .llvm_name = null,
318 .description = "SPIR-V version 1.3",
319 .dependencies = featureSet(&[_]Feature{
320 .v1_2,
321 }),
322 };
323 result[@enumToInt(Feature.v1_4)] = .{
324 .llvm_name = null,
325 .description = "SPIR-V version 1.4",
326 .dependencies = featureSet(&[_]Feature{
327 .v1_3,
328 }),
329 };
330 result[@enumToInt(Feature.v1_5)] = .{
331 .llvm_name = null,
332 .description = "SPIR-V version 1.5",
333 .dependencies = featureSet(&[_]Feature{
334 .v1_4,
335 }),
336 };
337 result[@enumToInt(Feature.SPV_AMD_shader_fragment_mask)] = .{
338 .llvm_name = null,
339 .description = "SPIR-V extension SPV_AMD_shader_fragment_mask",
340 .dependencies = featureSet(&[_]Feature{}),
341 };
342 result[@enumToInt(Feature.SPV_AMD_gpu_shader_int16)] = .{
343 .llvm_name = null,
344 .description = "SPIR-V extension SPV_AMD_gpu_shader_int16",
345 .dependencies = featureSet(&[_]Feature{}),
346 };
347 result[@enumToInt(Feature.SPV_AMD_gpu_shader_half_float)] = .{
348 .llvm_name = null,
349 .description = "SPIR-V extension SPV_AMD_gpu_shader_half_float",
350 .dependencies = featureSet(&[_]Feature{}),
351 };
352 result[@enumToInt(Feature.SPV_AMD_texture_gather_bias_lod)] = .{
353 .llvm_name = null,
354 .description = "SPIR-V extension SPV_AMD_texture_gather_bias_lod",
355 .dependencies = featureSet(&[_]Feature{}),
356 };
357 result[@enumToInt(Feature.SPV_AMD_shader_ballot)] = .{
358 .llvm_name = null,
359 .description = "SPIR-V extension SPV_AMD_shader_ballot",
360 .dependencies = featureSet(&[_]Feature{}),
361 };
362 result[@enumToInt(Feature.SPV_AMD_gcn_shader)] = .{
363 .llvm_name = null,
364 .description = "SPIR-V extension SPV_AMD_gcn_shader",
365 .dependencies = featureSet(&[_]Feature{}),
366 };
367 result[@enumToInt(Feature.SPV_AMD_shader_image_load_store_lod)] = .{
368 .llvm_name = null,
369 .description = "SPIR-V extension SPV_AMD_shader_image_load_store_lod",
370 .dependencies = featureSet(&[_]Feature{}),
371 };
372 result[@enumToInt(Feature.SPV_AMD_shader_explicit_vertex_parameter)] = .{
373 .llvm_name = null,
374 .description = "SPIR-V extension SPV_AMD_shader_explicit_vertex_parameter",
375 .dependencies = featureSet(&[_]Feature{}),
376 };
377 result[@enumToInt(Feature.SPV_AMD_shader_trinary_minmax)] = .{
378 .llvm_name = null,
379 .description = "SPIR-V extension SPV_AMD_shader_trinary_minmax",
380 .dependencies = featureSet(&[_]Feature{}),
381 };
382 result[@enumToInt(Feature.SPV_AMD_gpu_shader_half_float_fetch)] = .{
383 .llvm_name = null,
384 .description = "SPIR-V extension SPV_AMD_gpu_shader_half_float_fetch",
385 .dependencies = featureSet(&[_]Feature{}),
386 };
387 result[@enumToInt(Feature.SPV_GOOGLE_hlsl_functionality1)] = .{
388 .llvm_name = null,
389 .description = "SPIR-V extension SPV_GOOGLE_hlsl_functionality1",
390 .dependencies = featureSet(&[_]Feature{}),
391 };
392 result[@enumToInt(Feature.SPV_GOOGLE_user_type)] = .{
393 .llvm_name = null,
394 .description = "SPIR-V extension SPV_GOOGLE_user_type",
395 .dependencies = featureSet(&[_]Feature{}),
396 };
397 result[@enumToInt(Feature.SPV_GOOGLE_decorate_string)] = .{
398 .llvm_name = null,
399 .description = "SPIR-V extension SPV_GOOGLE_decorate_string",
400 .dependencies = featureSet(&[_]Feature{}),
401 };
402 result[@enumToInt(Feature.SPV_EXT_demote_to_helper_invocation)] = .{
403 .llvm_name = null,
404 .description = "SPIR-V extension SPV_EXT_demote_to_helper_invocation",
405 .dependencies = featureSet(&[_]Feature{}),
406 };
407 result[@enumToInt(Feature.SPV_EXT_descriptor_indexing)] = .{
408 .llvm_name = null,
409 .description = "SPIR-V extension SPV_EXT_descriptor_indexing",
410 .dependencies = featureSet(&[_]Feature{}),
411 };
412 result[@enumToInt(Feature.SPV_EXT_fragment_fully_covered)] = .{
413 .llvm_name = null,
414 .description = "SPIR-V extension SPV_EXT_fragment_fully_covered",
415 .dependencies = featureSet(&[_]Feature{}),
416 };
417 result[@enumToInt(Feature.SPV_EXT_shader_stencil_export)] = .{
418 .llvm_name = null,
419 .description = "SPIR-V extension SPV_EXT_shader_stencil_export",
420 .dependencies = featureSet(&[_]Feature{}),
421 };
422 result[@enumToInt(Feature.SPV_EXT_physical_storage_buffer)] = .{
423 .llvm_name = null,
424 .description = "SPIR-V extension SPV_EXT_physical_storage_buffer",
425 .dependencies = featureSet(&[_]Feature{}),
426 };
427 result[@enumToInt(Feature.SPV_EXT_shader_atomic_float_add)] = .{
428 .llvm_name = null,
429 .description = "SPIR-V extension SPV_EXT_shader_atomic_float_add",
430 .dependencies = featureSet(&[_]Feature{}),
431 };
432 result[@enumToInt(Feature.SPV_EXT_shader_atomic_float_min_max)] = .{
433 .llvm_name = null,
434 .description = "SPIR-V extension SPV_EXT_shader_atomic_float_min_max",
435 .dependencies = featureSet(&[_]Feature{}),
436 };
437 result[@enumToInt(Feature.SPV_EXT_shader_image_int64)] = .{
438 .llvm_name = null,
439 .description = "SPIR-V extension SPV_EXT_shader_image_int64",
440 .dependencies = featureSet(&[_]Feature{}),
441 };
442 result[@enumToInt(Feature.SPV_EXT_fragment_shader_interlock)] = .{
443 .llvm_name = null,
444 .description = "SPIR-V extension SPV_EXT_fragment_shader_interlock",
445 .dependencies = featureSet(&[_]Feature{}),
446 };
447 result[@enumToInt(Feature.SPV_EXT_fragment_invocation_density)] = .{
448 .llvm_name = null,
449 .description = "SPIR-V extension SPV_EXT_fragment_invocation_density",
450 .dependencies = featureSet(&[_]Feature{}),
451 };
452 result[@enumToInt(Feature.SPV_EXT_shader_viewport_index_layer)] = .{
453 .llvm_name = null,
454 .description = "SPIR-V extension SPV_EXT_shader_viewport_index_layer",
455 .dependencies = featureSet(&[_]Feature{}),
456 };
457 result[@enumToInt(Feature.SPV_INTEL_loop_fuse)] = .{
458 .llvm_name = null,
459 .description = "SPIR-V extension SPV_INTEL_loop_fuse",
460 .dependencies = featureSet(&[_]Feature{}),
461 };
462 result[@enumToInt(Feature.SPV_INTEL_fpga_dsp_control)] = .{
463 .llvm_name = null,
464 .description = "SPIR-V extension SPV_INTEL_fpga_dsp_control",
465 .dependencies = featureSet(&[_]Feature{}),
466 };
467 result[@enumToInt(Feature.SPV_INTEL_fpga_reg)] = .{
468 .llvm_name = null,
469 .description = "SPIR-V extension SPV_INTEL_fpga_reg",
470 .dependencies = featureSet(&[_]Feature{}),
471 };
472 result[@enumToInt(Feature.SPV_INTEL_fpga_memory_accesses)] = .{
473 .llvm_name = null,
474 .description = "SPIR-V extension SPV_INTEL_fpga_memory_accesses",
475 .dependencies = featureSet(&[_]Feature{}),
476 };
477 result[@enumToInt(Feature.SPV_INTEL_fpga_loop_controls)] = .{
478 .llvm_name = null,
479 .description = "SPIR-V extension SPV_INTEL_fpga_loop_controls",
480 .dependencies = featureSet(&[_]Feature{}),
481 };
482 result[@enumToInt(Feature.SPV_INTEL_io_pipes)] = .{
483 .llvm_name = null,
484 .description = "SPIR-V extension SPV_INTEL_io_pipes",
485 .dependencies = featureSet(&[_]Feature{}),
486 };
487 result[@enumToInt(Feature.SPV_INTEL_unstructured_loop_controls)] = .{
488 .llvm_name = null,
489 .description = "SPIR-V extension SPV_INTEL_unstructured_loop_controls",
490 .dependencies = featureSet(&[_]Feature{}),
491 };
492 result[@enumToInt(Feature.SPV_INTEL_blocking_pipes)] = .{
493 .llvm_name = null,
494 .description = "SPIR-V extension SPV_INTEL_blocking_pipes",
495 .dependencies = featureSet(&[_]Feature{}),
496 };
497 result[@enumToInt(Feature.SPV_INTEL_device_side_avc_motion_estimation)] = .{
498 .llvm_name = null,
499 .description = "SPIR-V extension SPV_INTEL_device_side_avc_motion_estimation",
500 .dependencies = featureSet(&[_]Feature{}),
501 };
502 result[@enumToInt(Feature.SPV_INTEL_fpga_memory_attributes)] = .{
503 .llvm_name = null,
504 .description = "SPIR-V extension SPV_INTEL_fpga_memory_attributes",
505 .dependencies = featureSet(&[_]Feature{}),
506 };
507 result[@enumToInt(Feature.SPV_INTEL_fp_fast_math_mode)] = .{
508 .llvm_name = null,
509 .description = "SPIR-V extension SPV_INTEL_fp_fast_math_mode",
510 .dependencies = featureSet(&[_]Feature{}),
511 };
512 result[@enumToInt(Feature.SPV_INTEL_media_block_io)] = .{
513 .llvm_name = null,
514 .description = "SPIR-V extension SPV_INTEL_media_block_io",
515 .dependencies = featureSet(&[_]Feature{}),
516 };
517 result[@enumToInt(Feature.SPV_INTEL_shader_integer_functions2)] = .{
518 .llvm_name = null,
519 .description = "SPIR-V extension SPV_INTEL_shader_integer_functions2",
520 .dependencies = featureSet(&[_]Feature{}),
521 };
522 result[@enumToInt(Feature.SPV_INTEL_subgroups)] = .{
523 .llvm_name = null,
524 .description = "SPIR-V extension SPV_INTEL_subgroups",
525 .dependencies = featureSet(&[_]Feature{}),
526 };
527 result[@enumToInt(Feature.SPV_INTEL_fpga_cluster_attributes)] = .{
528 .llvm_name = null,
529 .description = "SPIR-V extension SPV_INTEL_fpga_cluster_attributes",
530 .dependencies = featureSet(&[_]Feature{}),
531 };
532 result[@enumToInt(Feature.SPV_INTEL_kernel_attributes)] = .{
533 .llvm_name = null,
534 .description = "SPIR-V extension SPV_INTEL_kernel_attributes",
535 .dependencies = featureSet(&[_]Feature{}),
536 };
537 result[@enumToInt(Feature.SPV_INTEL_arbitrary_precision_integers)] = .{
538 .llvm_name = null,
539 .description = "SPIR-V extension SPV_INTEL_arbitrary_precision_integers",
540 .dependencies = featureSet(&[_]Feature{}),
541 };
542 result[@enumToInt(Feature.SPV_KHR_8bit_storage)] = .{
543 .llvm_name = null,
544 .description = "SPIR-V extension SPV_KHR_8bit_storage",
545 .dependencies = featureSet(&[_]Feature{}),
546 };
547 result[@enumToInt(Feature.SPV_KHR_shader_clock)] = .{
548 .llvm_name = null,
549 .description = "SPIR-V extension SPV_KHR_shader_clock",
550 .dependencies = featureSet(&[_]Feature{}),
551 };
552 result[@enumToInt(Feature.SPV_KHR_device_group)] = .{
553 .llvm_name = null,
554 .description = "SPIR-V extension SPV_KHR_device_group",
555 .dependencies = featureSet(&[_]Feature{}),
556 };
557 result[@enumToInt(Feature.SPV_KHR_16bit_storage)] = .{
558 .llvm_name = null,
559 .description = "SPIR-V extension SPV_KHR_16bit_storage",
560 .dependencies = featureSet(&[_]Feature{}),
561 };
562 result[@enumToInt(Feature.SPV_KHR_variable_pointers)] = .{
563 .llvm_name = null,
564 .description = "SPIR-V extension SPV_KHR_variable_pointers",
565 .dependencies = featureSet(&[_]Feature{}),
566 };
567 result[@enumToInt(Feature.SPV_KHR_no_integer_wrap_decoration)] = .{
568 .llvm_name = null,
569 .description = "SPIR-V extension SPV_KHR_no_integer_wrap_decoration",
570 .dependencies = featureSet(&[_]Feature{}),
571 };
572 result[@enumToInt(Feature.SPV_KHR_subgroup_vote)] = .{
573 .llvm_name = null,
574 .description = "SPIR-V extension SPV_KHR_subgroup_vote",
575 .dependencies = featureSet(&[_]Feature{}),
576 };
577 result[@enumToInt(Feature.SPV_KHR_multiview)] = .{
578 .llvm_name = null,
579 .description = "SPIR-V extension SPV_KHR_multiview",
580 .dependencies = featureSet(&[_]Feature{}),
581 };
582 result[@enumToInt(Feature.SPV_KHR_shader_ballot)] = .{
583 .llvm_name = null,
584 .description = "SPIR-V extension SPV_KHR_shader_ballot",
585 .dependencies = featureSet(&[_]Feature{}),
586 };
587 result[@enumToInt(Feature.SPV_KHR_vulkan_memory_model)] = .{
588 .llvm_name = null,
589 .description = "SPIR-V extension SPV_KHR_vulkan_memory_model",
590 .dependencies = featureSet(&[_]Feature{}),
591 };
592 result[@enumToInt(Feature.SPV_KHR_physical_storage_buffer)] = .{
593 .llvm_name = null,
594 .description = "SPIR-V extension SPV_KHR_physical_storage_buffer",
595 .dependencies = featureSet(&[_]Feature{}),
596 };
597 result[@enumToInt(Feature.SPV_KHR_workgroup_memory_explicit_layout)] = .{
598 .llvm_name = null,
599 .description = "SPIR-V extension SPV_KHR_workgroup_memory_explicit_layout",
600 .dependencies = featureSet(&[_]Feature{}),
601 };
602 result[@enumToInt(Feature.SPV_KHR_fragment_shading_rate)] = .{
603 .llvm_name = null,
604 .description = "SPIR-V extension SPV_KHR_fragment_shading_rate",
605 .dependencies = featureSet(&[_]Feature{}),
606 };
607 result[@enumToInt(Feature.SPV_KHR_shader_atomic_counter_ops)] = .{
608 .llvm_name = null,
609 .description = "SPIR-V extension SPV_KHR_shader_atomic_counter_ops",
610 .dependencies = featureSet(&[_]Feature{}),
611 };
612 result[@enumToInt(Feature.SPV_KHR_shader_draw_parameters)] = .{
613 .llvm_name = null,
614 .description = "SPIR-V extension SPV_KHR_shader_draw_parameters",
615 .dependencies = featureSet(&[_]Feature{}),
616 };
617 result[@enumToInt(Feature.SPV_KHR_storage_buffer_storage_class)] = .{
618 .llvm_name = null,
619 .description = "SPIR-V extension SPV_KHR_storage_buffer_storage_class",
620 .dependencies = featureSet(&[_]Feature{}),
621 };
622 result[@enumToInt(Feature.SPV_KHR_linkonce_odr)] = .{
623 .llvm_name = null,
624 .description = "SPIR-V extension SPV_KHR_linkonce_odr",
625 .dependencies = featureSet(&[_]Feature{}),
626 };
627 result[@enumToInt(Feature.SPV_KHR_terminate_invocation)] = .{
628 .llvm_name = null,
629 .description = "SPIR-V extension SPV_KHR_terminate_invocation",
630 .dependencies = featureSet(&[_]Feature{}),
631 };
632 result[@enumToInt(Feature.SPV_KHR_non_semantic_info)] = .{
633 .llvm_name = null,
634 .description = "SPIR-V extension SPV_KHR_non_semantic_info",
635 .dependencies = featureSet(&[_]Feature{}),
636 };
637 result[@enumToInt(Feature.SPV_KHR_post_depth_coverage)] = .{
638 .llvm_name = null,
639 .description = "SPIR-V extension SPV_KHR_post_depth_coverage",
640 .dependencies = featureSet(&[_]Feature{}),
641 };
642 result[@enumToInt(Feature.SPV_KHR_expect_assume)] = .{
643 .llvm_name = null,
644 .description = "SPIR-V extension SPV_KHR_expect_assume",
645 .dependencies = featureSet(&[_]Feature{}),
646 };
647 result[@enumToInt(Feature.SPV_KHR_ray_tracing)] = .{
648 .llvm_name = null,
649 .description = "SPIR-V extension SPV_KHR_ray_tracing",
650 .dependencies = featureSet(&[_]Feature{}),
651 };
652 result[@enumToInt(Feature.SPV_KHR_ray_query)] = .{
653 .llvm_name = null,
654 .description = "SPIR-V extension SPV_KHR_ray_query",
655 .dependencies = featureSet(&[_]Feature{}),
656 };
657 result[@enumToInt(Feature.SPV_KHR_float_controls)] = .{
658 .llvm_name = null,
659 .description = "SPIR-V extension SPV_KHR_float_controls",
660 .dependencies = featureSet(&[_]Feature{}),
661 };
662 result[@enumToInt(Feature.SPV_NV_viewport_array2)] = .{
663 .llvm_name = null,
664 .description = "SPIR-V extension SPV_NV_viewport_array2",
665 .dependencies = featureSet(&[_]Feature{}),
666 };
667 result[@enumToInt(Feature.SPV_NV_shader_subgroup_partitioned)] = .{
668 .llvm_name = null,
669 .description = "SPIR-V extension SPV_NV_shader_subgroup_partitioned",
670 .dependencies = featureSet(&[_]Feature{}),
671 };
672 result[@enumToInt(Feature.SPV_NVX_multiview_per_view_attributes)] = .{
673 .llvm_name = null,
674 .description = "SPIR-V extension SPV_NVX_multiview_per_view_attributes",
675 .dependencies = featureSet(&[_]Feature{}),
676 };
677 result[@enumToInt(Feature.SPV_NV_ray_tracing)] = .{
678 .llvm_name = null,
679 .description = "SPIR-V extension SPV_NV_ray_tracing",
680 .dependencies = featureSet(&[_]Feature{}),
681 };
682 result[@enumToInt(Feature.SPV_NV_shader_image_footprint)] = .{
683 .llvm_name = null,
684 .description = "SPIR-V extension SPV_NV_shader_image_footprint",
685 .dependencies = featureSet(&[_]Feature{}),
686 };
687 result[@enumToInt(Feature.SPV_NV_shading_rate)] = .{
688 .llvm_name = null,
689 .description = "SPIR-V extension SPV_NV_shading_rate",
690 .dependencies = featureSet(&[_]Feature{}),
691 };
692 result[@enumToInt(Feature.SPV_NV_stereo_view_rendering)] = .{
693 .llvm_name = null,
694 .description = "SPIR-V extension SPV_NV_stereo_view_rendering",
695 .dependencies = featureSet(&[_]Feature{}),
696 };
697 result[@enumToInt(Feature.SPV_NV_compute_shader_derivatives)] = .{
698 .llvm_name = null,
699 .description = "SPIR-V extension SPV_NV_compute_shader_derivatives",
700 .dependencies = featureSet(&[_]Feature{}),
701 };
702 result[@enumToInt(Feature.SPV_NV_shader_sm_builtins)] = .{
703 .llvm_name = null,
704 .description = "SPIR-V extension SPV_NV_shader_sm_builtins",
705 .dependencies = featureSet(&[_]Feature{}),
706 };
707 result[@enumToInt(Feature.SPV_NV_mesh_shader)] = .{
708 .llvm_name = null,
709 .description = "SPIR-V extension SPV_NV_mesh_shader",
710 .dependencies = featureSet(&[_]Feature{}),
711 };
712 result[@enumToInt(Feature.SPV_NV_geometry_shader_passthrough)] = .{
713 .llvm_name = null,
714 .description = "SPIR-V extension SPV_NV_geometry_shader_passthrough",
715 .dependencies = featureSet(&[_]Feature{}),
716 };
717 result[@enumToInt(Feature.SPV_NV_fragment_shader_barycentric)] = .{
718 .llvm_name = null,
719 .description = "SPIR-V extension SPV_NV_fragment_shader_barycentric",
720 .dependencies = featureSet(&[_]Feature{}),
721 };
722 result[@enumToInt(Feature.SPV_NV_cooperative_matrix)] = .{
723 .llvm_name = null,
724 .description = "SPIR-V extension SPV_NV_cooperative_matrix",
725 .dependencies = featureSet(&[_]Feature{}),
726 };
727 result[@enumToInt(Feature.SPV_NV_sample_mask_override_coverage)] = .{
728 .llvm_name = null,
729 .description = "SPIR-V extension SPV_NV_sample_mask_override_coverage",
730 .dependencies = featureSet(&[_]Feature{}),
731 };
732 result[@enumToInt(Feature.Matrix)] = .{
733 .llvm_name = null,
734 .description = "Enable SPIR-V capability Matrix",
735 .dependencies = featureSet(&[_]Feature{
736 }),
737 };
738 result[@enumToInt(Feature.Shader)] = .{
739 .llvm_name = null,
740 .description = "Enable SPIR-V capability Shader",
741 .dependencies = featureSet(&[_]Feature{
742 .Matrix,
743 }),
744 };
745 result[@enumToInt(Feature.Geometry)] = .{
746 .llvm_name = null,
747 .description = "Enable SPIR-V capability Geometry",
748 .dependencies = featureSet(&[_]Feature{
749 .Shader,
750 }),
751 };
752 result[@enumToInt(Feature.Tessellation)] = .{
753 .llvm_name = null,
754 .description = "Enable SPIR-V capability Tessellation",
755 .dependencies = featureSet(&[_]Feature{
756 .Shader,
757 }),
758 };
759 result[@enumToInt(Feature.Addresses)] = .{
760 .llvm_name = null,
761 .description = "Enable SPIR-V capability Addresses",
762 .dependencies = featureSet(&[_]Feature{
763 }),
764 };
765 result[@enumToInt(Feature.Linkage)] = .{
766 .llvm_name = null,
767 .description = "Enable SPIR-V capability Linkage",
768 .dependencies = featureSet(&[_]Feature{
769 }),
770 };
771 result[@enumToInt(Feature.Kernel)] = .{
772 .llvm_name = null,
773 .description = "Enable SPIR-V capability Kernel",
774 .dependencies = featureSet(&[_]Feature{
775 }),
776 };
777 result[@enumToInt(Feature.Vector16)] = .{
778 .llvm_name = null,
779 .description = "Enable SPIR-V capability Vector16",
780 .dependencies = featureSet(&[_]Feature{
781 .Kernel,
782 }),
783 };
784 result[@enumToInt(Feature.Float16Buffer)] = .{
785 .llvm_name = null,
786 .description = "Enable SPIR-V capability Float16Buffer",
787 .dependencies = featureSet(&[_]Feature{
788 .Kernel,
789 }),
790 };
791 result[@enumToInt(Feature.Float16)] = .{
792 .llvm_name = null,
793 .description = "Enable SPIR-V capability Float16",
794 .dependencies = featureSet(&[_]Feature{
795 }),
796 };
797 result[@enumToInt(Feature.Float64)] = .{
798 .llvm_name = null,
799 .description = "Enable SPIR-V capability Float64",
800 .dependencies = featureSet(&[_]Feature{
801 }),
802 };
803 result[@enumToInt(Feature.Int64)] = .{
804 .llvm_name = null,
805 .description = "Enable SPIR-V capability Int64",
806 .dependencies = featureSet(&[_]Feature{
807 }),
808 };
809 result[@enumToInt(Feature.Int64Atomics)] = .{
810 .llvm_name = null,
811 .description = "Enable SPIR-V capability Int64Atomics",
812 .dependencies = featureSet(&[_]Feature{
813 .Int64,
814 }),
815 };
816 result[@enumToInt(Feature.ImageBasic)] = .{
817 .llvm_name = null,
818 .description = "Enable SPIR-V capability ImageBasic",
819 .dependencies = featureSet(&[_]Feature{
820 .Kernel,
821 }),
822 };
823 result[@enumToInt(Feature.ImageReadWrite)] = .{
824 .llvm_name = null,
825 .description = "Enable SPIR-V capability ImageReadWrite",
826 .dependencies = featureSet(&[_]Feature{
827 .ImageBasic,
828 }),
829 };
830 result[@enumToInt(Feature.ImageMipmap)] = .{
831 .llvm_name = null,
832 .description = "Enable SPIR-V capability ImageMipmap",
833 .dependencies = featureSet(&[_]Feature{
834 .ImageBasic,
835 }),
836 };
837 result[@enumToInt(Feature.Pipes)] = .{
838 .llvm_name = null,
839 .description = "Enable SPIR-V capability Pipes",
840 .dependencies = featureSet(&[_]Feature{
841 .Kernel,
842 }),
843 };
844 result[@enumToInt(Feature.Groups)] = .{
845 .llvm_name = null,
846 .description = "Enable SPIR-V capability Groups",
847 .dependencies = featureSet(&[_]Feature{
848 }),
849 };
850 result[@enumToInt(Feature.DeviceEnqueue)] = .{
851 .llvm_name = null,
852 .description = "Enable SPIR-V capability DeviceEnqueue",
853 .dependencies = featureSet(&[_]Feature{
854 .Kernel,
855 }),
856 };
857 result[@enumToInt(Feature.LiteralSampler)] = .{
858 .llvm_name = null,
859 .description = "Enable SPIR-V capability LiteralSampler",
860 .dependencies = featureSet(&[_]Feature{
861 .Kernel,
862 }),
863 };
864 result[@enumToInt(Feature.AtomicStorage)] = .{
865 .llvm_name = null,
866 .description = "Enable SPIR-V capability AtomicStorage",
867 .dependencies = featureSet(&[_]Feature{
868 .Shader,
869 }),
870 };
871 result[@enumToInt(Feature.Int16)] = .{
872 .llvm_name = null,
873 .description = "Enable SPIR-V capability Int16",
874 .dependencies = featureSet(&[_]Feature{
875 }),
876 };
877 result[@enumToInt(Feature.TessellationPointSize)] = .{
878 .llvm_name = null,
879 .description = "Enable SPIR-V capability TessellationPointSize",
880 .dependencies = featureSet(&[_]Feature{
881 .Tessellation,
882 }),
883 };
884 result[@enumToInt(Feature.GeometryPointSize)] = .{
885 .llvm_name = null,
886 .description = "Enable SPIR-V capability GeometryPointSize",
887 .dependencies = featureSet(&[_]Feature{
888 .Geometry,
889 }),
890 };
891 result[@enumToInt(Feature.ImageGatherExtended)] = .{
892 .llvm_name = null,
893 .description = "Enable SPIR-V capability ImageGatherExtended",
894 .dependencies = featureSet(&[_]Feature{
895 .Shader,
896 }),
897 };
898 result[@enumToInt(Feature.StorageImageMultisample)] = .{
899 .llvm_name = null,
900 .description = "Enable SPIR-V capability StorageImageMultisample",
901 .dependencies = featureSet(&[_]Feature{
902 .Shader,
903 }),
904 };
905 result[@enumToInt(Feature.UniformBufferArrayDynamicIndexing)] = .{
906 .llvm_name = null,
907 .description = "Enable SPIR-V capability UniformBufferArrayDynamicIndexing",
908 .dependencies = featureSet(&[_]Feature{
909 .Shader,
910 }),
911 };
912 result[@enumToInt(Feature.SampledImageArrayDynamicIndexing)] = .{
913 .llvm_name = null,
914 .description = "Enable SPIR-V capability SampledImageArrayDynamicIndexing",
915 .dependencies = featureSet(&[_]Feature{
916 .Shader,
917 }),
918 };
919 result[@enumToInt(Feature.StorageBufferArrayDynamicIndexing)] = .{
920 .llvm_name = null,
921 .description = "Enable SPIR-V capability StorageBufferArrayDynamicIndexing",
922 .dependencies = featureSet(&[_]Feature{
923 .Shader,
924 }),
925 };
926 result[@enumToInt(Feature.StorageImageArrayDynamicIndexing)] = .{
927 .llvm_name = null,
928 .description = "Enable SPIR-V capability StorageImageArrayDynamicIndexing",
929 .dependencies = featureSet(&[_]Feature{
930 .Shader,
931 }),
932 };
933 result[@enumToInt(Feature.ClipDistance)] = .{
934 .llvm_name = null,
935 .description = "Enable SPIR-V capability ClipDistance",
936 .dependencies = featureSet(&[_]Feature{
937 .Shader,
938 }),
939 };
940 result[@enumToInt(Feature.CullDistance)] = .{
941 .llvm_name = null,
942 .description = "Enable SPIR-V capability CullDistance",
943 .dependencies = featureSet(&[_]Feature{
944 .Shader,
945 }),
946 };
947 result[@enumToInt(Feature.ImageCubeArray)] = .{
948 .llvm_name = null,
949 .description = "Enable SPIR-V capability ImageCubeArray",
950 .dependencies = featureSet(&[_]Feature{
951 .SampledCubeArray,
952 }),
953 };
954 result[@enumToInt(Feature.SampleRateShading)] = .{
955 .llvm_name = null,
956 .description = "Enable SPIR-V capability SampleRateShading",
957 .dependencies = featureSet(&[_]Feature{
958 .Shader,
959 }),
960 };
961 result[@enumToInt(Feature.ImageRect)] = .{
962 .llvm_name = null,
963 .description = "Enable SPIR-V capability ImageRect",
964 .dependencies = featureSet(&[_]Feature{
965 .SampledRect,
966 }),
967 };
968 result[@enumToInt(Feature.SampledRect)] = .{
969 .llvm_name = null,
970 .description = "Enable SPIR-V capability SampledRect",
971 .dependencies = featureSet(&[_]Feature{
972 .Shader,
973 }),
974 };
975 result[@enumToInt(Feature.GenericPointer)] = .{
976 .llvm_name = null,
977 .description = "Enable SPIR-V capability GenericPointer",
978 .dependencies = featureSet(&[_]Feature{
979 .Addresses,
980 }),
981 };
982 result[@enumToInt(Feature.Int8)] = .{
983 .llvm_name = null,
984 .description = "Enable SPIR-V capability Int8",
985 .dependencies = featureSet(&[_]Feature{
986 }),
987 };
988 result[@enumToInt(Feature.InputAttachment)] = .{
989 .llvm_name = null,
990 .description = "Enable SPIR-V capability InputAttachment",
991 .dependencies = featureSet(&[_]Feature{
992 .Shader,
993 }),
994 };
995 result[@enumToInt(Feature.SparseResidency)] = .{
996 .llvm_name = null,
997 .description = "Enable SPIR-V capability SparseResidency",
998 .dependencies = featureSet(&[_]Feature{
999 .Shader,
1000 }),
1001 };
1002 result[@enumToInt(Feature.MinLod)] = .{
1003 .llvm_name = null,
1004 .description = "Enable SPIR-V capability MinLod",
1005 .dependencies = featureSet(&[_]Feature{
1006 .Shader,
1007 }),
1008 };
1009 result[@enumToInt(Feature.Sampled1D)] = .{
1010 .llvm_name = null,
1011 .description = "Enable SPIR-V capability Sampled1D",
1012 .dependencies = featureSet(&[_]Feature{
1013 }),
1014 };
1015 result[@enumToInt(Feature.Image1D)] = .{
1016 .llvm_name = null,
1017 .description = "Enable SPIR-V capability Image1D",
1018 .dependencies = featureSet(&[_]Feature{
1019 .Sampled1D,
1020 }),
1021 };
1022 result[@enumToInt(Feature.SampledCubeArray)] = .{
1023 .llvm_name = null,
1024 .description = "Enable SPIR-V capability SampledCubeArray",
1025 .dependencies = featureSet(&[_]Feature{
1026 .Shader,
1027 }),
1028 };
1029 result[@enumToInt(Feature.SampledBuffer)] = .{
1030 .llvm_name = null,
1031 .description = "Enable SPIR-V capability SampledBuffer",
1032 .dependencies = featureSet(&[_]Feature{
1033 }),
1034 };
1035 result[@enumToInt(Feature.ImageBuffer)] = .{
1036 .llvm_name = null,
1037 .description = "Enable SPIR-V capability ImageBuffer",
1038 .dependencies = featureSet(&[_]Feature{
1039 .SampledBuffer,
1040 }),
1041 };
1042 result[@enumToInt(Feature.ImageMSArray)] = .{
1043 .llvm_name = null,
1044 .description = "Enable SPIR-V capability ImageMSArray",
1045 .dependencies = featureSet(&[_]Feature{
1046 .Shader,
1047 }),
1048 };
1049 result[@enumToInt(Feature.StorageImageExtendedFormats)] = .{
1050 .llvm_name = null,
1051 .description = "Enable SPIR-V capability StorageImageExtendedFormats",
1052 .dependencies = featureSet(&[_]Feature{
1053 .Shader,
1054 }),
1055 };
1056 result[@enumToInt(Feature.ImageQuery)] = .{
1057 .llvm_name = null,
1058 .description = "Enable SPIR-V capability ImageQuery",
1059 .dependencies = featureSet(&[_]Feature{
1060 .Shader,
1061 }),
1062 };
1063 result[@enumToInt(Feature.DerivativeControl)] = .{
1064 .llvm_name = null,
1065 .description = "Enable SPIR-V capability DerivativeControl",
1066 .dependencies = featureSet(&[_]Feature{
1067 .Shader,
1068 }),
1069 };
1070 result[@enumToInt(Feature.InterpolationFunction)] = .{
1071 .llvm_name = null,
1072 .description = "Enable SPIR-V capability InterpolationFunction",
1073 .dependencies = featureSet(&[_]Feature{
1074 .Shader,
1075 }),
1076 };
1077 result[@enumToInt(Feature.TransformFeedback)] = .{
1078 .llvm_name = null,
1079 .description = "Enable SPIR-V capability TransformFeedback",
1080 .dependencies = featureSet(&[_]Feature{
1081 .Shader,
1082 }),
1083 };
1084 result[@enumToInt(Feature.GeometryStreams)] = .{
1085 .llvm_name = null,
1086 .description = "Enable SPIR-V capability GeometryStreams",
1087 .dependencies = featureSet(&[_]Feature{
1088 .Geometry,
1089 }),
1090 };
1091 result[@enumToInt(Feature.StorageImageReadWithoutFormat)] = .{
1092 .llvm_name = null,
1093 .description = "Enable SPIR-V capability StorageImageReadWithoutFormat",
1094 .dependencies = featureSet(&[_]Feature{
1095 .Shader,
1096 }),
1097 };
1098 result[@enumToInt(Feature.StorageImageWriteWithoutFormat)] = .{
1099 .llvm_name = null,
1100 .description = "Enable SPIR-V capability StorageImageWriteWithoutFormat",
1101 .dependencies = featureSet(&[_]Feature{
1102 .Shader,
1103 }),
1104 };
1105 result[@enumToInt(Feature.MultiViewport)] = .{
1106 .llvm_name = null,
1107 .description = "Enable SPIR-V capability MultiViewport",
1108 .dependencies = featureSet(&[_]Feature{
1109 .Geometry,
1110 }),
1111 };
1112 result[@enumToInt(Feature.SubgroupDispatch)] = .{
1113 .llvm_name = null,
1114 .description = "Enable SPIR-V capability SubgroupDispatch",
1115 .dependencies = featureSet(&[_]Feature{
1116 .v1_1,
1117 .DeviceEnqueue,
1118 }),
1119 };
1120 result[@enumToInt(Feature.NamedBarrier)] = .{
1121 .llvm_name = null,
1122 .description = "Enable SPIR-V capability NamedBarrier",
1123 .dependencies = featureSet(&[_]Feature{
1124 .v1_1,
1125 .Kernel,
1126 }),
1127 };
1128 result[@enumToInt(Feature.PipeStorage)] = .{
1129 .llvm_name = null,
1130 .description = "Enable SPIR-V capability PipeStorage",
1131 .dependencies = featureSet(&[_]Feature{
1132 .v1_1,
1133 .Pipes,
1134 }),
1135 };
1136 result[@enumToInt(Feature.GroupNonUniform)] = .{
1137 .llvm_name = null,
1138 .description = "Enable SPIR-V capability GroupNonUniform",
1139 .dependencies = featureSet(&[_]Feature{
1140 .v1_3,
1141 }),
1142 };
1143 result[@enumToInt(Feature.GroupNonUniformVote)] = .{
1144 .llvm_name = null,
1145 .description = "Enable SPIR-V capability GroupNonUniformVote",
1146 .dependencies = featureSet(&[_]Feature{
1147 .v1_3,
1148 .GroupNonUniform,
1149 }),
1150 };
1151 result[@enumToInt(Feature.GroupNonUniformArithmetic)] = .{
1152 .llvm_name = null,
1153 .description = "Enable SPIR-V capability GroupNonUniformArithmetic",
1154 .dependencies = featureSet(&[_]Feature{
1155 .v1_3,
1156 .GroupNonUniform,
1157 }),
1158 };
1159 result[@enumToInt(Feature.GroupNonUniformBallot)] = .{
1160 .llvm_name = null,
1161 .description = "Enable SPIR-V capability GroupNonUniformBallot",
1162 .dependencies = featureSet(&[_]Feature{
1163 .v1_3,
1164 .GroupNonUniform,
1165 }),
1166 };
1167 result[@enumToInt(Feature.GroupNonUniformShuffle)] = .{
1168 .llvm_name = null,
1169 .description = "Enable SPIR-V capability GroupNonUniformShuffle",
1170 .dependencies = featureSet(&[_]Feature{
1171 .v1_3,
1172 .GroupNonUniform,
1173 }),
1174 };
1175 result[@enumToInt(Feature.GroupNonUniformShuffleRelative)] = .{
1176 .llvm_name = null,
1177 .description = "Enable SPIR-V capability GroupNonUniformShuffleRelative",
1178 .dependencies = featureSet(&[_]Feature{
1179 .v1_3,
1180 .GroupNonUniform,
1181 }),
1182 };
1183 result[@enumToInt(Feature.GroupNonUniformClustered)] = .{
1184 .llvm_name = null,
1185 .description = "Enable SPIR-V capability GroupNonUniformClustered",
1186 .dependencies = featureSet(&[_]Feature{
1187 .v1_3,
1188 .GroupNonUniform,
1189 }),
1190 };
1191 result[@enumToInt(Feature.GroupNonUniformQuad)] = .{
1192 .llvm_name = null,
1193 .description = "Enable SPIR-V capability GroupNonUniformQuad",
1194 .dependencies = featureSet(&[_]Feature{
1195 .v1_3,
1196 .GroupNonUniform,
1197 }),
1198 };
1199 result[@enumToInt(Feature.ShaderLayer)] = .{
1200 .llvm_name = null,
1201 .description = "Enable SPIR-V capability ShaderLayer",
1202 .dependencies = featureSet(&[_]Feature{
1203 .v1_5,
1204 }),
1205 };
1206 result[@enumToInt(Feature.ShaderViewportIndex)] = .{
1207 .llvm_name = null,
1208 .description = "Enable SPIR-V capability ShaderViewportIndex",
1209 .dependencies = featureSet(&[_]Feature{
1210 .v1_5,
1211 }),
1212 };
1213 result[@enumToInt(Feature.FragmentShadingRateKHR)] = .{
1214 .llvm_name = null,
1215 .description = "Enable SPIR-V capability FragmentShadingRateKHR",
1216 .dependencies = featureSet(&[_]Feature{
1217 .Shader,
1218 }),
1219 };
1220 result[@enumToInt(Feature.SubgroupBallotKHR)] = .{
1221 .llvm_name = null,
1222 .description = "Enable SPIR-V capability SubgroupBallotKHR",
1223 .dependencies = featureSet(&[_]Feature{
1224 }),
1225 };
1226 result[@enumToInt(Feature.DrawParameters)] = .{
1227 .llvm_name = null,
1228 .description = "Enable SPIR-V capability DrawParameters",
1229 .dependencies = featureSet(&[_]Feature{
1230 .v1_3,
1231 .Shader,
1232 }),
1233 };
1234 result[@enumToInt(Feature.WorkgroupMemoryExplicitLayoutKHR)] = .{
1235 .llvm_name = null,
1236 .description = "Enable SPIR-V capability WorkgroupMemoryExplicitLayoutKHR",
1237 .dependencies = featureSet(&[_]Feature{
1238 .Shader,
1239 }),
1240 };
1241 result[@enumToInt(Feature.WorkgroupMemoryExplicitLayout8BitAccessKHR)] = .{
1242 .llvm_name = null,
1243 .description = "Enable SPIR-V capability WorkgroupMemoryExplicitLayout8BitAccessKHR",
1244 .dependencies = featureSet(&[_]Feature{
1245 .WorkgroupMemoryExplicitLayoutKHR,
1246 }),
1247 };
1248 result[@enumToInt(Feature.WorkgroupMemoryExplicitLayout16BitAccessKHR)] = .{
1249 .llvm_name = null,
1250 .description = "Enable SPIR-V capability WorkgroupMemoryExplicitLayout16BitAccessKHR",
1251 .dependencies = featureSet(&[_]Feature{
1252 .Shader,
1253 }),
1254 };
1255 result[@enumToInt(Feature.SubgroupVoteKHR)] = .{
1256 .llvm_name = null,
1257 .description = "Enable SPIR-V capability SubgroupVoteKHR",
1258 .dependencies = featureSet(&[_]Feature{
1259 }),
1260 };
1261 result[@enumToInt(Feature.StorageBuffer16BitAccess)] = .{
1262 .llvm_name = null,
1263 .description = "Enable SPIR-V capability StorageBuffer16BitAccess",
1264 .dependencies = featureSet(&[_]Feature{
1265 .v1_3,
1266 }),
1267 };
1268 result[@enumToInt(Feature.StorageUniformBufferBlock16)] = .{
1269 .llvm_name = null,
1270 .description = "Enable SPIR-V capability StorageUniformBufferBlock16",
1271 .dependencies = featureSet(&[_]Feature{
1272 .v1_3,
1273 }),
1274 };
1275 result[@enumToInt(Feature.UniformAndStorageBuffer16BitAccess)] = .{
1276 .llvm_name = null,
1277 .description = "Enable SPIR-V capability UniformAndStorageBuffer16BitAccess",
1278 .dependencies = featureSet(&[_]Feature{
1279 .v1_3,
1280 .StorageBuffer16BitAccess,
1281 .StorageUniformBufferBlock16,
1282 }),
1283 };
1284 result[@enumToInt(Feature.StorageUniform16)] = .{
1285 .llvm_name = null,
1286 .description = "Enable SPIR-V capability StorageUniform16",
1287 .dependencies = featureSet(&[_]Feature{
1288 .v1_3,
1289 .StorageBuffer16BitAccess,
1290 .StorageUniformBufferBlock16,
1291 }),
1292 };
1293 result[@enumToInt(Feature.StoragePushConstant16)] = .{
1294 .llvm_name = null,
1295 .description = "Enable SPIR-V capability StoragePushConstant16",
1296 .dependencies = featureSet(&[_]Feature{
1297 .v1_3,
1298 }),
1299 };
1300 result[@enumToInt(Feature.StorageInputOutput16)] = .{
1301 .llvm_name = null,
1302 .description = "Enable SPIR-V capability StorageInputOutput16",
1303 .dependencies = featureSet(&[_]Feature{
1304 .v1_3,
1305 }),
1306 };
1307 result[@enumToInt(Feature.DeviceGroup)] = .{
1308 .llvm_name = null,
1309 .description = "Enable SPIR-V capability DeviceGroup",
1310 .dependencies = featureSet(&[_]Feature{
1311 .v1_3,
1312 }),
1313 };
1314 result[@enumToInt(Feature.MultiView)] = .{
1315 .llvm_name = null,
1316 .description = "Enable SPIR-V capability MultiView",
1317 .dependencies = featureSet(&[_]Feature{
1318 .v1_3,
1319 .Shader,
1320 }),
1321 };
1322 result[@enumToInt(Feature.VariablePointersStorageBuffer)] = .{
1323 .llvm_name = null,
1324 .description = "Enable SPIR-V capability VariablePointersStorageBuffer",
1325 .dependencies = featureSet(&[_]Feature{
1326 .v1_3,
1327 .Shader,
1328 }),
1329 };
1330 result[@enumToInt(Feature.VariablePointers)] = .{
1331 .llvm_name = null,
1332 .description = "Enable SPIR-V capability VariablePointers",
1333 .dependencies = featureSet(&[_]Feature{
1334 .v1_3,
1335 .VariablePointersStorageBuffer,
1336 }),
1337 };
1338 result[@enumToInt(Feature.AtomicStorageOps)] = .{
1339 .llvm_name = null,
1340 .description = "Enable SPIR-V capability AtomicStorageOps",
1341 .dependencies = featureSet(&[_]Feature{
1342 }),
1343 };
1344 result[@enumToInt(Feature.SampleMaskPostDepthCoverage)] = .{
1345 .llvm_name = null,
1346 .description = "Enable SPIR-V capability SampleMaskPostDepthCoverage",
1347 .dependencies = featureSet(&[_]Feature{
1348 }),
1349 };
1350 result[@enumToInt(Feature.StorageBuffer8BitAccess)] = .{
1351 .llvm_name = null,
1352 .description = "Enable SPIR-V capability StorageBuffer8BitAccess",
1353 .dependencies = featureSet(&[_]Feature{
1354 .v1_5,
1355 }),
1356 };
1357 result[@enumToInt(Feature.UniformAndStorageBuffer8BitAccess)] = .{
1358 .llvm_name = null,
1359 .description = "Enable SPIR-V capability UniformAndStorageBuffer8BitAccess",
1360 .dependencies = featureSet(&[_]Feature{
1361 .v1_5,
1362 .StorageBuffer8BitAccess,
1363 }),
1364 };
1365 result[@enumToInt(Feature.StoragePushConstant8)] = .{
1366 .llvm_name = null,
1367 .description = "Enable SPIR-V capability StoragePushConstant8",
1368 .dependencies = featureSet(&[_]Feature{
1369 .v1_5,
1370 }),
1371 };
1372 result[@enumToInt(Feature.DenormPreserve)] = .{
1373 .llvm_name = null,
1374 .description = "Enable SPIR-V capability DenormPreserve",
1375 .dependencies = featureSet(&[_]Feature{
1376 .v1_4,
1377 }),
1378 };
1379 result[@enumToInt(Feature.DenormFlushToZero)] = .{
1380 .llvm_name = null,
1381 .description = "Enable SPIR-V capability DenormFlushToZero",
1382 .dependencies = featureSet(&[_]Feature{
1383 .v1_4,
1384 }),
1385 };
1386 result[@enumToInt(Feature.SignedZeroInfNanPreserve)] = .{
1387 .llvm_name = null,
1388 .description = "Enable SPIR-V capability SignedZeroInfNanPreserve",
1389 .dependencies = featureSet(&[_]Feature{
1390 .v1_4,
1391 }),
1392 };
1393 result[@enumToInt(Feature.RoundingModeRTE)] = .{
1394 .llvm_name = null,
1395 .description = "Enable SPIR-V capability RoundingModeRTE",
1396 .dependencies = featureSet(&[_]Feature{
1397 .v1_4,
1398 }),
1399 };
1400 result[@enumToInt(Feature.RoundingModeRTZ)] = .{
1401 .llvm_name = null,
1402 .description = "Enable SPIR-V capability RoundingModeRTZ",
1403 .dependencies = featureSet(&[_]Feature{
1404 .v1_4,
1405 }),
1406 };
1407 result[@enumToInt(Feature.RayQueryProvisionalKHR)] = .{
1408 .llvm_name = null,
1409 .description = "Enable SPIR-V capability RayQueryProvisionalKHR",
1410 .dependencies = featureSet(&[_]Feature{
1411 .Shader,
1412 }),
1413 };
1414 result[@enumToInt(Feature.RayQueryKHR)] = .{
1415 .llvm_name = null,
1416 .description = "Enable SPIR-V capability RayQueryKHR",
1417 .dependencies = featureSet(&[_]Feature{
1418 .Shader,
1419 }),
1420 };
1421 result[@enumToInt(Feature.RayTraversalPrimitiveCullingKHR)] = .{
1422 .llvm_name = null,
1423 .description = "Enable SPIR-V capability RayTraversalPrimitiveCullingKHR",
1424 .dependencies = featureSet(&[_]Feature{
1425 .RayQueryKHR,
1426 .RayTracingKHR,
1427 }),
1428 };
1429 result[@enumToInt(Feature.RayTracingKHR)] = .{
1430 .llvm_name = null,
1431 .description = "Enable SPIR-V capability RayTracingKHR",
1432 .dependencies = featureSet(&[_]Feature{
1433 .Shader,
1434 }),
1435 };
1436 result[@enumToInt(Feature.Float16ImageAMD)] = .{
1437 .llvm_name = null,
1438 .description = "Enable SPIR-V capability Float16ImageAMD",
1439 .dependencies = featureSet(&[_]Feature{
1440 .Shader,
1441 }),
1442 };
1443 result[@enumToInt(Feature.ImageGatherBiasLodAMD)] = .{
1444 .llvm_name = null,
1445 .description = "Enable SPIR-V capability ImageGatherBiasLodAMD",
1446 .dependencies = featureSet(&[_]Feature{
1447 .Shader,
1448 }),
1449 };
1450 result[@enumToInt(Feature.FragmentMaskAMD)] = .{
1451 .llvm_name = null,
1452 .description = "Enable SPIR-V capability FragmentMaskAMD",
1453 .dependencies = featureSet(&[_]Feature{
1454 .Shader,
1455 }),
1456 };
1457 result[@enumToInt(Feature.StencilExportEXT)] = .{
1458 .llvm_name = null,
1459 .description = "Enable SPIR-V capability StencilExportEXT",
1460 .dependencies = featureSet(&[_]Feature{
1461 .Shader,
1462 }),
1463 };
1464 result[@enumToInt(Feature.ImageReadWriteLodAMD)] = .{
1465 .llvm_name = null,
1466 .description = "Enable SPIR-V capability ImageReadWriteLodAMD",
1467 .dependencies = featureSet(&[_]Feature{
1468 .Shader,
1469 }),
1470 };
1471 result[@enumToInt(Feature.Int64ImageEXT)] = .{
1472 .llvm_name = null,
1473 .description = "Enable SPIR-V capability Int64ImageEXT",
1474 .dependencies = featureSet(&[_]Feature{
1475 .Shader,
1476 }),
1477 };
1478 result[@enumToInt(Feature.ShaderClockKHR)] = .{
1479 .llvm_name = null,
1480 .description = "Enable SPIR-V capability ShaderClockKHR",
1481 .dependencies = featureSet(&[_]Feature{
1482 .Shader,
1483 }),
1484 };
1485 result[@enumToInt(Feature.SampleMaskOverrideCoverageNV)] = .{
1486 .llvm_name = null,
1487 .description = "Enable SPIR-V capability SampleMaskOverrideCoverageNV",
1488 .dependencies = featureSet(&[_]Feature{
1489 .SampleRateShading,
1490 }),
1491 };
1492 result[@enumToInt(Feature.GeometryShaderPassthroughNV)] = .{
1493 .llvm_name = null,
1494 .description = "Enable SPIR-V capability GeometryShaderPassthroughNV",
1495 .dependencies = featureSet(&[_]Feature{
1496 .Geometry,
1497 }),
1498 };
1499 result[@enumToInt(Feature.ShaderViewportIndexLayerEXT)] = .{
1500 .llvm_name = null,
1501 .description = "Enable SPIR-V capability ShaderViewportIndexLayerEXT",
1502 .dependencies = featureSet(&[_]Feature{
1503 .MultiViewport,
1504 }),
1505 };
1506 result[@enumToInt(Feature.ShaderViewportIndexLayerNV)] = .{
1507 .llvm_name = null,
1508 .description = "Enable SPIR-V capability ShaderViewportIndexLayerNV",
1509 .dependencies = featureSet(&[_]Feature{
1510 .MultiViewport,
1511 }),
1512 };
1513 result[@enumToInt(Feature.ShaderViewportMaskNV)] = .{
1514 .llvm_name = null,
1515 .description = "Enable SPIR-V capability ShaderViewportMaskNV",
1516 .dependencies = featureSet(&[_]Feature{
1517 .ShaderViewportIndexLayerNV,
1518 }),
1519 };
1520 result[@enumToInt(Feature.ShaderStereoViewNV)] = .{
1521 .llvm_name = null,
1522 .description = "Enable SPIR-V capability ShaderStereoViewNV",
1523 .dependencies = featureSet(&[_]Feature{
1524 .ShaderViewportMaskNV,
1525 }),
1526 };
1527 result[@enumToInt(Feature.PerViewAttributesNV)] = .{
1528 .llvm_name = null,
1529 .description = "Enable SPIR-V capability PerViewAttributesNV",
1530 .dependencies = featureSet(&[_]Feature{
1531 .MultiView,
1532 }),
1533 };
1534 result[@enumToInt(Feature.FragmentFullyCoveredEXT)] = .{
1535 .llvm_name = null,
1536 .description = "Enable SPIR-V capability FragmentFullyCoveredEXT",
1537 .dependencies = featureSet(&[_]Feature{
1538 .Shader,
1539 }),
1540 };
1541 result[@enumToInt(Feature.MeshShadingNV)] = .{
1542 .llvm_name = null,
1543 .description = "Enable SPIR-V capability MeshShadingNV",
1544 .dependencies = featureSet(&[_]Feature{
1545 .Shader,
1546 }),
1547 };
1548 result[@enumToInt(Feature.ImageFootprintNV)] = .{
1549 .llvm_name = null,
1550 .description = "Enable SPIR-V capability ImageFootprintNV",
1551 .dependencies = featureSet(&[_]Feature{
1552 }),
1553 };
1554 result[@enumToInt(Feature.FragmentBarycentricNV)] = .{
1555 .llvm_name = null,
1556 .description = "Enable SPIR-V capability FragmentBarycentricNV",
1557 .dependencies = featureSet(&[_]Feature{
1558 }),
1559 };
1560 result[@enumToInt(Feature.ComputeDerivativeGroupQuadsNV)] = .{
1561 .llvm_name = null,
1562 .description = "Enable SPIR-V capability ComputeDerivativeGroupQuadsNV",
1563 .dependencies = featureSet(&[_]Feature{
1564 }),
1565 };
1566 result[@enumToInt(Feature.FragmentDensityEXT)] = .{
1567 .llvm_name = null,
1568 .description = "Enable SPIR-V capability FragmentDensityEXT",
1569 .dependencies = featureSet(&[_]Feature{
1570 .Shader,
1571 }),
1572 };
1573 result[@enumToInt(Feature.ShadingRateNV)] = .{
1574 .llvm_name = null,
1575 .description = "Enable SPIR-V capability ShadingRateNV",
1576 .dependencies = featureSet(&[_]Feature{
1577 .Shader,
1578 }),
1579 };
1580 result[@enumToInt(Feature.GroupNonUniformPartitionedNV)] = .{
1581 .llvm_name = null,
1582 .description = "Enable SPIR-V capability GroupNonUniformPartitionedNV",
1583 .dependencies = featureSet(&[_]Feature{
1584 }),
1585 };
1586 result[@enumToInt(Feature.ShaderNonUniform)] = .{
1587 .llvm_name = null,
1588 .description = "Enable SPIR-V capability ShaderNonUniform",
1589 .dependencies = featureSet(&[_]Feature{
1590 .v1_5,
1591 .Shader,
1592 }),
1593 };
1594 result[@enumToInt(Feature.ShaderNonUniformEXT)] = .{
1595 .llvm_name = null,
1596 .description = "Enable SPIR-V capability ShaderNonUniformEXT",
1597 .dependencies = featureSet(&[_]Feature{
1598 .v1_5,
1599 .Shader,
1600 }),
1601 };
1602 result[@enumToInt(Feature.RuntimeDescriptorArray)] = .{
1603 .llvm_name = null,
1604 .description = "Enable SPIR-V capability RuntimeDescriptorArray",
1605 .dependencies = featureSet(&[_]Feature{
1606 .v1_5,
1607 .Shader,
1608 }),
1609 };
1610 result[@enumToInt(Feature.RuntimeDescriptorArrayEXT)] = .{
1611 .llvm_name = null,
1612 .description = "Enable SPIR-V capability RuntimeDescriptorArrayEXT",
1613 .dependencies = featureSet(&[_]Feature{
1614 .v1_5,
1615 .Shader,
1616 }),
1617 };
1618 result[@enumToInt(Feature.InputAttachmentArrayDynamicIndexing)] = .{
1619 .llvm_name = null,
1620 .description = "Enable SPIR-V capability InputAttachmentArrayDynamicIndexing",
1621 .dependencies = featureSet(&[_]Feature{
1622 .v1_5,
1623 .InputAttachment,
1624 }),
1625 };
1626 result[@enumToInt(Feature.InputAttachmentArrayDynamicIndexingEXT)] = .{
1627 .llvm_name = null,
1628 .description = "Enable SPIR-V capability InputAttachmentArrayDynamicIndexingEXT",
1629 .dependencies = featureSet(&[_]Feature{
1630 .v1_5,
1631 .InputAttachment,
1632 }),
1633 };
1634 result[@enumToInt(Feature.UniformTexelBufferArrayDynamicIndexing)] = .{
1635 .llvm_name = null,
1636 .description = "Enable SPIR-V capability UniformTexelBufferArrayDynamicIndexing",
1637 .dependencies = featureSet(&[_]Feature{
1638 .v1_5,
1639 .SampledBuffer,
1640 }),
1641 };
1642 result[@enumToInt(Feature.UniformTexelBufferArrayDynamicIndexingEXT)] = .{
1643 .llvm_name = null,
1644 .description = "Enable SPIR-V capability UniformTexelBufferArrayDynamicIndexingEXT",
1645 .dependencies = featureSet(&[_]Feature{
1646 .v1_5,
1647 .SampledBuffer,
1648 }),
1649 };
1650 result[@enumToInt(Feature.StorageTexelBufferArrayDynamicIndexing)] = .{
1651 .llvm_name = null,
1652 .description = "Enable SPIR-V capability StorageTexelBufferArrayDynamicIndexing",
1653 .dependencies = featureSet(&[_]Feature{
1654 .v1_5,
1655 .ImageBuffer,
1656 }),
1657 };
1658 result[@enumToInt(Feature.StorageTexelBufferArrayDynamicIndexingEXT)] = .{
1659 .llvm_name = null,
1660 .description = "Enable SPIR-V capability StorageTexelBufferArrayDynamicIndexingEXT",
1661 .dependencies = featureSet(&[_]Feature{
1662 .v1_5,
1663 .ImageBuffer,
1664 }),
1665 };
1666 result[@enumToInt(Feature.UniformBufferArrayNonUniformIndexing)] = .{
1667 .llvm_name = null,
1668 .description = "Enable SPIR-V capability UniformBufferArrayNonUniformIndexing",
1669 .dependencies = featureSet(&[_]Feature{
1670 .v1_5,
1671 .ShaderNonUniform,
1672 }),
1673 };
1674 result[@enumToInt(Feature.UniformBufferArrayNonUniformIndexingEXT)] = .{
1675 .llvm_name = null,
1676 .description = "Enable SPIR-V capability UniformBufferArrayNonUniformIndexingEXT",
1677 .dependencies = featureSet(&[_]Feature{
1678 .v1_5,
1679 .ShaderNonUniform,
1680 }),
1681 };
1682 result[@enumToInt(Feature.SampledImageArrayNonUniformIndexing)] = .{
1683 .llvm_name = null,
1684 .description = "Enable SPIR-V capability SampledImageArrayNonUniformIndexing",
1685 .dependencies = featureSet(&[_]Feature{
1686 .v1_5,
1687 .ShaderNonUniform,
1688 }),
1689 };
1690 result[@enumToInt(Feature.SampledImageArrayNonUniformIndexingEXT)] = .{
1691 .llvm_name = null,
1692 .description = "Enable SPIR-V capability SampledImageArrayNonUniformIndexingEXT",
1693 .dependencies = featureSet(&[_]Feature{
1694 .v1_5,
1695 .ShaderNonUniform,
1696 }),
1697 };
1698 result[@enumToInt(Feature.StorageBufferArrayNonUniformIndexing)] = .{
1699 .llvm_name = null,
1700 .description = "Enable SPIR-V capability StorageBufferArrayNonUniformIndexing",
1701 .dependencies = featureSet(&[_]Feature{
1702 .v1_5,
1703 .ShaderNonUniform,
1704 }),
1705 };
1706 result[@enumToInt(Feature.StorageBufferArrayNonUniformIndexingEXT)] = .{
1707 .llvm_name = null,
1708 .description = "Enable SPIR-V capability StorageBufferArrayNonUniformIndexingEXT",
1709 .dependencies = featureSet(&[_]Feature{
1710 .v1_5,
1711 .ShaderNonUniform,
1712 }),
1713 };
1714 result[@enumToInt(Feature.StorageImageArrayNonUniformIndexing)] = .{
1715 .llvm_name = null,
1716 .description = "Enable SPIR-V capability StorageImageArrayNonUniformIndexing",
1717 .dependencies = featureSet(&[_]Feature{
1718 .v1_5,
1719 .ShaderNonUniform,
1720 }),
1721 };
1722 result[@enumToInt(Feature.StorageImageArrayNonUniformIndexingEXT)] = .{
1723 .llvm_name = null,
1724 .description = "Enable SPIR-V capability StorageImageArrayNonUniformIndexingEXT",
1725 .dependencies = featureSet(&[_]Feature{
1726 .v1_5,
1727 .ShaderNonUniform,
1728 }),
1729 };
1730 result[@enumToInt(Feature.InputAttachmentArrayNonUniformIndexing)] = .{
1731 .llvm_name = null,
1732 .description = "Enable SPIR-V capability InputAttachmentArrayNonUniformIndexing",
1733 .dependencies = featureSet(&[_]Feature{
1734 .v1_5,
1735 .InputAttachment,
1736 .ShaderNonUniform,
1737 }),
1738 };
1739 result[@enumToInt(Feature.InputAttachmentArrayNonUniformIndexingEXT)] = .{
1740 .llvm_name = null,
1741 .description = "Enable SPIR-V capability InputAttachmentArrayNonUniformIndexingEXT",
1742 .dependencies = featureSet(&[_]Feature{
1743 .v1_5,
1744 .InputAttachment,
1745 .ShaderNonUniform,
1746 }),
1747 };
1748 result[@enumToInt(Feature.UniformTexelBufferArrayNonUniformIndexing)] = .{
1749 .llvm_name = null,
1750 .description = "Enable SPIR-V capability UniformTexelBufferArrayNonUniformIndexing",
1751 .dependencies = featureSet(&[_]Feature{
1752 .v1_5,
1753 .SampledBuffer,
1754 .ShaderNonUniform,
1755 }),
1756 };
1757 result[@enumToInt(Feature.UniformTexelBufferArrayNonUniformIndexingEXT)] = .{
1758 .llvm_name = null,
1759 .description = "Enable SPIR-V capability UniformTexelBufferArrayNonUniformIndexingEXT",
1760 .dependencies = featureSet(&[_]Feature{
1761 .v1_5,
1762 .SampledBuffer,
1763 .ShaderNonUniform,
1764 }),
1765 };
1766 result[@enumToInt(Feature.StorageTexelBufferArrayNonUniformIndexing)] = .{
1767 .llvm_name = null,
1768 .description = "Enable SPIR-V capability StorageTexelBufferArrayNonUniformIndexing",
1769 .dependencies = featureSet(&[_]Feature{
1770 .v1_5,
1771 .ImageBuffer,
1772 .ShaderNonUniform,
1773 }),
1774 };
1775 result[@enumToInt(Feature.StorageTexelBufferArrayNonUniformIndexingEXT)] = .{
1776 .llvm_name = null,
1777 .description = "Enable SPIR-V capability StorageTexelBufferArrayNonUniformIndexingEXT",
1778 .dependencies = featureSet(&[_]Feature{
1779 .v1_5,
1780 .ImageBuffer,
1781 .ShaderNonUniform,
1782 }),
1783 };
1784 result[@enumToInt(Feature.RayTracingNV)] = .{
1785 .llvm_name = null,
1786 .description = "Enable SPIR-V capability RayTracingNV",
1787 .dependencies = featureSet(&[_]Feature{
1788 .Shader,
1789 }),
1790 };
1791 result[@enumToInt(Feature.VulkanMemoryModel)] = .{
1792 .llvm_name = null,
1793 .description = "Enable SPIR-V capability VulkanMemoryModel",
1794 .dependencies = featureSet(&[_]Feature{
1795 .v1_5,
1796 }),
1797 };
1798 result[@enumToInt(Feature.VulkanMemoryModelKHR)] = .{
1799 .llvm_name = null,
1800 .description = "Enable SPIR-V capability VulkanMemoryModelKHR",
1801 .dependencies = featureSet(&[_]Feature{
1802 .v1_5,
1803 }),
1804 };
1805 result[@enumToInt(Feature.VulkanMemoryModelDeviceScope)] = .{
1806 .llvm_name = null,
1807 .description = "Enable SPIR-V capability VulkanMemoryModelDeviceScope",
1808 .dependencies = featureSet(&[_]Feature{
1809 .v1_5,
1810 }),
1811 };
1812 result[@enumToInt(Feature.VulkanMemoryModelDeviceScopeKHR)] = .{
1813 .llvm_name = null,
1814 .description = "Enable SPIR-V capability VulkanMemoryModelDeviceScopeKHR",
1815 .dependencies = featureSet(&[_]Feature{
1816 .v1_5,
1817 }),
1818 };
1819 result[@enumToInt(Feature.PhysicalStorageBufferAddresses)] = .{
1820 .llvm_name = null,
1821 .description = "Enable SPIR-V capability PhysicalStorageBufferAddresses",
1822 .dependencies = featureSet(&[_]Feature{
1823 .v1_5,
1824 .Shader,
1825 }),
1826 };
1827 result[@enumToInt(Feature.PhysicalStorageBufferAddressesEXT)] = .{
1828 .llvm_name = null,
1829 .description = "Enable SPIR-V capability PhysicalStorageBufferAddressesEXT",
1830 .dependencies = featureSet(&[_]Feature{
1831 .v1_5,
1832 .Shader,
1833 }),
1834 };
1835 result[@enumToInt(Feature.ComputeDerivativeGroupLinearNV)] = .{
1836 .llvm_name = null,
1837 .description = "Enable SPIR-V capability ComputeDerivativeGroupLinearNV",
1838 .dependencies = featureSet(&[_]Feature{
1839 }),
1840 };
1841 result[@enumToInt(Feature.RayTracingProvisionalKHR)] = .{
1842 .llvm_name = null,
1843 .description = "Enable SPIR-V capability RayTracingProvisionalKHR",
1844 .dependencies = featureSet(&[_]Feature{
1845 .Shader,
1846 }),
1847 };
1848 result[@enumToInt(Feature.CooperativeMatrixNV)] = .{
1849 .llvm_name = null,
1850 .description = "Enable SPIR-V capability CooperativeMatrixNV",
1851 .dependencies = featureSet(&[_]Feature{
1852 .Shader,
1853 }),
1854 };
1855 result[@enumToInt(Feature.FragmentShaderSampleInterlockEXT)] = .{
1856 .llvm_name = null,
1857 .description = "Enable SPIR-V capability FragmentShaderSampleInterlockEXT",
1858 .dependencies = featureSet(&[_]Feature{
1859 .Shader,
1860 }),
1861 };
1862 result[@enumToInt(Feature.FragmentShaderShadingRateInterlockEXT)] = .{
1863 .llvm_name = null,
1864 .description = "Enable SPIR-V capability FragmentShaderShadingRateInterlockEXT",
1865 .dependencies = featureSet(&[_]Feature{
1866 .Shader,
1867 }),
1868 };
1869 result[@enumToInt(Feature.ShaderSMBuiltinsNV)] = .{
1870 .llvm_name = null,
1871 .description = "Enable SPIR-V capability ShaderSMBuiltinsNV",
1872 .dependencies = featureSet(&[_]Feature{
1873 .Shader,
1874 }),
1875 };
1876 result[@enumToInt(Feature.FragmentShaderPixelInterlockEXT)] = .{
1877 .llvm_name = null,
1878 .description = "Enable SPIR-V capability FragmentShaderPixelInterlockEXT",
1879 .dependencies = featureSet(&[_]Feature{
1880 .Shader,
1881 }),
1882 };
1883 result[@enumToInt(Feature.DemoteToHelperInvocationEXT)] = .{
1884 .llvm_name = null,
1885 .description = "Enable SPIR-V capability DemoteToHelperInvocationEXT",
1886 .dependencies = featureSet(&[_]Feature{
1887 .Shader,
1888 }),
1889 };
1890 result[@enumToInt(Feature.SubgroupShuffleINTEL)] = .{
1891 .llvm_name = null,
1892 .description = "Enable SPIR-V capability SubgroupShuffleINTEL",
1893 .dependencies = featureSet(&[_]Feature{
1894 }),
1895 };
1896 result[@enumToInt(Feature.SubgroupBufferBlockIOINTEL)] = .{
1897 .llvm_name = null,
1898 .description = "Enable SPIR-V capability SubgroupBufferBlockIOINTEL",
1899 .dependencies = featureSet(&[_]Feature{
1900 }),
1901 };
1902 result[@enumToInt(Feature.SubgroupImageBlockIOINTEL)] = .{
1903 .llvm_name = null,
1904 .description = "Enable SPIR-V capability SubgroupImageBlockIOINTEL",
1905 .dependencies = featureSet(&[_]Feature{
1906 }),
1907 };
1908 result[@enumToInt(Feature.SubgroupImageMediaBlockIOINTEL)] = .{
1909 .llvm_name = null,
1910 .description = "Enable SPIR-V capability SubgroupImageMediaBlockIOINTEL",
1911 .dependencies = featureSet(&[_]Feature{
1912 }),
1913 };
1914 result[@enumToInt(Feature.RoundToInfinityINTEL)] = .{
1915 .llvm_name = null,
1916 .description = "Enable SPIR-V capability RoundToInfinityINTEL",
1917 .dependencies = featureSet(&[_]Feature{
1918 }),
1919 };
1920 result[@enumToInt(Feature.FloatingPointModeINTEL)] = .{
1921 .llvm_name = null,
1922 .description = "Enable SPIR-V capability FloatingPointModeINTEL",
1923 .dependencies = featureSet(&[_]Feature{
1924 }),
1925 };
1926 result[@enumToInt(Feature.IntegerFunctions2INTEL)] = .{
1927 .llvm_name = null,
1928 .description = "Enable SPIR-V capability IntegerFunctions2INTEL",
1929 .dependencies = featureSet(&[_]Feature{
1930 .Shader,
1931 }),
1932 };
1933 result[@enumToInt(Feature.FunctionPointersINTEL)] = .{
1934 .llvm_name = null,
1935 .description = "Enable SPIR-V capability FunctionPointersINTEL",
1936 .dependencies = featureSet(&[_]Feature{
1937 }),
1938 };
1939 result[@enumToInt(Feature.IndirectReferencesINTEL)] = .{
1940 .llvm_name = null,
1941 .description = "Enable SPIR-V capability IndirectReferencesINTEL",
1942 .dependencies = featureSet(&[_]Feature{
1943 }),
1944 };
1945 result[@enumToInt(Feature.AsmINTEL)] = .{
1946 .llvm_name = null,
1947 .description = "Enable SPIR-V capability AsmINTEL",
1948 .dependencies = featureSet(&[_]Feature{
1949 }),
1950 };
1951 result[@enumToInt(Feature.AtomicFloat32MinMaxEXT)] = .{
1952 .llvm_name = null,
1953 .description = "Enable SPIR-V capability AtomicFloat32MinMaxEXT",
1954 .dependencies = featureSet(&[_]Feature{
1955 }),
1956 };
1957 result[@enumToInt(Feature.AtomicFloat64MinMaxEXT)] = .{
1958 .llvm_name = null,
1959 .description = "Enable SPIR-V capability AtomicFloat64MinMaxEXT",
1960 .dependencies = featureSet(&[_]Feature{
1961 }),
1962 };
1963 result[@enumToInt(Feature.AtomicFloat16MinMaxEXT)] = .{
1964 .llvm_name = null,
1965 .description = "Enable SPIR-V capability AtomicFloat16MinMaxEXT",
1966 .dependencies = featureSet(&[_]Feature{
1967 }),
1968 };
1969 result[@enumToInt(Feature.VectorComputeINTEL)] = .{
1970 .llvm_name = null,
1971 .description = "Enable SPIR-V capability VectorComputeINTEL",
1972 .dependencies = featureSet(&[_]Feature{
1973 .VectorAnyINTEL,
1974 }),
1975 };
1976 result[@enumToInt(Feature.VectorAnyINTEL)] = .{
1977 .llvm_name = null,
1978 .description = "Enable SPIR-V capability VectorAnyINTEL",
1979 .dependencies = featureSet(&[_]Feature{
1980 }),
1981 };
1982 result[@enumToInt(Feature.ExpectAssumeKHR)] = .{
1983 .llvm_name = null,
1984 .description = "Enable SPIR-V capability ExpectAssumeKHR",
1985 .dependencies = featureSet(&[_]Feature{
1986 }),
1987 };
1988 result[@enumToInt(Feature.SubgroupAvcMotionEstimationINTEL)] = .{
1989 .llvm_name = null,
1990 .description = "Enable SPIR-V capability SubgroupAvcMotionEstimationINTEL",
1991 .dependencies = featureSet(&[_]Feature{
1992 }),
1993 };
1994 result[@enumToInt(Feature.SubgroupAvcMotionEstimationIntraINTEL)] = .{
1995 .llvm_name = null,
1996 .description = "Enable SPIR-V capability SubgroupAvcMotionEstimationIntraINTEL",
1997 .dependencies = featureSet(&[_]Feature{
1998 }),
1999 };
2000 result[@enumToInt(Feature.SubgroupAvcMotionEstimationChromaINTEL)] = .{
2001 .llvm_name = null,
2002 .description = "Enable SPIR-V capability SubgroupAvcMotionEstimationChromaINTEL",
2003 .dependencies = featureSet(&[_]Feature{
2004 }),
2005 };
2006 result[@enumToInt(Feature.VariableLengthArrayINTEL)] = .{
2007 .llvm_name = null,
2008 .description = "Enable SPIR-V capability VariableLengthArrayINTEL",
2009 .dependencies = featureSet(&[_]Feature{
2010 }),
2011 };
2012 result[@enumToInt(Feature.FunctionFloatControlINTEL)] = .{
2013 .llvm_name = null,
2014 .description = "Enable SPIR-V capability FunctionFloatControlINTEL",
2015 .dependencies = featureSet(&[_]Feature{
2016 }),
2017 };
2018 result[@enumToInt(Feature.FPGAMemoryAttributesINTEL)] = .{
2019 .llvm_name = null,
2020 .description = "Enable SPIR-V capability FPGAMemoryAttributesINTEL",
2021 .dependencies = featureSet(&[_]Feature{
2022 }),
2023 };
2024 result[@enumToInt(Feature.FPFastMathModeINTEL)] = .{
2025 .llvm_name = null,
2026 .description = "Enable SPIR-V capability FPFastMathModeINTEL",
2027 .dependencies = featureSet(&[_]Feature{
2028 .Kernel,
2029 }),
2030 };
2031 result[@enumToInt(Feature.ArbitraryPrecisionIntegersINTEL)] = .{
2032 .llvm_name = null,
2033 .description = "Enable SPIR-V capability ArbitraryPrecisionIntegersINTEL",
2034 .dependencies = featureSet(&[_]Feature{
2035 }),
2036 };
2037 result[@enumToInt(Feature.UnstructuredLoopControlsINTEL)] = .{
2038 .llvm_name = null,
2039 .description = "Enable SPIR-V capability UnstructuredLoopControlsINTEL",
2040 .dependencies = featureSet(&[_]Feature{
2041 }),
2042 };
2043 result[@enumToInt(Feature.FPGALoopControlsINTEL)] = .{
2044 .llvm_name = null,
2045 .description = "Enable SPIR-V capability FPGALoopControlsINTEL",
2046 .dependencies = featureSet(&[_]Feature{
2047 }),
2048 };
2049 result[@enumToInt(Feature.KernelAttributesINTEL)] = .{
2050 .llvm_name = null,
2051 .description = "Enable SPIR-V capability KernelAttributesINTEL",
2052 .dependencies = featureSet(&[_]Feature{
2053 }),
2054 };
2055 result[@enumToInt(Feature.FPGAKernelAttributesINTEL)] = .{
2056 .llvm_name = null,
2057 .description = "Enable SPIR-V capability FPGAKernelAttributesINTEL",
2058 .dependencies = featureSet(&[_]Feature{
2059 }),
2060 };
2061 result[@enumToInt(Feature.FPGAMemoryAccessesINTEL)] = .{
2062 .llvm_name = null,
2063 .description = "Enable SPIR-V capability FPGAMemoryAccessesINTEL",
2064 .dependencies = featureSet(&[_]Feature{
2065 }),
2066 };
2067 result[@enumToInt(Feature.FPGAClusterAttributesINTEL)] = .{
2068 .llvm_name = null,
2069 .description = "Enable SPIR-V capability FPGAClusterAttributesINTEL",
2070 .dependencies = featureSet(&[_]Feature{
2071 }),
2072 };
2073 result[@enumToInt(Feature.LoopFuseINTEL)] = .{
2074 .llvm_name = null,
2075 .description = "Enable SPIR-V capability LoopFuseINTEL",
2076 .dependencies = featureSet(&[_]Feature{
2077 }),
2078 };
2079 result[@enumToInt(Feature.FPGABufferLocationINTEL)] = .{
2080 .llvm_name = null,
2081 .description = "Enable SPIR-V capability FPGABufferLocationINTEL",
2082 .dependencies = featureSet(&[_]Feature{
2083 }),
2084 };
2085 result[@enumToInt(Feature.USMStorageClassesINTEL)] = .{
2086 .llvm_name = null,
2087 .description = "Enable SPIR-V capability USMStorageClassesINTEL",
2088 .dependencies = featureSet(&[_]Feature{
2089 }),
2090 };
2091 result[@enumToInt(Feature.IOPipesINTEL)] = .{
2092 .llvm_name = null,
2093 .description = "Enable SPIR-V capability IOPipesINTEL",
2094 .dependencies = featureSet(&[_]Feature{
2095 }),
2096 };
2097 result[@enumToInt(Feature.BlockingPipesINTEL)] = .{
2098 .llvm_name = null,
2099 .description = "Enable SPIR-V capability BlockingPipesINTEL",
2100 .dependencies = featureSet(&[_]Feature{
2101 }),
2102 };
2103 result[@enumToInt(Feature.FPGARegINTEL)] = .{
2104 .llvm_name = null,
2105 .description = "Enable SPIR-V capability FPGARegINTEL",
2106 .dependencies = featureSet(&[_]Feature{
2107 }),
2108 };
2109 result[@enumToInt(Feature.AtomicFloat32AddEXT)] = .{
2110 .llvm_name = null,
2111 .description = "Enable SPIR-V capability AtomicFloat32AddEXT",
2112 .dependencies = featureSet(&[_]Feature{
2113 .Shader,
2114 }),
2115 };
2116 result[@enumToInt(Feature.AtomicFloat64AddEXT)] = .{
2117 .llvm_name = null,
2118 .description = "Enable SPIR-V capability AtomicFloat64AddEXT",
2119 .dependencies = featureSet(&[_]Feature{
2120 .Shader,
2121 }),
2122 };
2123 result[@enumToInt(Feature.LongConstantCompositeINTEL)] = .{
2124 .llvm_name = null,
2125 .description = "Enable SPIR-V capability LongConstantCompositeINTEL",
2126 .dependencies = featureSet(&[_]Feature{
2127 }),
2128 };
2129 const ti = @typeInfo(Feature);
2130 for (result) |*elem, i| {
2131 elem.index = i;
2132 elem.name = ti.Enum.fields[i].name;
2133 }
2134 break :blk result;
2135};
lib/std/testing.zig+16-16
......@@ -29,11 +29,11 @@ pub var zig_exe_path: []const u8 = undefined;
2929/// and then aborts when actual_error_union is not expected_error.
3030pub fn expectError(expected_error: anyerror, actual_error_union: anytype) !void {
3131 if (actual_error_union) |actual_payload| {
32 std.debug.print("expected error.{s}, found {any}", .{ @errorName(expected_error), actual_payload });
32 std.debug.print("expected error.{s}, found {any}\n", .{ @errorName(expected_error), actual_payload });
3333 return error.TestUnexpectedError;
3434 } else |actual_error| {
3535 if (expected_error != actual_error) {
36 std.debug.print("expected error.{s}, found error.{s}", .{
36 std.debug.print("expected error.{s}, found error.{s}\n", .{
3737 @errorName(expected_error),
3838 @errorName(actual_error),
3939 });
......@@ -62,7 +62,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
6262
6363 .Type => {
6464 if (actual != expected) {
65 std.debug.print("expected type {s}, found type {s}", .{ @typeName(expected), @typeName(actual) });
65 std.debug.print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) });
6666 return error.TestExpectedEqual;
6767 }
6868 },
......@@ -78,7 +78,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
7878 .ErrorSet,
7979 => {
8080 if (actual != expected) {
81 std.debug.print("expected {}, found {}", .{ expected, actual });
81 std.debug.print("expected {}, found {}\n", .{ expected, actual });
8282 return error.TestExpectedEqual;
8383 }
8484 },
......@@ -87,17 +87,17 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
8787 switch (pointer.size) {
8888 .One, .Many, .C => {
8989 if (actual != expected) {
90 std.debug.print("expected {*}, found {*}", .{ expected, actual });
90 std.debug.print("expected {*}, found {*}\n", .{ expected, actual });
9191 return error.TestExpectedEqual;
9292 }
9393 },
9494 .Slice => {
9595 if (actual.ptr != expected.ptr) {
96 std.debug.print("expected slice ptr {*}, found {*}", .{ expected.ptr, actual.ptr });
96 std.debug.print("expected slice ptr {*}, found {*}\n", .{ expected.ptr, actual.ptr });
9797 return error.TestExpectedEqual;
9898 }
9999 if (actual.len != expected.len) {
100 std.debug.print("expected slice len {}, found {}", .{ expected.len, actual.len });
100 std.debug.print("expected slice len {}, found {}\n", .{ expected.len, actual.len });
101101 return error.TestExpectedEqual;
102102 }
103103 },
......@@ -110,7 +110,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
110110 var i: usize = 0;
111111 while (i < vectorType.len) : (i += 1) {
112112 if (!std.meta.eql(expected[i], actual[i])) {
113 std.debug.print("index {} incorrect. expected {}, found {}", .{ i, expected[i], actual[i] });
113 std.debug.print("index {} incorrect. expected {}, found {}\n", .{ i, expected[i], actual[i] });
114114 return error.TestExpectedEqual;
115115 }
116116 }
......@@ -153,12 +153,12 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
153153 if (actual) |actual_payload| {
154154 try expectEqual(expected_payload, actual_payload);
155155 } else {
156 std.debug.print("expected {any}, found null", .{expected_payload});
156 std.debug.print("expected {any}, found null\n", .{expected_payload});
157157 return error.TestExpectedEqual;
158158 }
159159 } else {
160160 if (actual) |actual_payload| {
161 std.debug.print("expected null, found {any}", .{actual_payload});
161 std.debug.print("expected null, found {any}\n", .{actual_payload});
162162 return error.TestExpectedEqual;
163163 }
164164 }
......@@ -169,12 +169,12 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
169169 if (actual) |actual_payload| {
170170 try expectEqual(expected_payload, actual_payload);
171171 } else |actual_err| {
172 std.debug.print("expected {any}, found {}", .{ expected_payload, actual_err });
172 std.debug.print("expected {any}, found {}\n", .{ expected_payload, actual_err });
173173 return error.TestExpectedEqual;
174174 }
175175 } else |expected_err| {
176176 if (actual) |actual_payload| {
177 std.debug.print("expected {}, found {any}", .{ expected_err, actual_payload });
177 std.debug.print("expected {}, found {any}\n", .{ expected_err, actual_payload });
178178 return error.TestExpectedEqual;
179179 } else |actual_err| {
180180 try expectEqual(expected_err, actual_err);
......@@ -225,7 +225,7 @@ pub fn expectApproxEqAbs(expected: anytype, actual: @TypeOf(expected), tolerance
225225
226226 switch (@typeInfo(T)) {
227227 .Float => if (!math.approxEqAbs(T, expected, actual, tolerance)) {
228 std.debug.print("actual {}, not within absolute tolerance {} of expected {}", .{ actual, tolerance, expected });
228 std.debug.print("actual {}, not within absolute tolerance {} of expected {}\n", .{ actual, tolerance, expected });
229229 return error.TestExpectedApproxEqAbs;
230230 },
231231
......@@ -257,7 +257,7 @@ pub fn expectApproxEqRel(expected: anytype, actual: @TypeOf(expected), tolerance
257257
258258 switch (@typeInfo(T)) {
259259 .Float => if (!math.approxEqRel(T, expected, actual, tolerance)) {
260 std.debug.print("actual {}, not within relative tolerance {} of expected {}", .{ actual, tolerance, expected });
260 std.debug.print("actual {}, not within relative tolerance {} of expected {}\n", .{ actual, tolerance, expected });
261261 return error.TestExpectedApproxEqRel;
262262 },
263263
......@@ -292,13 +292,13 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
292292 // If the child type is u8 and no weird bytes, we could print it as strings
293293 // Even for the length difference, it would be useful to see the values of the slices probably.
294294 if (expected.len != actual.len) {
295 std.debug.print("slice lengths differ. expected {d}, found {d}", .{ expected.len, actual.len });
295 std.debug.print("slice lengths differ. expected {d}, found {d}\n", .{ expected.len, actual.len });
296296 return error.TestExpectedEqual;
297297 }
298298 var i: usize = 0;
299299 while (i < expected.len) : (i += 1) {
300300 if (!std.meta.eql(expected[i], actual[i])) {
301 std.debug.print("index {} incorrect. expected {any}, found {any}", .{ i, expected[i], actual[i] });
301 std.debug.print("index {} incorrect. expected {any}, found {any}\n", .{ i, expected[i], actual[i] });
302302 return error.TestExpectedEqual;
303303 }
304304 }
lib/std/zig/cross_target.zig+10
......@@ -606,6 +606,7 @@ pub const CrossTarget = struct {
606606 qemu: []const u8,
607607 wine: []const u8,
608608 wasmtime: []const u8,
609 darling: []const u8,
609610 unavailable,
610611 };
611612
......@@ -667,6 +668,15 @@ pub const CrossTarget = struct {
667668 32 => return Executor{ .wasmtime = "wasmtime" },
668669 else => return .unavailable,
669670 },
671 .macos => {
672 // TODO loosen this check once upstream adds QEMU-based emulation
673 // layer for non-host architectures:
674 // https://github.com/darlinghq/darling/issues/863
675 if (cpu_arch != Target.current.cpu.arch) {
676 return .unavailable;
677 }
678 return Executor{ .darling = "darling" };
679 },
670680 else => return .unavailable,
671681 }
672682 }
lib/std/zig/parse.zig+77-241
......@@ -1309,9 +1309,8 @@ const Parser = struct {
13091309 return expr;
13101310 }
13111311
1312 /// Expr <- BoolOrExpr
13131312 fn parseExpr(p: *Parser) Error!Node.Index {
1314 return p.parseBoolOrExpr();
1313 return p.parseExprPrecedence(0);
13151314 }
13161315
13171316 fn expectExpr(p: *Parser) Error!Node.Index {
......@@ -1323,263 +1322,100 @@ const Parser = struct {
13231322 }
13241323 }
13251324
1326 /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
1327 fn parseBoolOrExpr(p: *Parser) Error!Node.Index {
1328 var res = try p.parseBoolAndExpr();
1329 if (res == 0) return null_node;
1325 const Assoc = enum {
1326 left,
1327 none,
1328 };
13301329
1331 while (true) {
1332 switch (p.token_tags[p.tok_i]) {
1333 .keyword_or => {
1334 const or_token = p.nextToken();
1335 const rhs = try p.parseBoolAndExpr();
1336 if (rhs == 0) {
1337 return p.fail(.invalid_token);
1338 }
1339 res = try p.addNode(.{
1340 .tag = .bool_or,
1341 .main_token = or_token,
1342 .data = .{
1343 .lhs = res,
1344 .rhs = rhs,
1345 },
1346 });
1347 },
1348 else => return res,
1349 }
1350 }
1351 }
1330 const OperInfo = struct {
1331 prec: i8,
1332 tag: Node.Tag,
1333 assoc: Assoc = Assoc.left,
1334 };
13521335
1353 /// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*
1354 fn parseBoolAndExpr(p: *Parser) !Node.Index {
1355 var res = try p.parseCompareExpr();
1356 if (res == 0) return null_node;
1336 // A table of binary operator information. Higher precedence numbers are
1337 // stickier. All operators at the same precedence level should have the same
1338 // associativity.
1339 const operTable = std.enums.directEnumArrayDefault(Token.Tag, OperInfo, .{ .prec = -1, .tag = Node.Tag.root }, 0, .{
1340 .keyword_or = .{ .prec = 10, .tag = .bool_or },
1341
1342 .keyword_and = .{ .prec = 20, .tag = .bool_and },
1343 .invalid_ampersands = .{ .prec = 20, .tag = .bool_and },
1344
1345 .equal_equal = .{ .prec = 30, .tag = .equal_equal, .assoc = Assoc.none },
1346 .bang_equal = .{ .prec = 30, .tag = .bang_equal, .assoc = Assoc.none },
1347 .angle_bracket_left = .{ .prec = 30, .tag = .less_than, .assoc = Assoc.none },
1348 .angle_bracket_right = .{ .prec = 30, .tag = .greater_than, .assoc = Assoc.none },
1349 .angle_bracket_left_equal = .{ .prec = 30, .tag = .less_or_equal, .assoc = Assoc.none },
1350 .angle_bracket_right_equal = .{ .prec = 30, .tag = .greater_or_equal, .assoc = Assoc.none },
1351
1352 .ampersand = .{ .prec = 40, .tag = .bit_and },
1353 .caret = .{ .prec = 40, .tag = .bit_xor },
1354 .pipe = .{ .prec = 40, .tag = .bit_or },
1355 .keyword_orelse = .{ .prec = 40, .tag = .@"orelse" },
1356 .keyword_catch = .{ .prec = 40, .tag = .@"catch" },
1357
1358 .angle_bracket_angle_bracket_left = .{ .prec = 50, .tag = .bit_shift_left },
1359 .angle_bracket_angle_bracket_right = .{ .prec = 50, .tag = .bit_shift_right },
1360
1361 .plus = .{ .prec = 60, .tag = .add },
1362 .minus = .{ .prec = 60, .tag = .sub },
1363 .plus_plus = .{ .prec = 60, .tag = .array_cat },
1364 .plus_percent = .{ .prec = 60, .tag = .add_wrap },
1365 .minus_percent = .{ .prec = 60, .tag = .sub_wrap },
1366
1367 .pipe_pipe = .{ .prec = 70, .tag = .merge_error_sets },
1368 .asterisk = .{ .prec = 70, .tag = .mul },
1369 .slash = .{ .prec = 70, .tag = .div },
1370 .percent = .{ .prec = 70, .tag = .mod },
1371 .asterisk_asterisk = .{ .prec = 70, .tag = .array_mult },
1372 .asterisk_percent = .{ .prec = 70, .tag = .mul_wrap },
1373 });
13571374
1358 while (true) {
1359 switch (p.token_tags[p.tok_i]) {
1360 .keyword_and => {
1361 const and_token = p.nextToken();
1362 const rhs = try p.parseCompareExpr();
1363 if (rhs == 0) {
1364 return p.fail(.invalid_token);
1365 }
1366 res = try p.addNode(.{
1367 .tag = .bool_and,
1368 .main_token = and_token,
1369 .data = .{
1370 .lhs = res,
1371 .rhs = rhs,
1372 },
1373 });
1374 },
1375 .invalid_ampersands => {
1376 try p.warn(.invalid_and);
1377 p.tok_i += 1;
1378 return p.parseCompareExpr();
1379 },
1380 else => return res,
1381 }
1375 fn parseExprPrecedence(p: *Parser, min_prec: i32) Error!Node.Index {
1376 var node = try p.parsePrefixExpr();
1377 if (node == 0) {
1378 return null_node;
13821379 }
1383 }
13841380
1385 /// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
1386 /// CompareOp
1387 /// <- EQUALEQUAL
1388 /// / EXCLAMATIONMARKEQUAL
1389 /// / LARROW
1390 /// / RARROW
1391 /// / LARROWEQUAL
1392 /// / RARROWEQUAL
1393 fn parseCompareExpr(p: *Parser) !Node.Index {
1394 const expr = try p.parseBitwiseExpr();
1395 if (expr == 0) return null_node;
1396
1397 const tag: Node.Tag = switch (p.token_tags[p.tok_i]) {
1398 .equal_equal => .equal_equal,
1399 .bang_equal => .bang_equal,
1400 .angle_bracket_left => .less_than,
1401 .angle_bracket_right => .greater_than,
1402 .angle_bracket_left_equal => .less_or_equal,
1403 .angle_bracket_right_equal => .greater_or_equal,
1404 else => return expr,
1405 };
1406 return p.addNode(.{
1407 .tag = tag,
1408 .main_token = p.nextToken(),
1409 .data = .{
1410 .lhs = expr,
1411 .rhs = try p.expectBitwiseExpr(),
1412 },
1413 });
1414 }
1415
1416 /// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
1417 /// BitwiseOp
1418 /// <- AMPERSAND
1419 /// / CARET
1420 /// / PIPE
1421 /// / KEYWORD_orelse
1422 /// / KEYWORD_catch Payload?
1423 fn parseBitwiseExpr(p: *Parser) !Node.Index {
1424 var res = try p.parseBitShiftExpr();
1425 if (res == 0) return null_node;
1381 var banned_prec: i8 = -1;
14261382
14271383 while (true) {
1428 const tag: Node.Tag = switch (p.token_tags[p.tok_i]) {
1429 .ampersand => .bit_and,
1430 .caret => .bit_xor,
1431 .pipe => .bit_or,
1432 .keyword_orelse => .@"orelse",
1384 const tok_tag = p.token_tags[p.tok_i];
1385 const info = operTable[@intCast(usize, @enumToInt(tok_tag))];
1386 if (info.prec < min_prec or info.prec == banned_prec) {
1387 break;
1388 }
1389 const oper_token = p.nextToken();
1390 // Special-case handling for "catch" and "&&".
1391 switch (tok_tag) {
14331392 .keyword_catch => {
1434 const catch_token = p.nextToken();
14351393 _ = try p.parsePayload();
1436 const rhs = try p.parseBitShiftExpr();
1437 if (rhs == 0) {
1438 return p.fail(.invalid_token);
1439 }
1440 res = try p.addNode(.{
1441 .tag = .@"catch",
1442 .main_token = catch_token,
1443 .data = .{
1444 .lhs = res,
1445 .rhs = rhs,
1446 },
1447 });
1448 continue;
1449 },
1450 else => return res,
1451 };
1452 res = try p.addNode(.{
1453 .tag = tag,
1454 .main_token = p.nextToken(),
1455 .data = .{
1456 .lhs = res,
1457 .rhs = try p.expectBitShiftExpr(),
14581394 },
1459 });
1460 }
1461 }
1462
1463 fn expectBitwiseExpr(p: *Parser) Error!Node.Index {
1464 const node = try p.parseBitwiseExpr();
1465 if (node == 0) {
1466 return p.fail(.invalid_token);
1467 } else {
1468 return node;
1469 }
1470 }
1471
1472 /// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
1473 /// BitShiftOp
1474 /// <- LARROW2
1475 /// / RARROW2
1476 fn parseBitShiftExpr(p: *Parser) Error!Node.Index {
1477 var res = try p.parseAdditionExpr();
1478 if (res == 0) return null_node;
1479
1480 while (true) {
1481 const tag: Node.Tag = switch (p.token_tags[p.tok_i]) {
1482 .angle_bracket_angle_bracket_left => .bit_shift_left,
1483 .angle_bracket_angle_bracket_right => .bit_shift_right,
1484 else => return res,
1485 };
1486 res = try p.addNode(.{
1487 .tag = tag,
1488 .main_token = p.nextToken(),
1489 .data = .{
1490 .lhs = res,
1491 .rhs = try p.expectAdditionExpr(),
1395 .invalid_ampersands => {
1396 try p.warn(.invalid_and);
14921397 },
1493 });
1494 }
1495 }
1496
1497 fn expectBitShiftExpr(p: *Parser) Error!Node.Index {
1498 const node = try p.parseBitShiftExpr();
1499 if (node == 0) {
1500 return p.fail(.invalid_token);
1501 } else {
1502 return node;
1503 }
1504 }
1505
1506 /// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
1507 /// AdditionOp
1508 /// <- PLUS
1509 /// / MINUS
1510 /// / PLUS2
1511 /// / PLUSPERCENT
1512 /// / MINUSPERCENT
1513 fn parseAdditionExpr(p: *Parser) Error!Node.Index {
1514 var res = try p.parseMultiplyExpr();
1515 if (res == 0) return null_node;
1398 else => {},
1399 }
1400 const rhs = try p.parseExprPrecedence(info.prec + 1);
1401 if (rhs == 0) {
1402 return p.fail(.invalid_token);
1403 }
15161404
1517 while (true) {
1518 const tag: Node.Tag = switch (p.token_tags[p.tok_i]) {
1519 .plus => .add,
1520 .minus => .sub,
1521 .plus_plus => .array_cat,
1522 .plus_percent => .add_wrap,
1523 .minus_percent => .sub_wrap,
1524 else => return res,
1525 };
1526 res = try p.addNode(.{
1527 .tag = tag,
1528 .main_token = p.nextToken(),
1405 node = try p.addNode(.{
1406 .tag = info.tag,
1407 .main_token = oper_token,
15291408 .data = .{
1530 .lhs = res,
1531 .rhs = try p.expectMultiplyExpr(),
1409 .lhs = node,
1410 .rhs = rhs,
15321411 },
15331412 });
1534 }
1535 }
15361413
1537 fn expectAdditionExpr(p: *Parser) Error!Node.Index {
1538 const node = try p.parseAdditionExpr();
1539 if (node == 0) {
1540 return p.fail(.invalid_token);
1541 }
1542 return node;
1543 }
1544
1545 /// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*
1546 /// MultiplyOp
1547 /// <- PIPE2
1548 /// / ASTERISK
1549 /// / SLASH
1550 /// / PERCENT
1551 /// / ASTERISK2
1552 /// / ASTERISKPERCENT
1553 fn parseMultiplyExpr(p: *Parser) Error!Node.Index {
1554 var res = try p.parsePrefixExpr();
1555 if (res == 0) return null_node;
1556
1557 while (true) {
1558 const tag: Node.Tag = switch (p.token_tags[p.tok_i]) {
1559 .pipe_pipe => .merge_error_sets,
1560 .asterisk => .mul,
1561 .slash => .div,
1562 .percent => .mod,
1563 .asterisk_asterisk => .array_mult,
1564 .asterisk_percent => .mul_wrap,
1565 else => return res,
1566 };
1567 res = try p.addNode(.{
1568 .tag = tag,
1569 .main_token = p.nextToken(),
1570 .data = .{
1571 .lhs = res,
1572 .rhs = try p.expectPrefixExpr(),
1573 },
1574 });
1414 if (info.assoc == Assoc.none) {
1415 banned_prec = info.prec;
1416 }
15751417 }
1576 }
15771418
1578 fn expectMultiplyExpr(p: *Parser) Error!Node.Index {
1579 const node = try p.parseMultiplyExpr();
1580 if (node == 0) {
1581 return p.fail(.invalid_token);
1582 }
15831419 return node;
15841420 }
15851421
lib/std/zig/parser_test.zig+11
......@@ -2828,6 +2828,7 @@ test "zig fmt: precedence" {
28282828 \\ a or b and c;
28292829 \\ (a or b) and c;
28302830 \\ (a or b) and c;
2831 \\ a == b and c == d;
28312832 \\}
28322833 \\
28332834 );
......@@ -4892,6 +4893,16 @@ test "recovery: missing comma" {
48924893 });
48934894}
48944895
4896test "recovery: non-associative operators" {
4897 try testError(
4898 \\const x = a == b == c;
4899 \\const x = a == b != c;
4900 , &[_]Error{
4901 .expected_token,
4902 .expected_token,
4903 });
4904}
4905
48954906test "recovery: extra qualifier" {
48964907 try testError(
48974908 \\const a: *const const u8;
src/Compilation.zig+16-8
......@@ -638,6 +638,7 @@ pub const InitOptions = struct {
638638 system_libs: []const []const u8 = &[0][]const u8{},
639639 link_libc: bool = false,
640640 link_libcpp: bool = false,
641 link_libunwind: bool = false,
641642 want_pic: ?bool = null,
642643 /// This means that if the output mode is an executable it will be a
643644 /// Position Independent Executable. If the output mode is not an
......@@ -885,8 +886,13 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
885886 };
886887
887888 const tsan = options.want_tsan orelse false;
889 // TSAN is implemented in C++ so it requires linking libc++.
890 const link_libcpp = options.link_libcpp or tsan;
891 const link_libc = link_libcpp or options.link_libc or
892 target_util.osRequiresLibC(options.target);
888893
889 const link_libc = options.link_libc or target_util.osRequiresLibC(options.target) or tsan;
894 const link_libunwind = options.link_libunwind or
895 (link_libcpp and target_util.libcNeedsLibUnwind(options.target));
890896
891897 const must_dynamic_link = dl: {
892898 if (target_util.cannotDynamicLink(options.target))
......@@ -972,9 +978,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
972978 break :pic explicit;
973979 } else pie or must_pic;
974980
975 // TSAN is implemented in C++ so it requires linking libc++.
976 const link_libcpp = options.link_libcpp or tsan;
977
978981 // Make a decision on whether to use Clang for translate-c and compiling C files.
979982 const use_clang = if (options.use_clang) |explicit| explicit else blk: {
980983 if (build_options.have_llvm) {
......@@ -1067,6 +1070,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
10671070 cache.hash.add(strip);
10681071 cache.hash.add(link_libc);
10691072 cache.hash.add(link_libcpp);
1073 cache.hash.add(link_libunwind);
10701074 cache.hash.add(options.output_mode);
10711075 cache.hash.add(options.machine_code_model);
10721076 cache.hash.addOptionalEmitLoc(options.emit_bin);
......@@ -1262,6 +1266,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
12621266 .system_linker_hack = darwin_options.system_linker_hack,
12631267 .link_libc = link_libc,
12641268 .link_libcpp = link_libcpp,
1269 .link_libunwind = link_libunwind,
12651270 .objects = options.link_objects,
12661271 .frameworks = options.frameworks,
12671272 .framework_dirs = options.framework_dirs,
......@@ -2943,6 +2948,10 @@ pub fn addCCArgs(
29432948 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
29442949 }
29452950
2951 if (target_util.clangMightShellOutForAssembly(target)) {
2952 try argv.append("-integrated-as");
2953 }
2954
29462955 if (target.os.tag == .freestanding) {
29472956 try argv.append("-ffreestanding");
29482957 }
......@@ -3139,7 +3148,7 @@ fn detectLibCIncludeDirs(
31393148
31403149 if (is_native_abi) {
31413150 const libc = try arena.create(LibCInstallation);
3142 libc.* = try LibCInstallation.findNative(.{ .allocator = arena });
3151 libc.* = try LibCInstallation.findNative(.{ .allocator = arena, .verbose = true });
31433152 return detectLibCFromLibCInstallation(arena, target, libc);
31443153 }
31453154
......@@ -3276,9 +3285,8 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {
32763285 .Lib => comp.bin_file.options.link_mode == .Dynamic,
32773286 .Exe => true,
32783287 };
3279 return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and
3280 comp.bin_file.options.object_format != .c and
3281 target_util.libcNeedsLibUnwind(comp.getTarget());
3288 return is_exe_or_dyn_lib and comp.bin_file.options.link_libunwind and
3289 comp.bin_file.options.object_format != .c;
32823290}
32833291
32843292fn updateBuiltinZigFile(comp: *Compilation, mod: *Module) Allocator.Error!void {
src/clang.zig+5
......@@ -905,6 +905,11 @@ pub const TypedefNameDecl = opaque {
905905 extern fn ZigClangTypedefNameDecl_getLocation(*const TypedefNameDecl) SourceLocation;
906906};
907907
908pub const FileScopeAsmDecl = opaque {
909 pub const getAsmString = ZigClangFileScopeAsmDecl_getAsmString;
910 extern fn ZigClangFileScopeAsmDecl_getAsmString(*const FileScopeAsmDecl) *const StringLiteral;
911};
912
908913pub const TypedefType = opaque {
909914 pub const getDecl = ZigClangTypedefType_getDecl;
910915 extern fn ZigClangTypedefType_getDecl(*const TypedefType) *const TypedefNameDecl;
src/codegen.zig+9-9
......@@ -960,7 +960,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
960960 /// allocated. A second call to `copyToTmpRegister` may return the same register.
961961 /// This can have a side effect of spilling instructions to the stack to free up a register.
962962 fn copyToTmpRegister(self: *Self, src: LazySrcLoc, ty: Type, mcv: MCValue) !Register {
963 const reg = try self.register_manager.allocRegWithoutTracking(&.{});
963 const reg = try self.register_manager.allocReg(null, &.{});
964964 try self.genSetReg(src, ty, reg, mcv);
965965 return reg;
966966 }
......@@ -2231,7 +2231,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
22312231 switch (mc_arg) {
22322232 .none => continue,
22332233 .register => |reg| {
2234 try self.register_manager.getRegWithoutTracking(reg);
2234 try self.register_manager.getReg(reg, null);
22352235 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
22362236 },
22372237 .stack_offset => {
......@@ -2327,7 +2327,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
23272327 .compare_flags_signed => unreachable,
23282328 .compare_flags_unsigned => unreachable,
23292329 .register => |reg| {
2330 try self.register_manager.getRegWithoutTracking(reg);
2330 try self.register_manager.getReg(reg, null);
23312331 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
23322332 },
23332333 .stack_offset => {
......@@ -2390,7 +2390,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
23902390 .compare_flags_signed => unreachable,
23912391 .compare_flags_unsigned => unreachable,
23922392 .register => |reg| {
2393 try self.register_manager.getRegWithoutTracking(reg);
2393 try self.register_manager.getReg(reg, null);
23942394 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
23952395 },
23962396 .stack_offset => {
......@@ -2443,7 +2443,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
24432443 .register => |reg| {
24442444 // TODO prevent this macho if block to be generated for all archs
24452445 switch (arch) {
2446 .x86_64, .aarch64 => try self.register_manager.getRegWithoutTracking(reg),
2446 .x86_64, .aarch64 => try self.register_manager.getReg(reg, null),
24472447 else => unreachable,
24482448 }
24492449 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
......@@ -3134,7 +3134,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
31343134
31353135 const arg = inst.args[i];
31363136 const arg_mcv = try self.resolveInst(arg);
3137 try self.register_manager.getRegWithoutTracking(reg);
3137 try self.register_manager.getReg(reg, null);
31383138 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
31393139 }
31403140
......@@ -3167,7 +3167,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
31673167
31683168 const arg = inst.args[i];
31693169 const arg_mcv = try self.resolveInst(arg);
3170 try self.register_manager.getRegWithoutTracking(reg);
3170 try self.register_manager.getReg(reg, null);
31713171 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
31723172 }
31733173
......@@ -3202,7 +3202,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
32023202
32033203 const arg = inst.args[i];
32043204 const arg_mcv = try self.resolveInst(arg);
3205 try self.register_manager.getRegWithoutTracking(reg);
3205 try self.register_manager.getReg(reg, null);
32063206 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
32073207 }
32083208
......@@ -3235,7 +3235,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
32353235
32363236 const arg = inst.args[i];
32373237 const arg_mcv = try self.resolveInst(arg);
3238 try self.register_manager.getRegWithoutTracking(reg);
3238 try self.register_manager.getReg(reg, null);
32393239 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
32403240 }
32413241
src/codegen/spirv.zig+74-19
......@@ -1,9 +1,13 @@
11const std = @import("std");
22const Allocator = std.mem.Allocator;
3const log = std.log.scoped(.codegen);
34
45const spec = @import("spirv/spec.zig");
56const Module = @import("../Module.zig");
67const Decl = Module.Decl;
8const Type = @import("../type.zig").Type;
9
10pub const TypeMap = std.HashMap(Type, u32, Type.hash, Type.eql, std.hash_map.default_max_load_percentage);
711
812pub fn writeInstruction(code: *std.ArrayList(u32), instr: spec.Opcode, args: []const u32) !void {
913 const word_count = @intCast(u32, args.len + 1);
......@@ -12,38 +16,89 @@ pub fn writeInstruction(code: *std.ArrayList(u32), instr: spec.Opcode, args: []c
1216}
1317
1418pub const SPIRVModule = struct {
15 next_id: u32 = 0,
16 free_id_list: std.ArrayList(u32),
19 next_result_id: u32 = 0,
20
21 target: std.Target,
22
23 types: TypeMap,
24
25 types_and_globals: std.ArrayList(u32),
26 fn_decls: std.ArrayList(u32),
1727
18 pub fn init(allocator: *Allocator) SPIRVModule {
28 pub fn init(target: std.Target, allocator: *Allocator) SPIRVModule {
1929 return .{
20 .free_id_list = std.ArrayList(u32).init(allocator),
30 .target = target,
31 .types = TypeMap.init(allocator),
32 .types_and_globals = std.ArrayList(u32).init(allocator),
33 .fn_decls = std.ArrayList(u32).init(allocator),
2134 };
2235 }
2336
2437 pub fn deinit(self: *SPIRVModule) void {
25 self.free_id_list.deinit();
38 self.fn_decls.deinit();
39 self.types_and_globals.deinit();
40 self.types.deinit();
41 self.* = undefined;
2642 }
2743
28 pub fn allocId(self: *SPIRVModule) u32 {
29 if (self.free_id_list.popOrNull()) |id| return id;
44 pub fn allocResultId(self: *SPIRVModule) u32 {
45 defer self.next_result_id += 1;
46 return self.next_result_id;
47 }
3048
31 defer self.next_id += 1;
32 return self.next_id;
49 pub fn resultIdBound(self: *SPIRVModule) u32 {
50 return self.next_result_id;
3351 }
3452
35 pub fn freeId(self: *SPIRVModule, id: u32) void {
36 if (id + 1 == self.next_id) {
37 self.next_id -= 1;
38 } else {
39 // If no more memory to append the id to the free list, just ignore it.
40 self.free_id_list.append(id) catch {};
53 pub fn getOrGenType(self: *SPIRVModule, t: Type) !u32 {
54 // We can't use getOrPut here so we can recursively generate types.
55 if (self.types.get(t)) |already_generated| {
56 return already_generated;
4157 }
42 }
4358
44 pub fn idBound(self: *SPIRVModule) u32 {
45 return self.next_id;
59 const result = self.allocResultId();
60
61 switch (t.zigTypeTag()) {
62 .Void => try writeInstruction(&self.types_and_globals, .OpTypeVoid, &[_]u32{ result }),
63 .Bool => try writeInstruction(&self.types_and_globals, .OpTypeBool, &[_]u32{ result }),
64 .Int => {
65 const int_info = t.intInfo(self.target);
66 try writeInstruction(&self.types_and_globals, .OpTypeInt, &[_]u32{
67 result,
68 int_info.bits,
69 switch (int_info.signedness) {
70 .unsigned => 0,
71 .signed => 1,
72 },
73 });
74 },
75 // TODO: Verify that floatBits() will be correct.
76 .Float => try writeInstruction(&self.types_and_globals, .OpTypeFloat, &[_]u32{ result, t.floatBits(self.target) }),
77 .Null,
78 .Undefined,
79 .EnumLiteral,
80 .ComptimeFloat,
81 .ComptimeInt,
82 .Type,
83 => unreachable, // Must be const or comptime.
84
85 .BoundFn => unreachable, // this type will be deleted from the language.
86
87 else => return error.TODO,
88 }
89
90 try self.types.put(t, result);
91 return result;
4692 }
4793
48 pub fn genDecl(self: SPIRVModule, id: u32, code: *std.ArrayList(u32), decl: *Decl) !void {}
94 pub fn gen(self: *SPIRVModule, decl: *Decl) !void {
95 switch (decl.ty.zigTypeTag()) {
96 .Fn => {
97 log.debug("Generating code for function '{s}'", .{ std.mem.spanZ(decl.name) });
98
99 _ = try self.getOrGenType(decl.ty.fnReturnType());
100 },
101 else => return error.TODO,
102 }
103 }
49104};
src/codegen/spirv/spec.zig+89-31
......@@ -1,26 +1,5 @@
1// Copyright (c) 2014-2020 The Khronos Group Inc.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and/or associated documentation files (the "Materials"),
5// to deal in the Materials without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Materials, and to permit persons to whom the
8// Materials are furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Materials.
12//
13// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
14// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
15// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
16//
17// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
23// IN THE MATERIALS.
1//! This file is auto-generated by tools/gen_spirv_spec.zig.
2
243const Version = @import("std").builtin.Version;
254pub const version = Version{ .major = 1, .minor = 5, .patch = 4 };
265pub const magic_number: u32 = 0x07230203;
......@@ -443,8 +422,15 @@ pub const Opcode = extern enum(u16) {
443422 OpUSubSatINTEL = 5596,
444423 OpIMul32x16INTEL = 5597,
445424 OpUMul32x16INTEL = 5598,
446 OpFunctionPointerINTEL = 5600,
425 OpConstFunctionPointerINTEL = 5600,
447426 OpFunctionPointerCallINTEL = 5601,
427 OpAsmTargetINTEL = 5609,
428 OpAsmINTEL = 5610,
429 OpAsmCallINTEL = 5611,
430 OpAtomicFMinEXT = 5614,
431 OpAtomicFMaxEXT = 5615,
432 OpAssumeTrueKHR = 5630,
433 OpExpectKHR = 5631,
448434 OpDecorateString = 5632,
449435 OpDecorateStringGOOGLE = 5632,
450436 OpMemberDecorateString = 5633,
......@@ -567,7 +553,12 @@ pub const Opcode = extern enum(u16) {
567553 OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814,
568554 OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815,
569555 OpSubgroupAvcSicGetInterRawSadsINTEL = 5816,
556 OpVariableLengthArrayINTEL = 5818,
557 OpSaveMemoryINTEL = 5819,
558 OpRestoreMemoryINTEL = 5820,
570559 OpLoopControlINTEL = 5887,
560 OpPtrCastToCrossWorkgroupINTEL = 5934,
561 OpCrossWorkgroupCastToPtrINTEL = 5938,
571562 OpReadPipeBlockingINTEL = 5946,
572563 OpWritePipeBlockingINTEL = 5947,
573564 OpFPGARegINTEL = 5949,
......@@ -589,6 +580,10 @@ pub const Opcode = extern enum(u16) {
589580 OpRayQueryGetIntersectionObjectToWorldKHR = 6031,
590581 OpRayQueryGetIntersectionWorldToObjectKHR = 6032,
591582 OpAtomicFAddEXT = 6035,
583 OpTypeBufferSurfaceINTEL = 6086,
584 OpTypeStructContinuedINTEL = 6090,
585 OpConstantCompositeContinuedINTEL = 6091,
586 OpSpecConstantCompositeContinuedINTEL = 6092,
592587 _,
593588};
594589pub const ImageOperands = packed struct {
......@@ -642,8 +637,8 @@ pub const FPFastMathMode = packed struct {
642637 _reserved_bit_13: bool = false,
643638 _reserved_bit_14: bool = false,
644639 _reserved_bit_15: bool = false,
645 _reserved_bit_16: bool = false,
646 _reserved_bit_17: bool = false,
640 AllowContractFastINTEL: bool = false,
641 AllowReassocINTEL: bool = false,
647642 _reserved_bit_18: bool = false,
648643 _reserved_bit_19: bool = false,
649644 _reserved_bit_20: bool = false,
......@@ -717,7 +712,7 @@ pub const LoopControl = packed struct {
717712 LoopCoalesceINTEL: bool = false,
718713 MaxInterleavingINTEL: bool = false,
719714 SpeculatedIterationsINTEL: bool = false,
720 _reserved_bit_23: bool = false,
715 NoFusionINTEL: bool = false,
721716 _reserved_bit_24: bool = false,
722717 _reserved_bit_25: bool = false,
723718 _reserved_bit_26: bool = false,
......@@ -1037,10 +1032,16 @@ pub const ExecutionMode = extern enum(u32) {
10371032 SampleInterlockUnorderedEXT = 5369,
10381033 ShadingRateInterlockOrderedEXT = 5370,
10391034 ShadingRateInterlockUnorderedEXT = 5371,
1035 SharedLocalMemorySizeINTEL = 5618,
1036 RoundingModeRTPINTEL = 5620,
1037 RoundingModeRTNINTEL = 5621,
1038 FloatingPointModeALTINTEL = 5622,
1039 FloatingPointModeIEEEINTEL = 5623,
10401040 MaxWorkgroupSizeINTEL = 5893,
10411041 MaxWorkDimINTEL = 5894,
10421042 NoGlobalOffsetINTEL = 5895,
10431043 NumSIMDWorkitemsINTEL = 5896,
1044 SchedulerTargetFmaxMhzINTEL = 5903,
10441045 _,
10451046};
10461047pub const StorageClass = extern enum(u32) {
......@@ -1072,6 +1073,8 @@ pub const StorageClass = extern enum(u32) {
10721073 PhysicalStorageBuffer = 5349,
10731074 PhysicalStorageBufferEXT = 5349,
10741075 CodeSectionINTEL = 5605,
1076 DeviceOnlyINTEL = 5936,
1077 HostOnlyINTEL = 5937,
10751078 _,
10761079};
10771080pub const Dim = extern enum(u32) {
......@@ -1192,9 +1195,20 @@ pub const FPRoundingMode = extern enum(u32) {
11921195 RTN = 3,
11931196 _,
11941197};
1198pub const FPDenormMode = extern enum(u32) {
1199 Preserve = 0,
1200 FlushToZero = 1,
1201 _,
1202};
1203pub const FPOperationMode = extern enum(u32) {
1204 IEEE = 0,
1205 ALT = 1,
1206 _,
1207};
11951208pub const LinkageType = extern enum(u32) {
11961209 Export = 0,
11971210 Import = 1,
1211 LinkOnceODR = 2,
11981212 _,
11991213};
12001214pub const AccessQualifier = extern enum(u32) {
......@@ -1279,12 +1293,22 @@ pub const Decoration = extern enum(u32) {
12791293 RestrictPointerEXT = 5355,
12801294 AliasedPointer = 5356,
12811295 AliasedPointerEXT = 5356,
1296 SIMTCallINTEL = 5599,
12821297 ReferencedIndirectlyINTEL = 5602,
1298 ClobberINTEL = 5607,
1299 SideEffectsINTEL = 5608,
1300 VectorComputeVariableINTEL = 5624,
1301 FuncParamIOKindINTEL = 5625,
1302 VectorComputeFunctionINTEL = 5626,
1303 StackCallINTEL = 5627,
1304 GlobalVariableOffsetINTEL = 5628,
12831305 CounterBuffer = 5634,
12841306 HlslCounterBufferGOOGLE = 5634,
12851307 UserSemantic = 5635,
12861308 HlslSemanticGOOGLE = 5635,
12871309 UserTypeGOOGLE = 5636,
1310 FunctionRoundingModeINTEL = 5822,
1311 FunctionDenormModeINTEL = 5823,
12881312 RegisterINTEL = 5825,
12891313 MemoryINTEL = 5826,
12901314 NumbanksINTEL = 5827,
......@@ -1297,6 +1321,17 @@ pub const Decoration = extern enum(u32) {
12971321 MergeINTEL = 5834,
12981322 BankBitsINTEL = 5835,
12991323 ForcePow2DepthINTEL = 5836,
1324 BurstCoalesceINTEL = 5899,
1325 CacheSizeINTEL = 5900,
1326 DontStaticallyCoalesceINTEL = 5901,
1327 PrefetchINTEL = 5902,
1328 StallEnableINTEL = 5905,
1329 FuseLoopsInFunctionINTEL = 5907,
1330 BufferLocationINTEL = 5921,
1331 IOPipeStorageINTEL = 5944,
1332 FunctionFloatingPointModeINTEL = 6080,
1333 SingleElementVectorINTEL = 6085,
1334 VectorComputeCallableFunctionINTEL = 6087,
13001335 _,
13011336};
13021337pub const BuiltIn = extern enum(u32) {
......@@ -1342,14 +1377,14 @@ pub const BuiltIn = extern enum(u32) {
13421377 VertexIndex = 42,
13431378 InstanceIndex = 43,
13441379 SubgroupEqMask = 4416,
1345 SubgroupGeMask = 4417,
1346 SubgroupGtMask = 4418,
1347 SubgroupLeMask = 4419,
1348 SubgroupLtMask = 4420,
13491380 SubgroupEqMaskKHR = 4416,
1381 SubgroupGeMask = 4417,
13501382 SubgroupGeMaskKHR = 4417,
1383 SubgroupGtMask = 4418,
13511384 SubgroupGtMaskKHR = 4418,
1385 SubgroupLeMask = 4419,
13521386 SubgroupLeMaskKHR = 4419,
1387 SubgroupLtMask = 4420,
13531388 SubgroupLtMaskKHR = 4420,
13541389 BaseVertex = 4424,
13551390 BaseInstance = 4425,
......@@ -1520,6 +1555,9 @@ pub const Capability = extern enum(u32) {
15201555 FragmentShadingRateKHR = 4422,
15211556 SubgroupBallotKHR = 4423,
15221557 DrawParameters = 4427,
1558 WorkgroupMemoryExplicitLayoutKHR = 4428,
1559 WorkgroupMemoryExplicitLayout8BitAccessKHR = 4429,
1560 WorkgroupMemoryExplicitLayout16BitAccessKHR = 4430,
15231561 SubgroupVoteKHR = 4431,
15241562 StorageBuffer16BitAccess = 4433,
15251563 StorageUniformBufferBlock16 = 4433,
......@@ -1610,21 +1648,41 @@ pub const Capability = extern enum(u32) {
16101648 SubgroupBufferBlockIOINTEL = 5569,
16111649 SubgroupImageBlockIOINTEL = 5570,
16121650 SubgroupImageMediaBlockIOINTEL = 5579,
1651 RoundToInfinityINTEL = 5582,
1652 FloatingPointModeINTEL = 5583,
16131653 IntegerFunctions2INTEL = 5584,
16141654 FunctionPointersINTEL = 5603,
16151655 IndirectReferencesINTEL = 5604,
1656 AsmINTEL = 5606,
1657 AtomicFloat32MinMaxEXT = 5612,
1658 AtomicFloat64MinMaxEXT = 5613,
1659 AtomicFloat16MinMaxEXT = 5616,
1660 VectorComputeINTEL = 5617,
1661 VectorAnyINTEL = 5619,
1662 ExpectAssumeKHR = 5629,
16161663 SubgroupAvcMotionEstimationINTEL = 5696,
16171664 SubgroupAvcMotionEstimationIntraINTEL = 5697,
16181665 SubgroupAvcMotionEstimationChromaINTEL = 5698,
1666 VariableLengthArrayINTEL = 5817,
1667 FunctionFloatControlINTEL = 5821,
16191668 FPGAMemoryAttributesINTEL = 5824,
1669 FPFastMathModeINTEL = 5837,
1670 ArbitraryPrecisionIntegersINTEL = 5844,
16201671 UnstructuredLoopControlsINTEL = 5886,
16211672 FPGALoopControlsINTEL = 5888,
16221673 KernelAttributesINTEL = 5892,
16231674 FPGAKernelAttributesINTEL = 5897,
1675 FPGAMemoryAccessesINTEL = 5898,
1676 FPGAClusterAttributesINTEL = 5904,
1677 LoopFuseINTEL = 5906,
1678 FPGABufferLocationINTEL = 5920,
1679 USMStorageClassesINTEL = 5935,
1680 IOPipesINTEL = 5943,
16241681 BlockingPipesINTEL = 5945,
16251682 FPGARegINTEL = 5948,
16261683 AtomicFloat32AddEXT = 6033,
16271684 AtomicFloat64AddEXT = 6034,
1685 LongConstantCompositeINTEL = 6089,
16281686 _,
16291687};
16301688pub const RayQueryIntersection = extern enum(u32) {
src/glibc.zig+7-3
......@@ -446,10 +446,14 @@ fn start_asm_path(comp: *Compilation, arena: *Allocator, basename: []const u8) !
446446 try result.appendSlice(comp.zig_lib_directory.path.?);
447447 try result.appendSlice(s ++ "libc" ++ s ++ "glibc" ++ s ++ "sysdeps" ++ s);
448448 if (is_sparc) {
449 if (is_64) {
450 try result.appendSlice("sparc" ++ s ++ "sparc64");
449 if (mem.eql(u8, basename, "crti.S") or mem.eql(u8, basename, "crtn.S")) {
450 try result.appendSlice("sparc");
451451 } else {
452 try result.appendSlice("sparc" ++ s ++ "sparc32");
452 if (is_64) {
453 try result.appendSlice("sparc" ++ s ++ "sparc64");
454 } else {
455 try result.appendSlice("sparc" ++ s ++ "sparc32");
456 }
453457 }
454458 } else if (arch.isARM()) {
455459 try result.appendSlice("arm");
src/link.zig+1
......@@ -63,6 +63,7 @@ pub const Options = struct {
6363 system_linker_hack: bool,
6464 link_libc: bool,
6565 link_libcpp: bool,
66 link_libunwind: bool,
6667 function_sections: bool,
6768 eh_frame_hdr: bool,
6869 emit_relocs: bool,
src/link/Elf.zig+6-13
......@@ -1645,6 +1645,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
16451645 try argv.append(comp.libcxx_static_lib.?.full_object_path);
16461646 }
16471647
1648 // libunwind dep
1649 if (self.base.options.link_libunwind) {
1650 try argv.append(comp.libunwind_static_lib.?.full_object_path);
1651 }
1652
16481653 // libc dep
16491654 if (self.base.options.link_libc) {
16501655 if (self.base.options.libc_installation != null) {
......@@ -1653,18 +1658,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
16531658 }
16541659 const needs_grouping = self.base.options.link_mode == .Static;
16551660 if (needs_grouping) try argv.append("--start-group");
1656 // This matches the order of glibc.libs
1657 try argv.appendSlice(&[_][]const u8{
1658 "-lm",
1659 "-lpthread",
1660 "-lc",
1661 "-ldl",
1662 "-lrt",
1663 "-lutil",
1664 });
1661 try argv.appendSlice(target_util.libcFullLinkFlags(target));
16651662 if (needs_grouping) try argv.append("--end-group");
16661663 } else if (target.isGnuLibC()) {
1667 try argv.append(comp.libunwind_static_lib.?.full_object_path);
16681664 for (glibc.libs) |lib| {
16691665 const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
16701666 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
......@@ -1673,13 +1669,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
16731669 }
16741670 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
16751671 } else if (target.isMusl()) {
1676 try argv.append(comp.libunwind_static_lib.?.full_object_path);
16771672 try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
16781673 .Static => "libc.a",
16791674 .Dynamic => "libc.so",
16801675 }));
1681 } else if (self.base.options.link_libcpp) {
1682 try argv.append(comp.libunwind_static_lib.?.full_object_path);
16831676 } else {
16841677 unreachable; // Compiler was supposed to emit an error for not being able to provide libc.
16851678 }
src/link/MachO.zig+56-21
......@@ -363,18 +363,30 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
363363 self.base.file = file;
364364
365365 // Create dSYM bundle.
366 const d_sym_path = try fmt.allocPrint(allocator, "{s}.dSYM/Contents/Resources/DWARF/", .{sub_path});
367 defer allocator.free(d_sym_path);
368 var d_sym_bundle = try options.emit.?.directory.handle.makeOpenPath(d_sym_path, .{});
369 defer d_sym_bundle.close();
370 const d_sym_file = try d_sym_bundle.createFile(sub_path, .{
371 .truncate = false,
372 .read = true,
373 });
374 self.d_sym = .{
375 .base = self,
376 .file = d_sym_file,
377 };
366 if (!options.strip and options.module != null) {
367 const dir = options.module.?.zig_cache_artifact_directory;
368 log.debug("creating {s}.dSYM bundle in {s}", .{ sub_path, dir.path });
369
370 const d_sym_path = try fmt.allocPrint(
371 allocator,
372 "{s}.dSYM" ++ fs.path.sep_str ++ "Contents" ++ fs.path.sep_str ++ "Resources" ++ fs.path.sep_str ++ "DWARF",
373 .{sub_path},
374 );
375 defer allocator.free(d_sym_path);
376
377 var d_sym_bundle = try dir.handle.makeOpenPath(d_sym_path, .{});
378 defer d_sym_bundle.close();
379
380 const d_sym_file = try d_sym_bundle.createFile(sub_path, .{
381 .truncate = false,
382 .read = true,
383 });
384
385 self.d_sym = .{
386 .base = self,
387 .file = d_sym_file,
388 };
389 }
378390
379391 // Index 0 is always a null symbol.
380392 try self.locals.append(allocator, .{
......@@ -1198,7 +1210,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
11981210 const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment);
11991211 if (need_realloc) {
12001212 const vaddr = try self.growTextBlock(&decl.link.macho, code.len, required_alignment);
1201 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr });
1213
1214 log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr });
1215
12021216 if (vaddr != symbol.n_value) {
12031217 log.debug(" (writing new offset table entry)", .{});
12041218 self.offset_table.items[decl.link.macho.offset_table_index] = .{
......@@ -1208,6 +1222,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
12081222 };
12091223 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
12101224 }
1225
1226 symbol.n_value = vaddr;
12111227 } else if (code.len < decl.link.macho.size) {
12121228 self.shrinkTextBlock(&decl.link.macho, code.len);
12131229 }
......@@ -1224,7 +1240,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
12241240 const decl_name = mem.spanZ(decl.name);
12251241 const name_str_index = try self.makeString(decl_name);
12261242 const addr = try self.allocateTextBlock(&decl.link.macho, code.len, required_alignment);
1243
12271244 log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, addr });
1245
12281246 errdefer self.freeTextBlock(&decl.link.macho);
12291247
12301248 symbol.* = .{
......@@ -1368,15 +1386,32 @@ pub fn updateDeclExports(
13681386 continue;
13691387 }
13701388 }
1371 const n_desc = switch (exp.options.linkage) {
1372 .Internal => macho.REFERENCE_FLAG_PRIVATE_DEFINED,
1373 .Strong => blk: {
1374 if (mem.eql(u8, exp.options.name, "_start")) {
1389
1390 var n_type: u8 = macho.N_SECT | macho.N_EXT;
1391 var n_desc: u16 = 0;
1392
1393 switch (exp.options.linkage) {
1394 .Internal => {
1395 // Symbol should be hidden, or in MachO lingo, private extern.
1396 // We should also mark the symbol as Weak: n_desc == N_WEAK_DEF.
1397 // TODO work out when to add N_WEAK_REF.
1398 n_type |= macho.N_PEXT;
1399 n_desc |= macho.N_WEAK_DEF;
1400 },
1401 .Strong => {
1402 // Check if the export is _main, and note if os.
1403 // Otherwise, don't do anything since we already have all the flags
1404 // set that we need for global (strong) linkage.
1405 // n_type == N_SECT | N_EXT
1406 if (mem.eql(u8, exp.options.name, "_main")) {
13751407 self.entry_addr = decl_sym.n_value;
13761408 }
1377 break :blk macho.REFERENCE_FLAG_DEFINED;
13781409 },
1379 .Weak => macho.N_WEAK_REF,
1410 .Weak => {
1411 // Weak linkage is specified as part of n_desc field.
1412 // Symbol's n_type is like for a symbol with strong linkage.
1413 n_desc |= macho.N_WEAK_DEF;
1414 },
13801415 .LinkOnce => {
13811416 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
13821417 module.failed_exports.putAssumeCapacityNoClobber(
......@@ -1385,8 +1420,8 @@ pub fn updateDeclExports(
13851420 );
13861421 continue;
13871422 },
1388 };
1389 const n_type = decl_sym.n_type | macho.N_EXT;
1423 }
1424
13901425 if (exp.link.macho.sym_index) |i| {
13911426 const sym = &self.globals.items[i];
13921427 sym.* = .{
src/link/SpirV.zig+49-52
......@@ -16,11 +16,16 @@
1616//! All function declarations without a body (extern functions presumably).
1717//! All regular functions.
1818
19// Because SPIR-V requires re-compilation anyway, and so hot swapping will not work
20// anyway, we simply generate all the code in flushModule. This keeps
21// things considerably simpler.
22
1923const SpirV = @This();
2024
2125const std = @import("std");
2226const Allocator = std.mem.Allocator;
2327const assert = std.debug.assert;
28const log = std.log.scoped(.link);
2429
2530const Module = @import("../Module.zig");
2631const Compilation = @import("../Compilation.zig");
......@@ -30,16 +35,15 @@ const trace = @import("../tracy.zig").trace;
3035const build_options = @import("build_options");
3136const spec = @import("../codegen/spirv/spec.zig");
3237
38// TODO: Should this struct be used at all rather than just a hashmap of aux data for every decl?
3339pub const FnData = struct {
34 id: ?u32 = null,
35 code: std.ArrayListUnmanaged(u32) = .{},
40 // We're going to fill these in flushModule, and we're going to fill them unconditionally,
41 // so just set it to undefined.
42 id: u32 = undefined
3643};
3744
3845base: link.File,
3946
40/// TODO: Does this file need to support multiple independent modules?
41spirv_module: codegen.SPIRVModule,
42
4347/// This linker backend does not try to incrementally link output SPIR-V code.
4448/// Instead, it tracks all declarations in this table, and iterates over it
4549/// in the flush function.
......@@ -54,7 +58,6 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*SpirV {
5458 .file = null,
5559 .allocator = gpa,
5660 },
57 .spirv_module = codegen.SPIRVModule.init(gpa),
5861 };
5962
6063 // TODO: Figure out where to put all of these
......@@ -94,29 +97,11 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
9497
9598pub fn deinit(self: *SpirV) void {
9699 self.decl_table.deinit(self.base.allocator);
97 self.spirv_module.deinit();
98100}
99101
100102pub fn updateDecl(self: *SpirV, module: *Module, decl: *Module.Decl) !void {
101 const tracy = trace(@src());
102 defer tracy.end();
103
104103 // Keep track of all decls so we can iterate over them on flush().
105104 _ = try self.decl_table.getOrPut(self.base.allocator, decl);
106
107 const fn_data = &decl.fn_link.spirv;
108 if (fn_data.id == null) {
109 fn_data.id = self.spirv_module.allocId();
110 }
111
112 var managed_code = fn_data.code.toManaged(self.base.allocator);
113 managed_code.items.len = 0;
114
115 try self.spirv_module.genDecl(fn_data.id.?, &managed_code, decl);
116 fn_data.code = managed_code.toUnmanaged();
117
118 // Free excess allocated memory for this Decl.
119 fn_data.code.shrinkAndFree(self.base.allocator, fn_data.code.items.len);
120105}
121106
122107pub fn updateDeclExports(
......@@ -128,10 +113,6 @@ pub fn updateDeclExports(
128113
129114pub fn freeDecl(self: *SpirV, decl: *Module.Decl) void {
130115 self.decl_table.removeAssertDiscard(decl);
131 var fn_data = decl.fn_link.spirv;
132 fn_data.code.deinit(self.base.allocator);
133 if (fn_data.id) |id| self.spirv_module.freeId(id);
134 decl.fn_link.spirv = undefined;
135116}
136117
137118pub fn flush(self: *SpirV, comp: *Compilation) !void {
......@@ -149,51 +130,67 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void {
149130 const module = self.base.options.module.?;
150131 const target = comp.getTarget();
151132
133 var spirv_module = codegen.SPIRVModule.init(target, self.base.allocator);
134 defer spirv_module.deinit();
135
136 // Allocate an ID for every declaration before generating code,
137 // so that we can access them before processing them.
138 // TODO: We're allocating an ID unconditionally now, are there
139 // declarations which don't generate a result?
140 // TODO: fn_link is used here, but thats probably not the right field. It will work anyway though.
141 {
142 for (self.decl_table.items()) |entry| {
143 const decl = entry.key;
144 if (!decl.has_tv) continue;
145
146 decl.fn_link.spirv.id = spirv_module.allocResultId();
147 log.debug("Allocating id {} to '{s}'", .{ decl.fn_link.spirv.id, std.mem.spanZ(decl.name) });
148 }
149 }
150
151 // Now, actually generate the code for all declarations.
152 {
153 for (self.decl_table.items()) |entry| {
154 const decl = entry.key;
155 if (!decl.has_tv) continue;
156
157 try spirv_module.gen(decl);
158 }
159 }
160
152161 var binary = std.ArrayList(u32).init(self.base.allocator);
153162 defer binary.deinit();
154163
155 // Note: The order of adding sections to the final binary
156 // follows the SPIR-V logical module format!
157
158164 try binary.appendSlice(&[_]u32{
159165 spec.magic_number,
160166 (spec.version.major << 16) | (spec.version.minor << 8),
161167 0, // TODO: Register Zig compiler magic number.
162 self.spirv_module.idBound(),
168 spirv_module.resultIdBound(), // ID bound.
163169 0, // Schema (currently reserved for future use in the SPIR-V spec).
164170 });
165171
166172 try writeCapabilities(&binary, target);
167173 try writeMemoryModel(&binary, target);
168174
169 // Collect list of buffers to write.
170 // SPIR-V files support both little and big endian words. The actual format is
171 // disambiguated by the magic number, and so theoretically we don't need to worry
172 // about endian-ness when writing the final binary.
173 var all_buffers = std.ArrayList(std.os.iovec_const).init(self.base.allocator);
174 defer all_buffers.deinit();
175
176 // Pre-allocate enough for the binary info + all functions
177 try all_buffers.ensureCapacity(self.decl_table.count() + 1);
178
179 all_buffers.appendAssumeCapacity(wordsToIovConst(binary.items));
175 // Note: The order of adding sections to the final binary
176 // follows the SPIR-V logical module format!
177 var all_buffers = [_]std.os.iovec_const{
178 wordsToIovConst(binary.items),
179 wordsToIovConst(spirv_module.types_and_globals.items),
180 wordsToIovConst(spirv_module.fn_decls.items),
181 };
180182
181 for (self.decl_table.items()) |entry| {
182 const decl = entry.key;
183 if (!decl.has_tv) continue;
184 const fn_data = &decl.fn_link.spirv;
185 all_buffers.appendAssumeCapacity(wordsToIovConst(fn_data.code.items));
186 }
183 const file = self.base.file.?;
184 const bytes = std.mem.sliceAsBytes(binary.items);
187185
188186 var file_size: u64 = 0;
189 for (all_buffers.items) |iov| {
187 for (all_buffers) |iov| {
190188 file_size += iov.iov_len;
191189 }
192190
193 const file = self.base.file.?;
194191 try file.seekTo(0);
195192 try file.setEndPos(file_size);
196 try file.pwritevAll(all_buffers.items, 0);
193 try file.pwritevAll(&all_buffers, 0);
197194}
198195
199196fn writeCapabilities(binary: *std.ArrayList(u32), target: std.Target) !void {
src/main.zig+7
......@@ -544,6 +544,7 @@ fn buildOutputType(
544544 var ensure_libcpp_on_non_freestanding = false;
545545 var link_libc = false;
546546 var link_libcpp = false;
547 var link_libunwind = false;
547548 var want_native_include_dirs = false;
548549 var enable_cache: ?bool = null;
549550 var want_pic: ?bool = null;
......@@ -1556,6 +1557,11 @@ fn buildOutputType(
15561557 _ = system_libs.orderedRemove(i);
15571558 continue;
15581559 }
1560 if (mem.eql(u8, lib_name, "unwind")) {
1561 link_libunwind = true;
1562 _ = system_libs.orderedRemove(i);
1563 continue;
1564 }
15591565 if (std.fs.path.isAbsolute(lib_name)) {
15601566 fatal("cannot use absolute path as a system library: {s}", .{lib_name});
15611567 }
......@@ -1871,6 +1877,7 @@ fn buildOutputType(
18711877 .system_libs = system_libs.items,
18721878 .link_libc = link_libc,
18731879 .link_libcpp = link_libcpp,
1880 .link_libunwind = link_libunwind,
18741881 .want_pic = want_pic,
18751882 .want_pie = want_pie,
18761883 .want_lto = want_lto,
src/register_manager.zig+219-156
......@@ -7,6 +7,9 @@ const ir = @import("ir.zig");
77const Type = @import("type.zig").Type;
88const Module = @import("Module.zig");
99const LazySrcLoc = Module.LazySrcLoc;
10const expect = std.testing.expect;
11const expectEqual = std.testing.expectEqual;
12const expectEqualSlices = std.testing.expectEqualSlices;
1013
1114const log = std.log.scoped(.register_manager);
1215
......@@ -66,77 +69,14 @@ pub fn RegisterManager(
6669 return self.allocated_registers & @as(FreeRegInt, 1) << shift != 0;
6770 }
6871
69 /// Returns `null` if all registers are allocated.
72 /// Allocates a specified number of registers, optionally
73 /// tracking them. Returns `null` if not enough registers are
74 /// free.
7075 pub fn tryAllocRegs(
7176 self: *Self,
7277 comptime count: comptime_int,
73 insts: [count]*ir.Inst,
74 exceptions: []Register,
75 ) ?[count]Register {
76 if (self.tryAllocRegsWithoutTracking(count, exceptions)) |regs| {
77 for (regs) |reg, i| {
78 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
79 self.registers[index] = insts[i];
80 self.markRegUsed(reg);
81 }
82
83 return regs;
84 } else {
85 return null;
86 }
87 }
88
89 /// Returns `null` if all registers are allocated.
90 pub fn tryAllocReg(self: *Self, inst: *ir.Inst, exceptions: []Register) ?Register {
91 return if (tryAllocRegs(self, 1, .{inst}, exceptions)) |regs| regs[0] else null;
92 }
93
94 pub fn allocRegs(
95 self: *Self,
96 comptime count: comptime_int,
97 insts: [count]*ir.Inst,
98 exceptions: []Register,
99 ) ![count]Register {
100 comptime assert(count > 0 and count <= callee_preserved_regs.len);
101 assert(count + exceptions.len <= callee_preserved_regs.len);
102
103 return self.tryAllocRegs(count, insts, exceptions) orelse blk: {
104 // We'll take over the first count registers. Spill
105 // the instructions that were previously there to a
106 // stack allocations.
107 var regs: [count]Register = undefined;
108 var i: usize = 0;
109 for (callee_preserved_regs) |reg| {
110 if (i >= count) break;
111 if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
112 regs[i] = reg;
113
114 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
115 if (self.isRegFree(reg)) {
116 self.markRegUsed(reg);
117 } else {
118 const spilled_inst = self.registers[index].?;
119 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
120 }
121 self.registers[index] = insts[i];
122
123 i += 1;
124 }
125
126 break :blk regs;
127 };
128 }
129
130 pub fn allocReg(self: *Self, inst: *ir.Inst, exceptions: []Register) !Register {
131 return (try self.allocRegs(1, .{inst}, exceptions))[0];
132 }
133
134 /// Does not track the registers.
135 /// Returns `null` if not enough registers are free.
136 pub fn tryAllocRegsWithoutTracking(
137 self: *Self,
138 comptime count: comptime_int,
139 exceptions: []Register,
78 insts: [count]?*ir.Inst,
79 exceptions: []const Register,
14080 ) ?[count]Register {
14181 comptime if (callee_preserved_regs.len == 0) return null;
14282 comptime assert(count > 0 and count <= callee_preserved_regs.len);
......@@ -156,18 +96,40 @@ pub fn RegisterManager(
15696 }
15797 }
15898
159 return if (i < count) null else regs;
99 if (i == count) {
100 for (regs) |reg, j| {
101 if (insts[j]) |inst| {
102 // Track the register
103 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
104 self.registers[index] = inst;
105 self.markRegUsed(reg);
106 }
107 }
108
109 return regs;
110 } else return null;
160111 }
161112
162 /// Does not track the register.
163 /// Returns `null` if all registers are allocated.
164 pub fn tryAllocRegWithoutTracking(self: *Self, exceptions: []Register) ?Register {
165 return if (self.tryAllocRegsWithoutTracking(1, exceptions)) |regs| regs[0] else null;
113 /// Allocates a register and optionally tracks it with a
114 /// corresponding instruction. Returns `null` if all registers
115 /// are allocated.
116 pub fn tryAllocReg(self: *Self, inst: ?*ir.Inst, exceptions: []const Register) ?Register {
117 return if (tryAllocRegs(self, 1, .{inst}, exceptions)) |regs| regs[0] else null;
166118 }
167119
168 /// Does not track the registers
169 pub fn allocRegsWithoutTracking(self: *Self, comptime count: comptime_int, exceptions: []Register) ![count]Register {
170 return self.tryAllocRegsWithoutTracking(count, exceptions) orelse blk: {
120 /// Allocates a specified number of registers, optionally
121 /// tracking them. Asserts that count + exceptions.len is not
122 /// larger than the total number of registers available.
123 pub fn allocRegs(
124 self: *Self,
125 comptime count: comptime_int,
126 insts: [count]?*ir.Inst,
127 exceptions: []const Register,
128 ) ![count]Register {
129 comptime assert(count > 0 and count <= callee_preserved_regs.len);
130 assert(count + exceptions.len <= callee_preserved_regs.len);
131
132 return self.tryAllocRegs(count, insts, exceptions) orelse blk: {
171133 // We'll take over the first count registers. Spill
172134 // the instructions that were previously there to a
173135 // stack allocations.
......@@ -179,11 +141,22 @@ pub fn RegisterManager(
179141 regs[i] = reg;
180142
181143 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
182 if (!self.isRegFree(reg)) {
183 const spilled_inst = self.registers[index].?;
184 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
185 self.registers[index] = null;
186 self.markRegFree(reg);
144 if (insts[i]) |inst| {
145 // Track the register
146 if (self.isRegFree(reg)) {
147 self.markRegUsed(reg);
148 } else {
149 const spilled_inst = self.registers[index].?;
150 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
151 }
152 self.registers[index] = inst;
153 } else {
154 // Don't track the register
155 if (!self.isRegFree(reg)) {
156 const spilled_inst = self.registers[index].?;
157 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
158 self.freeReg(reg);
159 }
187160 }
188161
189162 i += 1;
......@@ -193,39 +166,36 @@ pub fn RegisterManager(
193166 };
194167 }
195168
196 /// Does not track the register.
197 pub fn allocRegWithoutTracking(self: *Self, exceptions: []Register) !Register {
198 return (try self.allocRegsWithoutTracking(1, exceptions))[0];
199 }
200
201 /// Allocates the specified register with the specified
202 /// instruction. Spills the register if it is currently
203 /// allocated.
204 pub fn getReg(self: *Self, reg: Register, inst: *ir.Inst) !void {
205 const index = reg.allocIndex() orelse return;
206
207 if (!self.isRegFree(reg)) {
208 // Move the instruction that was previously there to a
209 // stack allocation.
210 const spilled_inst = self.registers[index].?;
211 self.registers[index] = inst;
212 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
213 } else {
214 self.getRegAssumeFree(reg, inst);
215 }
169 /// Allocates a register and optionally tracks it with a
170 /// corresponding instruction.
171 pub fn allocReg(self: *Self, inst: ?*ir.Inst, exceptions: []const Register) !Register {
172 return (try self.allocRegs(1, .{inst}, exceptions))[0];
216173 }
217174
218 /// Spills the register if it is currently allocated.
219 /// Does not track the register.
220 pub fn getRegWithoutTracking(self: *Self, reg: Register) !void {
175 /// Spills the register if it is currently allocated. If a
176 /// corresponding instruction is passed, will also track this
177 /// register.
178 pub fn getReg(self: *Self, reg: Register, inst: ?*ir.Inst) !void {
221179 const index = reg.allocIndex() orelse return;
222180
223 if (!self.isRegFree(reg)) {
224 // Move the instruction that was previously there to a
225 // stack allocation.
226 const spilled_inst = self.registers[index].?;
227 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
228 self.markRegFree(reg);
181 if (inst) |tracked_inst|
182 if (!self.isRegFree(reg)) {
183 // Move the instruction that was previously there to a
184 // stack allocation.
185 const spilled_inst = self.registers[index].?;
186 self.registers[index] = tracked_inst;
187 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
188 } else {
189 self.getRegAssumeFree(reg, tracked_inst);
190 }
191 else {
192 if (!self.isRegFree(reg)) {
193 // Move the instruction that was previously there to a
194 // stack allocation.
195 const spilled_inst = self.registers[index].?;
196 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
197 self.freeReg(reg);
198 }
229199 }
230200 }
231201
......@@ -250,42 +220,63 @@ pub fn RegisterManager(
250220 };
251221}
252222
253const MockRegister = enum(u2) {
223const MockRegister1 = enum(u2) {
254224 r0,
255225 r1,
256226 r2,
257227 r3,
258228
259 pub fn allocIndex(self: MockRegister) ?u2 {
260 inline for (mock_callee_preserved_regs) |cpreg, i| {
229 pub fn allocIndex(self: MockRegister1) ?u2 {
230 inline for (callee_preserved_regs) |cpreg, i| {
261231 if (self == cpreg) return i;
262232 }
263233 return null;
264234 }
265};
266
267const mock_callee_preserved_regs = [_]MockRegister{ .r2, .r3 };
268235
269const MockFunction = struct {
270 allocator: *Allocator,
271 register_manager: RegisterManager(Self, MockRegister, &mock_callee_preserved_regs) = .{},
272 spilled: std.ArrayListUnmanaged(MockRegister) = .{},
236 const callee_preserved_regs = [_]MockRegister1{ .r2, .r3 };
237};
273238
274 const Self = @This();
239const MockRegister2 = enum(u2) {
240 r0,
241 r1,
242 r2,
243 r3,
275244
276 pub fn deinit(self: *Self) void {
277 self.spilled.deinit(self.allocator);
245 pub fn allocIndex(self: MockRegister2) ?u2 {
246 inline for (callee_preserved_regs) |cpreg, i| {
247 if (self == cpreg) return i;
248 }
249 return null;
278250 }
279251
280 pub fn spillInstruction(self: *Self, src: LazySrcLoc, reg: MockRegister, inst: *ir.Inst) !void {
281 try self.spilled.append(self.allocator, reg);
282 }
252 const callee_preserved_regs = [_]MockRegister2{ .r0, .r1, .r2, .r3 };
283253};
284254
285test "tryAllocReg: no spilling" {
255fn MockFunction(comptime Register: type) type {
256 return struct {
257 allocator: *Allocator,
258 register_manager: RegisterManager(Self, Register, &Register.callee_preserved_regs) = .{},
259 spilled: std.ArrayListUnmanaged(Register) = .{},
260
261 const Self = @This();
262
263 pub fn deinit(self: *Self) void {
264 self.spilled.deinit(self.allocator);
265 }
266
267 pub fn spillInstruction(self: *Self, src: LazySrcLoc, reg: Register, inst: *ir.Inst) !void {
268 try self.spilled.append(self.allocator, reg);
269 }
270 };
271}
272
273const MockFunction1 = MockFunction(MockRegister1);
274const MockFunction2 = MockFunction(MockRegister2);
275
276test "default state" {
286277 const allocator = std.testing.allocator;
287278
288 var function = MockFunction{
279 var function = MockFunction1{
289280 .allocator = allocator,
290281 };
291282 defer function.deinit();
......@@ -296,27 +287,48 @@ test "tryAllocReg: no spilling" {
296287 .src = .unneeded,
297288 };
298289
299 try std.testing.expect(!function.register_manager.isRegAllocated(.r2));
300 try std.testing.expect(!function.register_manager.isRegAllocated(.r3));
290 try expect(!function.register_manager.isRegAllocated(.r2));
291 try expect(!function.register_manager.isRegAllocated(.r3));
292 try expect(function.register_manager.isRegFree(.r2));
293 try expect(function.register_manager.isRegFree(.r3));
294}
295
296test "tryAllocReg: no spilling" {
297 const allocator = std.testing.allocator;
298
299 var function = MockFunction1{
300 .allocator = allocator,
301 };
302 defer function.deinit();
303
304 var mock_instruction = ir.Inst{
305 .tag = .breakpoint,
306 .ty = Type.initTag(.void),
307 .src = .unneeded,
308 };
301309
302 try std.testing.expectEqual(@as(?MockRegister, .r2), function.register_manager.tryAllocReg(&mock_instruction, &.{}));
303 try std.testing.expectEqual(@as(?MockRegister, .r3), function.register_manager.tryAllocReg(&mock_instruction, &.{}));
304 try std.testing.expectEqual(@as(?MockRegister, null), function.register_manager.tryAllocReg(&mock_instruction, &.{}));
310 try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(&mock_instruction, &.{}));
311 try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(&mock_instruction, &.{}));
312 try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(&mock_instruction, &.{}));
305313
306 try std.testing.expect(function.register_manager.isRegAllocated(.r2));
307 try std.testing.expect(function.register_manager.isRegAllocated(.r3));
314 try expect(function.register_manager.isRegAllocated(.r2));
315 try expect(function.register_manager.isRegAllocated(.r3));
316 try expect(!function.register_manager.isRegFree(.r2));
317 try expect(!function.register_manager.isRegFree(.r3));
308318
309319 function.register_manager.freeReg(.r2);
310320 function.register_manager.freeReg(.r3);
311321
312 try std.testing.expect(function.register_manager.isRegAllocated(.r2));
313 try std.testing.expect(function.register_manager.isRegAllocated(.r3));
322 try expect(function.register_manager.isRegAllocated(.r2));
323 try expect(function.register_manager.isRegAllocated(.r3));
324 try expect(function.register_manager.isRegFree(.r2));
325 try expect(function.register_manager.isRegFree(.r3));
314326}
315327
316328test "allocReg: spilling" {
317329 const allocator = std.testing.allocator;
318330
319 var function = MockFunction{
331 var function = MockFunction1{
320332 .allocator = allocator,
321333 };
322334 defer function.deinit();
......@@ -327,26 +339,28 @@ test "allocReg: spilling" {
327339 .src = .unneeded,
328340 };
329341
330 try std.testing.expect(!function.register_manager.isRegAllocated(.r2));
331 try std.testing.expect(!function.register_manager.isRegAllocated(.r3));
332
333 try std.testing.expectEqual(@as(?MockRegister, .r2), try function.register_manager.allocReg(&mock_instruction, &.{}));
334 try std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction, &.{}));
342 try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(&mock_instruction, &.{}));
343 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(&mock_instruction, &.{}));
335344
336345 // Spill a register
337 try std.testing.expectEqual(@as(?MockRegister, .r2), try function.register_manager.allocReg(&mock_instruction, &.{}));
338 try std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items);
346 try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(&mock_instruction, &.{}));
347 try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);
339348
340349 // No spilling necessary
341350 function.register_manager.freeReg(.r3);
342 try std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction, &.{}));
343 try std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items);
351 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(&mock_instruction, &.{}));
352 try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);
353
354 // Exceptions
355 function.register_manager.freeReg(.r2);
356 function.register_manager.freeReg(.r3);
357 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(&mock_instruction, &.{.r2}));
344358}
345359
346test "getReg" {
360test "tryAllocRegs" {
347361 const allocator = std.testing.allocator;
348362
349 var function = MockFunction{
363 var function = MockFunction2{
350364 .allocator = allocator,
351365 };
352366 defer function.deinit();
......@@ -357,18 +371,67 @@ test "getReg" {
357371 .src = .unneeded,
358372 };
359373
360 try std.testing.expect(!function.register_manager.isRegAllocated(.r2));
361 try std.testing.expect(!function.register_manager.isRegAllocated(.r3));
374 try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{}).?);
375
376 // Exceptions
377 function.register_manager.freeReg(.r0);
378 function.register_manager.freeReg(.r1);
379 function.register_manager.freeReg(.r2);
380 try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{.r1}).?);
381}
382
383test "allocRegs" {
384 const allocator = std.testing.allocator;
385
386 var function = MockFunction2{
387 .allocator = allocator,
388 };
389 defer function.deinit();
390
391 var mock_instruction = ir.Inst{
392 .tag = .breakpoint,
393 .ty = Type.initTag(.void),
394 .src = .unneeded,
395 };
396
397 try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, try function.register_manager.allocRegs(3, .{
398 &mock_instruction,
399 &mock_instruction,
400 &mock_instruction,
401 }, &.{}));
402
403 // Exceptions
404 try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, try function.register_manager.allocRegs(3, .{ null, null, null }, &.{.r1}));
405 try expectEqualSlices(MockRegister2, &[_]MockRegister2{ .r0, .r2 }, function.spilled.items);
406}
407
408test "getReg" {
409 const allocator = std.testing.allocator;
410
411 var function = MockFunction1{
412 .allocator = allocator,
413 };
414 defer function.deinit();
415
416 var mock_instruction = ir.Inst{
417 .tag = .breakpoint,
418 .ty = Type.initTag(.void),
419 .src = .unneeded,
420 };
362421
363422 try function.register_manager.getReg(.r3, &mock_instruction);
364423
365 try std.testing.expect(!function.register_manager.isRegAllocated(.r2));
366 try std.testing.expect(function.register_manager.isRegAllocated(.r3));
424 try expect(!function.register_manager.isRegAllocated(.r2));
425 try expect(function.register_manager.isRegAllocated(.r3));
426 try expect(function.register_manager.isRegFree(.r2));
427 try expect(!function.register_manager.isRegFree(.r3));
367428
368429 // Spill r3
369430 try function.register_manager.getReg(.r3, &mock_instruction);
370431
371 try std.testing.expect(!function.register_manager.isRegAllocated(.r2));
372 try std.testing.expect(function.register_manager.isRegAllocated(.r3));
373 try std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r3}, function.spilled.items);
432 try expect(!function.register_manager.isRegAllocated(.r2));
433 try expect(function.register_manager.isRegAllocated(.r3));
434 try expect(function.register_manager.isRegFree(.r2));
435 try expect(!function.register_manager.isRegFree(.r3));
436 try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r3}, function.spilled.items);
374437}
src/stage1/codegen.cpp+3-3
......@@ -5485,8 +5485,8 @@ static enum ZigLLVM_AtomicRMWBinOp to_ZigLLVMAtomicRMWBinOp(AtomicRmwOp op, bool
54855485}
54865486
54875487static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction) {
5488 // If the operand type of an atomic operation is not a power of two sized
5489 // we need to widen it before using it and then truncate the result.
5488 // If the operand type of an atomic operation is not byte sized we need to
5489 // widen it before using it and then truncate the result.
54905490
54915491 ir_assert(instruction->value->type->id == ZigTypeIdPointer, instruction);
54925492 ZigType *operand_type = instruction->value->type->data.pointer.child_type;
......@@ -5498,7 +5498,7 @@ static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction) {
54985498 bool is_signed = operand_type->data.integral.is_signed;
54995499
55005500 ir_assert(bit_count != 0, instruction);
5501 if (bit_count == 1 || !is_power_of_2(bit_count)) {
5501 if (!is_power_of_2(bit_count) || bit_count % 8) {
55025502 return get_llvm_type(g, get_int_type(g, is_signed, operand_type->abi_size * 8));
55035503 } else {
55045504 return nullptr;
src/target.zig+27
......@@ -374,3 +374,30 @@ pub fn hasRedZone(target: std.Target) bool {
374374 else => false,
375375 };
376376}
377
378pub fn libcFullLinkFlags(target: std.Target) []const []const u8 {
379 // The linking order of these is significant and should match the order other
380 // c compilers such as gcc or clang use.
381 return switch (target.os.tag) {
382 .netbsd, .openbsd => &[_][]const u8{
383 "-lm",
384 "-lpthread",
385 "-lc",
386 "-lutil",
387 },
388 else => &[_][]const u8{
389 "-lm",
390 "-lpthread",
391 "-lc",
392 "-ldl",
393 "-lrt",
394 "-lutil",
395 },
396 };
397}
398
399pub fn clangMightShellOutForAssembly(target: std.Target) bool {
400 // Clang defaults to using the system assembler over the internal one
401 // when targeting a non-BSD OS.
402 return target.cpu.arch.isSPARC();
403}
src/test.zig+11
......@@ -8,6 +8,7 @@ const build_options = @import("build_options");
88const enable_qemu: bool = build_options.enable_qemu;
99const enable_wine: bool = build_options.enable_wine;
1010const enable_wasmtime: bool = build_options.enable_wasmtime;
11const enable_darling: bool = build_options.enable_darling;
1112const glibc_multi_install_dir: ?[]const u8 = build_options.glibc_multi_install_dir;
1213const ThreadPool = @import("ThreadPool.zig");
1314const CrossTarget = std.zig.CrossTarget;
......@@ -901,6 +902,16 @@ pub const TestContext = struct {
901902 } else {
902903 return; // wasmtime not available; pass test.
903904 },
905
906 .darling => |darling_bin_name| if (enable_darling) {
907 try argv.append(darling_bin_name);
908 // Since we use relative to cwd here, we invoke darling with
909 // "shell" subcommand.
910 try argv.append("shell");
911 try argv.append(exe_path);
912 } else {
913 return; // Darling not available; pass test.
914 },
904915 }
905916
906917 try comp.makeBinFileExecutable();
src/translate_c.zig+18
......@@ -480,6 +480,9 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {
480480 .Empty => {
481481 // Do nothing
482482 },
483 .FileScopeAsm => {
484 try transFileScopeAsm(c, &c.global_scope.base, @ptrCast(*const clang.FileScopeAsmDecl, decl));
485 },
483486 else => {
484487 const decl_name = try c.str(decl.getDeclKindName());
485488 try warn(c, &c.global_scope.base, decl.getLocation(), "ignoring {s} declaration", .{decl_name});
......@@ -487,6 +490,21 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {
487490 }
488491}
489492
493fn transFileScopeAsm(c: *Context, scope: *Scope, file_scope_asm: *const clang.FileScopeAsmDecl) Error!void {
494 const asm_string = file_scope_asm.getAsmString();
495 var len: usize = undefined;
496 const bytes_ptr = asm_string.getString_bytes_begin_size(&len);
497
498 const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])});
499 const str_node = try Tag.string_literal.create(c.arena, str);
500
501 const asm_node = try Tag.asm_simple.create(c.arena, str_node);
502 const block = try Tag.block_single.create(c.arena, asm_node);
503 const comptime_node = try Tag.@"comptime".create(c.arena, block);
504
505 try scope.appendNode(comptime_node);
506}
507
490508fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
491509 const fn_name = try c.str(@ptrCast(*const clang.NamedDecl, fn_decl).getName_bytes_begin());
492510 if (c.global_scope.sym_table.contains(fn_name))
src/translate_c/ast.zig+17
......@@ -161,6 +161,8 @@ pub const Node = extern union {
161161 /// @shuffle(type, a, b, mask)
162162 shuffle,
163163
164 asm_simple,
165
164166 negate,
165167 negate_wrap,
166168 bit_not,
......@@ -245,6 +247,7 @@ pub const Node = extern union {
245247 .std_mem_zeroes,
246248 .@"return",
247249 .@"comptime",
250 .asm_simple,
248251 .discard,
249252 .std_math_Log2Int,
250253 .negate,
......@@ -1017,6 +1020,19 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
10171020 },
10181021 });
10191022 },
1023 .asm_simple => {
1024 const payload = node.castTag(.asm_simple).?.data;
1025 const asm_token = try c.addToken(.keyword_asm, "asm");
1026 _ = try c.addToken(.l_paren, "(");
1027 return c.addNode(.{
1028 .tag = .asm_simple,
1029 .main_token = asm_token,
1030 .data = .{
1031 .lhs = try renderNode(c, payload),
1032 .rhs = try c.addToken(.r_paren, ")"),
1033 },
1034 });
1035 },
10201036 .type => {
10211037 const payload = node.castTag(.type).?.data;
10221038 return c.addNode(.{
......@@ -2257,6 +2273,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
22572273 .@"continue",
22582274 .@"return",
22592275 .@"comptime",
2276 .asm_simple,
22602277 .usingnamespace_builtins,
22612278 .while_true,
22622279 .if_not_break,
src/zig_clang.cpp+5
......@@ -1820,6 +1820,11 @@ const ZigClangEnumDecl *ZigClangEnumDecl_getDefinition(const ZigClangEnumDecl *z
18201820 return reinterpret_cast<const ZigClangEnumDecl *>(definition);
18211821}
18221822
1823const ZigClangStringLiteral *ZigClangFileScopeAsmDecl_getAsmString(const ZigClangFileScopeAsmDecl *self) {
1824 const clang::StringLiteral *result = reinterpret_cast<const clang::FileScopeAsmDecl*>(self)->getAsmString();
1825 return reinterpret_cast<const ZigClangStringLiteral *>(result);
1826}
1827
18231828bool ZigClangRecordDecl_isUnion(const ZigClangRecordDecl *record_decl) {
18241829 return reinterpret_cast<const clang::RecordDecl*>(record_decl)->isUnion();
18251830}
src/zig_clang.h+3
......@@ -124,6 +124,7 @@ struct ZigClangEnumType;
124124struct ZigClangExpr;
125125struct ZigClangFieldDecl;
126126struct ZigClangFileID;
127struct ZigClangFileScopeAsmDecl;
127128struct ZigClangFloatingLiteral;
128129struct ZigClangForStmt;
129130struct ZigClangFullSourceLoc;
......@@ -1000,6 +1001,8 @@ ZIG_EXTERN_C unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangV
10001001ZIG_EXTERN_C unsigned ZigClangFunctionDecl_getAlignedAttribute(const struct ZigClangFunctionDecl *self, const ZigClangASTContext* ctx);
10011002ZIG_EXTERN_C unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx);
10021003
1004ZIG_EXTERN_C const struct ZigClangStringLiteral *ZigClangFileScopeAsmDecl_getAsmString(const struct ZigClangFileScopeAsmDecl *self);
1005
10031006ZIG_EXTERN_C struct ZigClangQualType ZigClangParmVarDecl_getOriginalType(const struct ZigClangParmVarDecl *self);
10041007
10051008ZIG_EXTERN_C bool ZigClangRecordDecl_getPackedAttribute(const struct ZigClangRecordDecl *);
test/behavior/atomics.zig+1-1
......@@ -199,7 +199,7 @@ fn testAtomicRmwInt() !void {
199199
200200test "atomics with different types" {
201201 try testAtomicsWithType(bool, true, false);
202 inline for (.{ u1, i5, u15 }) |T| {
202 inline for (.{ u1, i4, u5, i15, u24 }) |T| {
203203 var x: T = 0;
204204 try testAtomicsWithType(T, 0, 1);
205205 }
test/stage2/darwin.zig+34-7
......@@ -19,7 +19,7 @@ pub fn addCases(ctx: *TestContext) !void {
1919
2020 // Incorrect return type
2121 case.addError(
22 \\pub export fn _start() noreturn {
22 \\pub export fn main() noreturn {
2323 \\}
2424 , &[_][]const u8{
2525 ":2:1: error: expected noreturn, found void",
......@@ -30,7 +30,7 @@ pub fn addCases(ctx: *TestContext) !void {
3030 \\extern "c" fn write(usize, usize, usize) usize;
3131 \\extern "c" fn exit(usize) noreturn;
3232 \\
33 \\pub export fn _start() noreturn {
33 \\pub export fn main() noreturn {
3434 \\ print();
3535 \\
3636 \\ exit(0);
......@@ -45,12 +45,39 @@ pub fn addCases(ctx: *TestContext) !void {
4545 "Hello, World!\n",
4646 );
4747
48 // Now change the message only
48 // Print it 4 times and force growth and realloc.
4949 case.addCompareOutput(
5050 \\extern "c" fn write(usize, usize, usize) usize;
5151 \\extern "c" fn exit(usize) noreturn;
5252 \\
53 \\pub export fn _start() noreturn {
53 \\pub export fn main() noreturn {
54 \\ print();
55 \\ print();
56 \\ print();
57 \\ print();
58 \\
59 \\ exit(0);
60 \\}
61 \\
62 \\fn print() void {
63 \\ const msg = @ptrToInt("Hello, World!\n");
64 \\ const len = 14;
65 \\ _ = write(1, msg, len);
66 \\}
67 ,
68 \\Hello, World!
69 \\Hello, World!
70 \\Hello, World!
71 \\Hello, World!
72 \\
73 );
74
75 // Print it once, and change the message.
76 case.addCompareOutput(
77 \\extern "c" fn write(usize, usize, usize) usize;
78 \\extern "c" fn exit(usize) noreturn;
79 \\
80 \\export fn _main() noreturn {
5481 \\ print();
5582 \\
5683 \\ exit(0);
......@@ -70,7 +97,7 @@ pub fn addCases(ctx: *TestContext) !void {
7097 \\extern "c" fn write(usize, usize, usize) usize;
7198 \\extern "c" fn exit(usize) noreturn;
7299 \\
73 \\pub export fn _start() noreturn {
100 \\pub export fn main() noreturn {
74101 \\ print();
75102 \\ print();
76103 \\
......@@ -96,7 +123,7 @@ pub fn addCases(ctx: *TestContext) !void {
96123 case.addCompareOutput(
97124 \\extern "c" fn exit(usize) noreturn;
98125 \\
99 \\pub export fn _start() noreturn {
126 \\pub export fn main() noreturn {
100127 \\ exit(0);
101128 \\}
102129 ,
......@@ -107,7 +134,7 @@ pub fn addCases(ctx: *TestContext) !void {
107134 \\extern "c" fn exit(usize) noreturn;
108135 \\extern "c" fn write(usize, usize, usize) usize;
109136 \\
110 \\pub export fn _start() noreturn {
137 \\pub export fn main() noreturn {
111138 \\ _ = write(1, @ptrToInt("Hey!\n"), 5);
112139 \\ exit(0);
113140 \\}
test/tests.zig+2
......@@ -503,6 +503,7 @@ pub fn addPkgTests(
503503 is_wine_enabled: bool,
504504 is_qemu_enabled: bool,
505505 is_wasmtime_enabled: bool,
506 is_darling_enabled: bool,
506507 glibc_dir: ?[]const u8,
507508) *build.Step {
508509 const step = b.step(b.fmt("test-{s}", .{name}), desc);
......@@ -564,6 +565,7 @@ pub fn addPkgTests(
564565 these_tests.enable_wine = is_wine_enabled;
565566 these_tests.enable_qemu = is_qemu_enabled;
566567 these_tests.enable_wasmtime = is_wasmtime_enabled;
568 these_tests.enable_darling = is_darling_enabled;
567569 these_tests.glibc_multi_install_dir = glibc_dir;
568570 these_tests.addIncludeDir("test");
569571
test/translate_c.zig+14
......@@ -3499,4 +3499,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
34993499 \\ '\u{1f4af}',
35003500 \\};
35013501 });
3502
3503 cases.add("global assembly",
3504 \\__asm__(".globl func\n\t"
3505 \\ ".type func, @function\n\t"
3506 \\ "func:\n\t"
3507 \\ ".cfi_startproc\n\t"
3508 \\ "movl $42, %eax\n\t"
3509 \\ "ret\n\t"
3510 \\ ".cfi_endproc");
3511 , &[_][]const u8{
3512 \\comptime {
3513 \\ asm (".globl func\n\t.type func, @function\n\tfunc:\n\t.cfi_startproc\n\tmovl $42, %eax\n\tret\n\t.cfi_endproc");
3514 \\}
3515 });
35023516}
tools/gen_spirv_spec.zig+25-122
......@@ -1,96 +1,5 @@
11const std = @import("std");
2const Writer = std.ArrayList(u8).Writer;
3
4//! See https://www.khronos.org/registry/spir-v/specs/unified1/MachineReadableGrammar.html
5//! and the files in https://github.com/KhronosGroup/SPIRV-Headers/blob/master/include/spirv/unified1/
6//! Note: Non-canonical casing in these structs used to match SPIR-V spec json.
7const Registry = union(enum) {
8 core: CoreRegistry,
9 extension: ExtensionRegistry,
10};
11
12const CoreRegistry = struct {
13 copyright: [][]const u8,
14 /// Hexadecimal representation of the magic number
15 magic_number: []const u8,
16 major_version: u32,
17 minor_version: u32,
18 revision: u32,
19 instruction_printing_class: []InstructionPrintingClass,
20 instructions: []Instruction,
21 operand_kinds: []OperandKind,
22};
23
24const ExtensionRegistry = struct {
25 copyright: [][]const u8,
26 version: u32,
27 revision: u32,
28 instructions: []Instruction,
29 operand_kinds: []OperandKind = &[_]OperandKind{},
30};
31
32const InstructionPrintingClass = struct {
33 tag: []const u8,
34 heading: ?[]const u8 = null,
35};
36
37const Instruction = struct {
38 opname: []const u8,
39 class: ?[]const u8 = null, // Note: Only available in the core registry.
40 opcode: u32,
41 operands: []Operand = &[_]Operand{},
42 capabilities: [][]const u8 = &[_][]const u8{},
43 extensions: [][]const u8 = &[_][]const u8{},
44 version: ?[]const u8 = null,
45
46 lastVersion: ?[]const u8 = null,
47};
48
49const Operand = struct {
50 kind: []const u8,
51 /// If this field is 'null', the operand is only expected once.
52 quantifier: ?Quantifier = null,
53 name: []const u8 = "",
54};
55
56const Quantifier = enum {
57 /// zero or once
58 @"?",
59 /// zero or more
60 @"*",
61};
62
63const OperandCategory = enum {
64 BitEnum,
65 ValueEnum,
66 Id,
67 Literal,
68 Composite,
69};
70
71const OperandKind = struct {
72 category: OperandCategory,
73 /// The name
74 kind: []const u8,
75 doc: ?[]const u8 = null,
76 enumerants: ?[]Enumerant = null,
77 bases: ?[]const []const u8 = null,
78};
79
80const Enumerant = struct {
81 enumerant: []const u8,
82 value: union(enum) {
83 bitflag: []const u8, // Hexadecimal representation of the value
84 int: u31,
85 },
86 capabilities: [][]const u8 = &[_][]const u8{},
87 /// Valid for .ValueEnum and .BitEnum
88 extensions: [][]const u8 = &[_][]const u8{},
89 /// `quantifier` will always be `null`.
90 parameters: []Operand = &[_]Operand{},
91 version: ?[]const u8 = null,
92 lastVersion: ?[]const u8 = null,
93};
2const g = @import("spirv/grammar.zig");
943
954pub fn main() !void {
965 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
......@@ -106,24 +15,25 @@ pub fn main() !void {
10615 const spec = try std.fs.cwd().readFileAlloc(allocator, spec_path, std.math.maxInt(usize));
10716
10817 var tokens = std.json.TokenStream.init(spec);
109 var registry = try std.json.parse(Registry, &tokens, .{.allocator = allocator});
18 var registry = try std.json.parse(g.Registry, &tokens, .{.allocator = allocator});
11019
111 var buf = std.ArrayList(u8).init(allocator);
112 defer buf.deinit();
113
114 try render(buf.writer(), registry);
115
116 const tree = try std.zig.parse(allocator, buf.items);
117 _ = try std.zig.render(allocator, std.io.getStdOut().writer(), tree);
20 var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
21 try render(bw.writer(), registry);
22 try bw.flush();
11823}
11924
120fn render(writer: Writer, registry: Registry) !void {
25fn render(writer: anytype, registry: g.Registry) !void {
26 try writer.writeAll(
27 \\//! This file is auto-generated by tools/gen_spirv_spec.zig.
28 \\
29 \\const Version = @import("std").builtin.Version;
30 \\
31 );
32
12133 switch (registry) {
12234 .core => |core_reg| {
123 try renderCopyRight(writer, core_reg.copyright);
12435 try writer.print(
125 \\const Version = @import("builtin").Version;
126 \\pub const version = Version{{.major = {}, .minor = {}, .patch = {}}};
36 \\pub const version = Version{{ .major = {}, .minor = {}, .patch = {} }};
12737 \\pub const magic_number: u32 = {s};
12838 \\
12939 , .{ core_reg.major_version, core_reg.minor_version, core_reg.revision, core_reg.magic_number },
......@@ -132,10 +42,8 @@ fn render(writer: Writer, registry: Registry) !void {
13242 try renderOperandKinds(writer, core_reg.operand_kinds);
13343 },
13444 .extension => |ext_reg| {
135 try renderCopyRight(writer, ext_reg.copyright);
13645 try writer.print(
137 \\const Version = @import("builtin").Version;
138 \\pub const version = Version{{.major = {}, .minor = 0, .patch = {}}};
46 \\pub const version = Version{{ .major = {}, .minor = 0, .patch = {} }};
13947 \\
14048 , .{ ext_reg.version, ext_reg.revision },
14149 );
......@@ -145,21 +53,15 @@ fn render(writer: Writer, registry: Registry) !void {
14553 }
14654}
14755
148fn renderCopyRight(writer: Writer, copyright: []const []const u8) !void {
149 for (copyright) |line| {
150 try writer.print("// {s}\n", .{ line });
151 }
152}
153
154fn renderOpcodes(writer: Writer, instructions: []const Instruction) !void {
56fn renderOpcodes(writer: anytype, instructions: []const g.Instruction) !void {
15557 try writer.writeAll("pub const Opcode = extern enum(u16) {\n");
15658 for (instructions) |instr| {
157 try writer.print("{} = {},\n", .{ std.zig.fmtId(instr.opname), instr.opcode });
59 try writer.print(" {} = {},\n", .{ std.zig.fmtId(instr.opname), instr.opcode });
15860 }
159 try writer.writeAll("_,\n};\n");
61 try writer.writeAll(" _,\n};\n");
16062}
16163
162fn renderOperandKinds(writer: Writer, kinds: []const OperandKind) !void {
64fn renderOperandKinds(writer: anytype, kinds: []const g.OperandKind) !void {
16365 for (kinds) |kind| {
16466 switch (kind.category) {
16567 .ValueEnum => try renderValueEnum(writer, kind),
......@@ -169,20 +71,20 @@ fn renderOperandKinds(writer: Writer, kinds: []const OperandKind) !void {
16971 }
17072}
17173
172fn renderValueEnum(writer: Writer, enumeration: OperandKind) !void {
74fn renderValueEnum(writer: anytype, enumeration: g.OperandKind) !void {
17375 try writer.print("pub const {s} = extern enum(u32) {{\n", .{ enumeration.kind });
17476
17577 const enumerants = enumeration.enumerants orelse return error.InvalidRegistry;
17678 for (enumerants) |enumerant| {
17779 if (enumerant.value != .int) return error.InvalidRegistry;
17880
179 try writer.print("{} = {},\n", .{ std.zig.fmtId(enumerant.enumerant), enumerant.value.int });
81 try writer.print(" {} = {},\n", .{ std.zig.fmtId(enumerant.enumerant), enumerant.value.int });
18082 }
18183
182 try writer.writeAll("_,\n};\n");
84 try writer.writeAll(" _,\n};\n");
18385}
18486
185fn renderBitEnum(writer: Writer, enumeration: OperandKind) !void {
87fn renderBitEnum(writer: anytype, enumeration: g.OperandKind) !void {
18688 try writer.print("pub const {s} = packed struct {{\n", .{ enumeration.kind });
18789
18890 var flags_by_bitpos = [_]?[]const u8{null} ** 32;
......@@ -205,6 +107,7 @@ fn renderBitEnum(writer: Writer, enumeration: OperandKind) !void {
205107 }
206108
207109 for (flags_by_bitpos) |maybe_flag_name, bitpos| {
110 try writer.writeAll(" ");
208111 if (maybe_flag_name) |flag_name| {
209112 try writer.writeAll(flag_name);
210113 } else {
......@@ -215,7 +118,7 @@ fn renderBitEnum(writer: Writer, enumeration: OperandKind) !void {
215118 if (bitpos == 0) { // Force alignment to integer boundaries
216119 try writer.writeAll("align(@alignOf(u32)) ");
217120 }
218 try writer.writeAll("= false, ");
121 try writer.writeAll("= false,\n");
219122 }
220123
221124 try writer.writeAll("};\n");
tools/spirv/grammar.zig created+90
......@@ -0,0 +1,90 @@
1//! See https://www.khronos.org/registry/spir-v/specs/unified1/MachineReadableGrammar.html
2//! and the files in https://github.com/KhronosGroup/SPIRV-Headers/blob/master/include/spirv/unified1/
3//! Note: Non-canonical casing in these structs used to match SPIR-V spec json.
4pub const Registry = union(enum) {
5 core: CoreRegistry,
6 extension: ExtensionRegistry,
7};
8
9pub const CoreRegistry = struct {
10 copyright: [][]const u8,
11 /// Hexadecimal representation of the magic number
12 magic_number: []const u8,
13 major_version: u32,
14 minor_version: u32,
15 revision: u32,
16 instruction_printing_class: []InstructionPrintingClass,
17 instructions: []Instruction,
18 operand_kinds: []OperandKind,
19};
20
21pub const ExtensionRegistry = struct {
22 copyright: [][]const u8,
23 version: u32,
24 revision: u32,
25 instructions: []Instruction,
26 operand_kinds: []OperandKind = &[_]OperandKind{},
27};
28
29pub const InstructionPrintingClass = struct {
30 tag: []const u8,
31 heading: ?[]const u8 = null,
32};
33
34pub const Instruction = struct {
35 opname: []const u8,
36 class: ?[]const u8 = null, // Note: Only available in the core registry.
37 opcode: u32,
38 operands: []Operand = &[_]Operand{},
39 capabilities: [][]const u8 = &[_][]const u8{},
40 extensions: [][]const u8 = &[_][]const u8{},
41 version: ?[]const u8 = null,
42
43 lastVersion: ?[]const u8 = null,
44};
45
46pub const Operand = struct {
47 kind: []const u8,
48 /// If this field is 'null', the operand is only expected once.
49 quantifier: ?Quantifier = null,
50 name: []const u8 = "",
51};
52
53pub const Quantifier = enum {
54 /// zero or once
55 @"?",
56 /// zero or more
57 @"*",
58};
59
60pub const OperandCategory = enum {
61 BitEnum,
62 ValueEnum,
63 Id,
64 Literal,
65 Composite,
66};
67
68pub const OperandKind = struct {
69 category: OperandCategory,
70 /// The name
71 kind: []const u8,
72 doc: ?[]const u8 = null,
73 enumerants: ?[]Enumerant = null,
74 bases: ?[]const []const u8 = null,
75};
76
77pub const Enumerant = struct {
78 enumerant: []const u8,
79 value: union(enum) {
80 bitflag: []const u8, // Hexadecimal representation of the value
81 int: u31,
82 },
83 capabilities: [][]const u8 = &[_][]const u8{},
84 /// Valid for .ValueEnum and .BitEnum
85 extensions: [][]const u8 = &[_][]const u8{},
86 /// `quantifier` will always be `null`.
87 parameters: []Operand = &[_]Operand{},
88 version: ?[]const u8 = null,
89 lastVersion: ?[]const u8 = null,
90};
tools/update_spirv_features.zig created+321
......@@ -0,0 +1,321 @@
1const std = @import("std");
2const fs = std.fs;
3const Allocator = std.mem.Allocator;
4const g = @import("spirv/grammar.zig");
5
6//! This tool generates SPIR-V features from the grammar files in the SPIRV-Headers
7//! (https://github.com/KhronosGroup/SPIRV-Headers/) and SPIRV-Registry (https://github.com/KhronosGroup/SPIRV-Registry/)
8//! repositories. Currently it only generates a basic feature set definition consisting of versions, extensions and capabilities.
9//! There is a lot left to be desired, as currently dependencies of extensions and dependencies on extensions aren't generated.
10//! This is because there are some peculiarities in the SPIR-V registries:
11//! - Capabilities may depend on multiple extensions, which cannot be modelled yet by std.Target.
12//! - Extension dependencies are not documented in a machine-readable manner.
13//! - Note that the grammar spec also contains definitions from extensions which aren't actually official. Most of these seem to be
14//! from an intel project (https://github.com/intel/llvm/, https://github.com/intel/llvm/tree/sycl/sycl/doc/extensions/SPIRV),
15//! and so ONLY extensions in the SPIRV-Registry should be included.
16
17const Version = struct {
18 major: u32,
19 minor: u32,
20
21 fn parse(str: []const u8) !Version {
22 var it = std.mem.split(str, ".");
23
24 const major = it.next() orelse return error.InvalidVersion;
25 const minor = it.next() orelse return error.InvalidVersion;
26
27 if (it.next() != null) return error.InvalidVersion;
28
29 return Version{
30 .major = std.fmt.parseInt(u32, major, 10) catch return error.InvalidVersion,
31 .minor = std.fmt.parseInt(u32, minor, 10) catch return error.InvalidVersion,
32 };
33 }
34
35 fn eql(a: Version, b: Version) bool {
36 return a.major == b.major and a.minor == b.minor;
37 }
38
39 fn lessThan(ctx: void, a: Version, b: Version) bool {
40 return if (a.major == b.major)
41 a.minor < b.minor
42 else
43 a.major < b.major;
44 }
45};
46
47pub fn main() !void {
48 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
49 defer arena.deinit();
50 const allocator = &arena.allocator;
51
52 const args = try std.process.argsAlloc(allocator);
53
54 if (args.len <= 1) {
55 usageAndExit(std.io.getStdErr(), args[0], 1);
56 }
57 if (std.mem.eql(u8, args[1], "--help")) {
58 usageAndExit(std.io.getStdErr(), args[0], 0);
59 }
60 if (args.len != 3) {
61 usageAndExit(std.io.getStdErr(), args[0], 1);
62 }
63
64 const spirv_headers_root = args[1];
65 const spirv_registry_root = args[2];
66
67 if (std.mem.startsWith(u8, spirv_headers_root, "-") or std.mem.startsWith(u8, spirv_registry_root, "-")) {
68 usageAndExit(std.io.getStdErr(), args[0], 1);
69 }
70
71 const registry_path = try fs.path.join(allocator, &.{ spirv_headers_root, "include", "spirv", "unified1", "spirv.core.grammar.json" });
72 const registry_json = try std.fs.cwd().readFileAlloc(allocator, registry_path, std.math.maxInt(usize));
73 var tokens = std.json.TokenStream.init(registry_json);
74 const registry = try std.json.parse(g.CoreRegistry, &tokens, .{ .allocator = allocator });
75
76 const capabilities = for (registry.operand_kinds) |opkind| {
77 if (std.mem.eql(u8, opkind.kind, "Capability"))
78 break opkind.enumerants orelse return error.InvalidRegistry;
79 } else return error.InvalidRegistry;
80
81 const extensions = try gather_extensions(allocator, spirv_registry_root);
82 const versions = try gatherVersions(allocator, registry);
83
84 var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
85 const w = bw.writer();
86
87 try w.writeAll(
88 \\//! This file is auto-generated by tools/update_spirv_features.zig.
89 \\//! TODO: Dependencies of capabilities on extensions.
90 \\//! TODO: Dependencies of extensions on extensions.
91 \\//! TODO: Dependencies of extensions on versions.
92 \\
93 \\const std = @import("../std.zig");
94 \\const CpuFeature = std.Target.Cpu.Feature;
95 \\const CpuModel = std.Target.Cpu.Model;
96 \\
97 \\pub const Feature = enum {
98 \\
99 );
100
101 for (versions) |ver| {
102 try w.print(" v{}_{},\n", .{ ver.major, ver.minor });
103 }
104
105 for (extensions) |ext| {
106 try w.print(" {},\n", .{ std.zig.fmtId(ext) });
107 }
108
109 for (capabilities) |cap| {
110 try w.print(" {},\n", .{ std.zig.fmtId(cap.enumerant) });
111 }
112
113 try w.writeAll(
114 \\};
115 \\
116 \\pub usingnamespace CpuFeature.feature_set_fns(Feature);
117 \\
118 \\pub const all_features = blk: {
119 \\ @setEvalBranchQuota(2000);
120 \\ const len = @typeInfo(Feature).Enum.fields.len;
121 \\ std.debug.assert(len <= CpuFeature.Set.needed_bit_count);
122 \\ var result: [len]CpuFeature = undefined;
123 \\
124 );
125
126 for (versions) |ver, i| {
127 try w.print(
128 \\ result[@enumToInt(Feature.v{0}_{1})] = .{{
129 \\ .llvm_name = null,
130 \\ .description = "SPIR-V version {0}.{1}",
131 \\
132 , .{ ver.major, ver.minor }
133 );
134
135 if (i == 0) {
136 try w.writeAll(
137 \\ .dependencies = featureSet(&[_]Feature{}),
138 \\ };
139 \\
140 );
141 } else {
142 try w.print(
143 \\ .dependencies = featureSet(&[_]Feature{{
144 \\ .v{}_{},
145 \\ }}),
146 \\ }};
147 \\
148 , .{ versions[i - 1].major, versions[i - 1].minor }
149 );
150 }
151 }
152
153 // TODO: Extension dependencies.
154 for (extensions) |ext| {
155 try w.print(
156 \\ result[@enumToInt(Feature.{s})] = .{{
157 \\ .llvm_name = null,
158 \\ .description = "SPIR-V extension {s}",
159 \\ .dependencies = featureSet(&[_]Feature{{}}),
160 \\ }};
161 \\
162 , .{
163 std.zig.fmtId(ext),
164 ext,
165 }
166 );
167 }
168
169 // TODO: Capability extension dependencies.
170 for (capabilities) |cap| {
171 try w.print(
172 \\ result[@enumToInt(Feature.{s})] = .{{
173 \\ .llvm_name = null,
174 \\ .description = "Enable SPIR-V capability {s}",
175 \\ .dependencies = featureSet(&[_]Feature{{
176 \\
177 , .{
178 std.zig.fmtId(cap.enumerant),
179 cap.enumerant,
180 }
181 );
182
183 if (cap.version) |ver_str| {
184 if (!std.mem.eql(u8, ver_str, "None")) {
185 const ver = try Version.parse(ver_str);
186 try w.print(" .v{}_{},\n", .{ ver.major, ver.minor });
187 }
188 }
189
190 for (cap.capabilities) |cap_dep| {
191 try w.print(" .{},\n", .{ std.zig.fmtId(cap_dep) });
192 }
193
194 try w.writeAll(
195 \\ }),
196 \\ };
197 \\
198 );
199 }
200
201 try w.writeAll(
202 \\ const ti = @typeInfo(Feature);
203 \\ for (result) |*elem, i| {
204 \\ elem.index = i;
205 \\ elem.name = ti.Enum.fields[i].name;
206 \\ }
207 \\ break :blk result;
208 \\};
209 \\
210 );
211
212 try bw.flush();
213}
214
215/// SPIRV-Registry should hold all extensions currently registered for SPIR-V.
216/// The *.grammar.json in SPIRV-Headers should have most of these as well, but with this we're sure to get only the actually
217/// registered ones.
218/// TODO: Unfortunately, neither repository contains a machine-readable list of extension dependencies.
219fn gather_extensions(allocator: *Allocator, spirv_registry_root: []const u8) ![]const []const u8 {
220 const extensions_path = try fs.path.join(allocator, &.{spirv_registry_root, "extensions"});
221 var extensions_dir = try fs.cwd().openDir(extensions_path, .{ .iterate = true });
222 defer extensions_dir.close();
223
224 var extensions = std.ArrayList([]const u8).init(allocator);
225
226 var vendor_it = extensions_dir.iterate();
227 while (try vendor_it.next()) |vendor_entry| {
228 std.debug.assert(vendor_entry.kind == .Directory); // If this fails, the structure of SPIRV-Registry has changed.
229
230 const vendor_dir = try extensions_dir.openDir(vendor_entry.name, .{ .iterate = true });
231 var ext_it = vendor_dir.iterate();
232 while (try ext_it.next()) |ext_entry| {
233 // There is both a HTML and asciidoc version of every spec (as well as some other directories),
234 // we need just the name, but to avoid duplicates here we will just skip anything thats not asciidoc.
235 if (!std.mem.endsWith(u8, ext_entry.name, ".asciidoc"))
236 continue;
237
238 // Unfortunately, some extension filenames are incorrect, so we need to look for the string in tne 'Name Strings' section.
239 // This has the following format:
240 // ```
241 // Name Strings
242 // ------------
243 //
244 // SPV_EXT_name
245 // ```
246 // OR
247 // ```
248 // == Name Strings
249 //
250 // SPV_EXT_name
251 // ```
252
253 const ext_spec = try vendor_dir.readFileAlloc(allocator, ext_entry.name, std.math.maxInt(usize));
254 const name_strings = "Name Strings";
255
256 const name_strings_offset = std.mem.indexOf(u8, ext_spec, name_strings) orelse return error.InvalidRegistry;
257
258 // As the specs are inconsistent on this next part, just skip any newlines/minuses
259 var ext_start = name_strings_offset + name_strings.len + 1;
260 while (ext_spec[ext_start] == '\n' or ext_spec[ext_start] == '-') {
261 ext_start += 1;
262 }
263
264 const ext_end = std.mem.indexOfScalarPos(u8, ext_spec, ext_start, '\n') orelse return error.InvalidRegistry;
265 const ext = ext_spec[ext_start .. ext_end];
266
267 std.debug.assert(std.mem.startsWith(u8, ext, "SPV_")); // Sanity check, all extensions should have a name like SPV_VENDOR_extension.
268
269 try extensions.append(try allocator.dupe(u8, ext));
270 }
271 }
272
273 return extensions.items;
274}
275
276fn insertVersion(versions: *std.ArrayList(Version), version: ?[]const u8) !void {
277 const ver_str = version orelse return;
278 if (std.mem.eql(u8, ver_str, "None"))
279 return;
280
281 const ver = try Version.parse(ver_str);
282 for (versions.items) |existing_ver| {
283 if (ver.eql(existing_ver)) return;
284 }
285
286 try versions.append(ver);
287}
288
289fn gatherVersions(allocator: *Allocator, registry: g.CoreRegistry) ![]const Version {
290 // Expected number of versions is small
291 var versions = std.ArrayList(Version).init(allocator);
292
293 for (registry.instructions) |inst| {
294 try insertVersion(&versions, inst.version);
295 }
296
297 for (registry.operand_kinds) |opkind| {
298 const enumerants = opkind.enumerants orelse continue;
299 for (enumerants) |enumerant| {
300 try insertVersion(&versions, enumerant.version);
301 }
302 }
303
304 std.sort.sort(Version, versions.items, {}, Version.lessThan);
305
306 return versions.items;
307}
308
309fn usageAndExit(file: fs.File, arg0: []const u8, code: u8) noreturn {
310 file.writer().print(
311 \\Usage: {s} /path/git/SPIRV-Headers /path/git/SPIRV-Registry
312 \\
313 \\Prints to stdout Zig code which can be used to replace the file lib/std/target/spirv.zig.
314 \\
315 \\SPIRV-Headers can be cloned from https://github.com/KhronosGroup/SPIRV-Headers,
316 \\SPIRV-Registry can be cloned from https://github.com/KhronosGroup/SPIRV-Registry.
317 \\
318 , .{arg0}
319 ) catch std.process.exit(1);
320 std.process.exit(code);
321}