authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-03-02 13:08:21+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-03-18 19:13:50+01:00
log9b18125562b2402cae8450253decd906f09e4dc6
tree5525843896ccb333dfeb4fe832c565f4e1cd3b49
parent20d7bb68ac7043e7d4ec8f0653ec73a1090187da
signaturebadge-check Signed by SSH key SHA256:ZS52FNyUv2WUXvO4njmVaFVO46RHojFuOrxRc4LuKzg

spirv: make generic globals invocation-local


10 files changed, 1255 insertions(+), 771 deletions(-)

src/codegen/spirv.zig+240-208
...@@ -30,6 +30,8 @@ const SpvAssembler = @import("spirv/Assembler.zig");...@@ -30,6 +30,8 @@ const SpvAssembler = @import("spirv/Assembler.zig");
3030
31const InstMap = std.AutoHashMapUnmanaged(Air.Inst.Index, IdRef);31const InstMap = std.AutoHashMapUnmanaged(Air.Inst.Index, IdRef);
3232
33pub const zig_call_abi_ver = 3;
34
33/// We want to store some extra facts about types as mapped from Zig to SPIR-V.35/// We want to store some extra facts about types as mapped from Zig to SPIR-V.
34/// This structure is used to keep that extra information, as well as36/// This structure is used to keep that extra information, as well as
35/// the cached reference to the type.37/// the cached reference to the type.
...@@ -252,15 +254,18 @@ pub const Object = struct {...@@ -252,15 +254,18 @@ pub const Object = struct {
252 /// Note: Function does not actually generate the decl, it just allocates an index.254 /// Note: Function does not actually generate the decl, it just allocates an index.
253 pub fn resolveDecl(self: *Object, mod: *Module, decl_index: InternPool.DeclIndex) !SpvModule.Decl.Index {255 pub fn resolveDecl(self: *Object, mod: *Module, decl_index: InternPool.DeclIndex) !SpvModule.Decl.Index {
254 const decl = mod.declPtr(decl_index);256 const decl = mod.declPtr(decl_index);
257 assert(decl.has_tv); // TODO: Do we need to handle a situation where this is false?
255 try mod.markDeclAlive(decl);258 try mod.markDeclAlive(decl);
256259
257 const entry = try self.decl_link.getOrPut(self.gpa, decl_index);260 const entry = try self.decl_link.getOrPut(self.gpa, decl_index);
258 if (!entry.found_existing) {261 if (!entry.found_existing) {
259 // TODO: Extern fn?262 // TODO: Extern fn?
260 const kind: SpvModule.DeclKind = if (decl.val.isFuncBody(mod))263 const kind: SpvModule.Decl.Kind = if (decl.val.isFuncBody(mod))
261 .func264 .func
262 else265 else switch (decl.@"addrspace") {
263 .global;266 .generic => .invocation_global,
267 else => .global,
268 };
264269
265 entry.value_ptr.* = try self.spv.allocDecl(kind);270 entry.value_ptr.* = try self.spv.allocDecl(kind);
266 }271 }
...@@ -443,87 +448,90 @@ const DeclGen = struct {...@@ -443,87 +448,90 @@ const DeclGen = struct {
443 return self.inst_results.get(index).?; // Assertion means instruction does not dominate usage.448 return self.inst_results.get(index).?; // Assertion means instruction does not dominate usage.
444 }449 }
445450
446 fn resolveAnonDecl(self: *DeclGen, val: InternPool.Index, storage_class: StorageClass) !IdRef {451 fn resolveAnonDecl(self: *DeclGen, val: InternPool.Index) !IdRef {
447 // TODO: This cannot be a function at this point, but it should probably be handled anyway.452 // TODO: This cannot be a function at this point, but it should probably be handled anyway.
453
454 const mod = self.module;
455 const ty = Type.fromInterned(mod.intern_pool.typeOf(val));
456 const decl_ptr_ty_ref = try self.ptrType(ty, .Generic);
457
448 const spv_decl_index = blk: {458 const spv_decl_index = blk: {
449 const entry = try self.object.anon_decl_link.getOrPut(self.object.gpa, .{ val, storage_class });459 const entry = try self.object.anon_decl_link.getOrPut(self.object.gpa, .{ val, .Function });
450 if (entry.found_existing) {460 if (entry.found_existing) {
451 try self.addFunctionDep(entry.value_ptr.*, storage_class);461 try self.addFunctionDep(entry.value_ptr.*, .Function);
452 return self.spv.declPtr(entry.value_ptr.*).result_id;462
463 const result_id = self.spv.declPtr(entry.value_ptr.*).result_id;
464 return try self.castToGeneric(self.typeId(decl_ptr_ty_ref), result_id);
453 }465 }
454466
455 const spv_decl_index = try self.spv.allocDecl(.global);467 const spv_decl_index = try self.spv.allocDecl(.invocation_global);
456 try self.addFunctionDep(spv_decl_index, storage_class);468 try self.addFunctionDep(spv_decl_index, .Function);
457 entry.value_ptr.* = spv_decl_index;469 entry.value_ptr.* = spv_decl_index;
458 break :blk spv_decl_index;470 break :blk spv_decl_index;
459 };471 };
460472
461 const mod = self.module;
462 const ty = Type.fromInterned(mod.intern_pool.typeOf(val));
463 const ptr_ty_ref = try self.ptrType(ty, storage_class);
464
465 const var_id = self.spv.declPtr(spv_decl_index).result_id;
466
467 const section = &self.spv.sections.types_globals_constants;
468 try section.emit(self.spv.gpa, .OpVariable, .{
469 .id_result_type = self.typeId(ptr_ty_ref),
470 .id_result = var_id,
471 .storage_class = storage_class,
472 });
473
474 // TODO: At some point we will be able to generate this all constant here, but then all of473 // TODO: At some point we will be able to generate this all constant here, but then all of
475 // constant() will need to be implemented such that it doesn't generate any at-runtime code.474 // constant() will need to be implemented such that it doesn't generate any at-runtime code.
476 // NOTE: Because this is a global, we really only want to initialize it once. Therefore the475 // NOTE: Because this is a global, we really only want to initialize it once. Therefore the
477 // constant lowering of this value will need to be deferred to some other function, which476 // constant lowering of this value will need to be deferred to an initializer similar to
478 // is then added to the list of initializers using endGlobal().477 // other globals.
479478
480 // Save the current state so that we can temporarily generate into a different function.479 const result_id = self.spv.declPtr(spv_decl_index).result_id;
481 // TODO: This should probably be made a little more robust.
482 const func = self.func;
483 defer self.func = func;
484 const block_label = self.current_block_label;
485 defer self.current_block_label = block_label;
486480
487 self.func = .{};481 {
488 defer self.func.deinit(self.gpa);482 // Save the current state so that we can temporarily generate into a different function.
483 // TODO: This should probably be made a little more robust.
484 const func = self.func;
485 defer self.func = func;
486 const block_label = self.current_block_label;
487 defer self.current_block_label = block_label;
489488
490 // TODO: Merge this with genDecl?489 self.func = .{};
491 const begin = self.spv.beginGlobal();490 defer self.func.deinit(self.gpa);
492491
493 const void_ty_ref = try self.resolveType(Type.void, .direct);492 const void_ty_ref = try self.resolveType(Type.void, .direct);
494 const initializer_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{493 const initializer_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{
495 .return_type = void_ty_ref,494 .return_type = void_ty_ref,
496 .parameters = &.{},495 .parameters = &.{},
497 } });496 } });
498497
499 const initializer_id = self.spv.allocId();498 const initializer_id = self.spv.allocId();
500 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{
501 .id_result_type = self.typeId(void_ty_ref),
502 .id_result = initializer_id,
503 .function_control = .{},
504 .function_type = self.typeId(initializer_proto_ty_ref),
505 });
506 const root_block_id = self.spv.allocId();
507 try self.func.prologue.emit(self.spv.gpa, .OpLabel, .{
508 .id_result = root_block_id,
509 });
510 self.current_block_label = root_block_id;
511499
512 const val_id = try self.constant(ty, Value.fromInterned(val), .indirect);500 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{
513 try self.func.body.emit(self.spv.gpa, .OpStore, .{501 .id_result_type = self.typeId(void_ty_ref),
514 .pointer = var_id,502 .id_result = initializer_id,
515 .object = val_id,503 .function_control = .{},
516 });504 .function_type = self.typeId(initializer_proto_ty_ref),
505 });
506 const root_block_id = self.spv.allocId();
507 try self.func.prologue.emit(self.spv.gpa, .OpLabel, .{
508 .id_result = root_block_id,
509 });
510 self.current_block_label = root_block_id;
517511
518 self.spv.endGlobal(spv_decl_index, begin, var_id, initializer_id);512 const val_id = try self.constant(ty, Value.fromInterned(val), .indirect);
519 try self.func.body.emit(self.spv.gpa, .OpReturn, {});513 try self.func.body.emit(self.spv.gpa, .OpStore, .{
520 try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {});514 .pointer = result_id,
521 try self.spv.addFunction(spv_decl_index, self.func);515 .object = val_id,
516 });
522517
523 try self.spv.debugNameFmt(var_id, "__anon_{d}", .{@intFromEnum(val)});518 try self.func.body.emit(self.spv.gpa, .OpReturn, {});
524 try self.spv.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)});519 try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {});
520 try self.spv.addFunction(spv_decl_index, self.func);
521
522 try self.spv.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)});
525523
526 return var_id;524 const fn_decl_ptr_ty_ref = try self.ptrType(ty, .Function);
525 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{
526 .id_result_type = self.typeId(fn_decl_ptr_ty_ref),
527 .id_result = result_id,
528 .set = try self.spv.importInstructionSet(.zig),
529 .instruction = .{ .inst = 0 }, // TODO: Put this definition somewhere...
530 .id_ref_4 = &.{initializer_id},
531 });
532 }
533
534 return try self.castToGeneric(self.typeId(decl_ptr_ty_ref), result_id);
527 }535 }
528536
529 fn addFunctionDep(self: *DeclGen, decl_index: SpvModule.Decl.Index, storage_class: StorageClass) !void {537 fn addFunctionDep(self: *DeclGen, decl_index: SpvModule.Decl.Index, storage_class: StorageClass) !void {
...@@ -1179,19 +1187,10 @@ const DeclGen = struct {...@@ -1179,19 +1187,10 @@ const DeclGen = struct {
1179 unreachable; // TODO1187 unreachable; // TODO
1180 }1188 }
11811189
1182 const final_storage_class = self.spvStorageClass(ty.ptrAddressSpace(mod));1190 // Anon decl refs are always generic.
1183 const actual_storage_class = switch (final_storage_class) {1191 assert(ty.ptrAddressSpace(mod) == .generic);
1184 .Generic => .CrossWorkgroup,1192 const decl_ptr_ty_ref = try self.ptrType(decl_ty, .Generic);
1185 else => |other| other,1193 const ptr_id = try self.resolveAnonDecl(decl_val);
1186 };
1187
1188 const decl_id = try self.resolveAnonDecl(decl_val, actual_storage_class);
1189 const decl_ptr_ty_ref = try self.ptrType(decl_ty, final_storage_class);
1190
1191 const ptr_id = switch (final_storage_class) {
1192 .Generic => try self.castToGeneric(self.typeId(decl_ptr_ty_ref), decl_id),
1193 else => decl_id,
1194 };
11951194
1196 if (decl_ptr_ty_ref != ty_ref) {1195 if (decl_ptr_ty_ref != ty_ref) {
1197 // Differing pointer types, insert a cast.1196 // Differing pointer types, insert a cast.
...@@ -1229,8 +1228,13 @@ const DeclGen = struct {...@@ -1229,8 +1228,13 @@ const DeclGen = struct {
1229 }1228 }
12301229
1231 const spv_decl_index = try self.object.resolveDecl(mod, decl_index);1230 const spv_decl_index = try self.object.resolveDecl(mod, decl_index);
1231 const spv_decl = self.spv.declPtr(spv_decl_index);
1232
1233 const decl_id = switch (spv_decl.kind) {
1234 .func => unreachable, // TODO: Is this possible?
1235 .global, .invocation_global => spv_decl.result_id,
1236 };
12321237
1233 const decl_id = self.spv.declPtr(spv_decl_index).result_id;
1234 const final_storage_class = self.spvStorageClass(decl.@"addrspace");1238 const final_storage_class = self.spvStorageClass(decl.@"addrspace");
1235 try self.addFunctionDep(spv_decl_index, final_storage_class);1239 try self.addFunctionDep(spv_decl_index, final_storage_class);
12361240
...@@ -1509,6 +1513,13 @@ const DeclGen = struct {...@@ -1509,6 +1513,13 @@ const DeclGen = struct {
1509 if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref;1513 if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref;
15101514
1511 const fn_info = mod.typeToFunc(ty).?;1515 const fn_info = mod.typeToFunc(ty).?;
1516
1517 comptime assert(zig_call_abi_ver == 3);
1518 switch (fn_info.cc) {
1519 .Unspecified, .Kernel, .Fragment, .Vertex, .C => {},
1520 else => unreachable, // TODO
1521 }
1522
1512 // TODO: Put this somewhere in Sema.zig1523 // TODO: Put this somewhere in Sema.zig
1513 if (fn_info.is_var_args)1524 if (fn_info.is_var_args)
1514 return self.fail("VarArgs functions are unsupported for SPIR-V", .{});1525 return self.fail("VarArgs functions are unsupported for SPIR-V", .{});
...@@ -1956,13 +1967,15 @@ const DeclGen = struct {...@@ -1956,13 +1967,15 @@ const DeclGen = struct {
1956 /// (anyerror!void has the same layout as anyerror).1967 /// (anyerror!void has the same layout as anyerror).
1957 /// Each test declaration generates a function like.1968 /// Each test declaration generates a function like.
1958 /// %anyerror = OpTypeInt 0 161969 /// %anyerror = OpTypeInt 0 16
1970 /// %p_invocation_globals_struct_ty = ...
1959 /// %p_anyerror = OpTypePointer CrossWorkgroup %anyerror1971 /// %p_anyerror = OpTypePointer CrossWorkgroup %anyerror
1960 /// %K = OpTypeFunction %void %p_anyerror1972 /// %K = OpTypeFunction %void %p_invocation_globals_struct_ty %p_anyerror
1961 ///1973 ///
1962 /// %test = OpFunction %void %K1974 /// %test = OpFunction %void %K
1975 /// %p_invocation_globals = OpFunctionParameter p_invocation_globals_struct_ty
1963 /// %p_err = OpFunctionParameter %p_anyerror1976 /// %p_err = OpFunctionParameter %p_anyerror
1964 /// %lbl = OpLabel1977 /// %lbl = OpLabel
1965 /// %result = OpFunctionCall %anyerror %func1978 /// %result = OpFunctionCall %anyerror %func %p_invocation_globals
1966 /// OpStore %p_err %result1979 /// OpStore %p_err %result
1967 /// OpFunctionEnd1980 /// OpFunctionEnd
1968 /// TODO is to also write out the error as a function call parameter, and to somehow fetch1981 /// TODO is to also write out the error as a function call parameter, and to somehow fetch
...@@ -1972,10 +1985,12 @@ const DeclGen = struct {...@@ -1972,10 +1985,12 @@ const DeclGen = struct {
1972 const ptr_anyerror_ty_ref = try self.ptrType(Type.anyerror, .CrossWorkgroup);1985 const ptr_anyerror_ty_ref = try self.ptrType(Type.anyerror, .CrossWorkgroup);
1973 const void_ty_ref = try self.resolveType(Type.void, .direct);1986 const void_ty_ref = try self.resolveType(Type.void, .direct);
19741987
1975 const kernel_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{1988 const kernel_proto_ty_ref = try self.spv.resolve(.{
1976 .return_type = void_ty_ref,1989 .function_type = .{
1977 .parameters = &.{ptr_anyerror_ty_ref},1990 .return_type = void_ty_ref,
1978 } });1991 .parameters = &.{ptr_anyerror_ty_ref},
1992 },
1993 });
19791994
1980 const test_id = self.spv.declPtr(spv_test_decl_index).result_id;1995 const test_id = self.spv.declPtr(spv_test_decl_index).result_id;
19811996
...@@ -2026,147 +2041,164 @@ const DeclGen = struct {...@@ -2026,147 +2041,164 @@ const DeclGen = struct {
2026 const ip = &mod.intern_pool;2041 const ip = &mod.intern_pool;
2027 const decl = mod.declPtr(self.decl_index);2042 const decl = mod.declPtr(self.decl_index);
2028 const spv_decl_index = try self.object.resolveDecl(mod, self.decl_index);2043 const spv_decl_index = try self.object.resolveDecl(mod, self.decl_index);
2029 const target = self.getTarget();2044 const result_id = self.spv.declPtr(spv_decl_index).result_id;
20302045
2031 const decl_id = self.spv.declPtr(spv_decl_index).result_id;2046 switch (self.spv.declPtr(spv_decl_index).kind) {
2047 .func => {
2048 assert(decl.ty.zigTypeTag(mod) == .Fn);
2049 const fn_info = mod.typeToFunc(decl.ty).?;
2050 const return_ty_ref = try self.resolveFnReturnType(Type.fromInterned(fn_info.return_type));
20322051
2033 if (decl.val.getFunction(mod)) |_| {2052 const prototype_ty_ref = try self.resolveType(decl.ty, .direct);
2034 assert(decl.ty.zigTypeTag(mod) == .Fn);2053 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{
2035 const fn_info = mod.typeToFunc(decl.ty).?;2054 .id_result_type = self.typeId(return_ty_ref),
2036 const return_ty_ref = try self.resolveFnReturnType(Type.fromInterned(fn_info.return_type));2055 .id_result = result_id,
2056 .function_control = switch (fn_info.cc) {
2057 .Inline => .{ .Inline = true },
2058 else => .{},
2059 },
2060 .function_type = self.typeId(prototype_ty_ref),
2061 });
20372062
2038 const prototype_id = try self.resolveTypeId(decl.ty);2063 comptime assert(zig_call_abi_ver == 3);
2039 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{2064 try self.args.ensureUnusedCapacity(self.gpa, fn_info.param_types.len);
2040 .id_result_type = self.typeId(return_ty_ref),2065 for (fn_info.param_types.get(ip)) |param_ty_index| {
2041 .id_result = decl_id,2066 const param_ty = Type.fromInterned(param_ty_index);
2042 .function_control = switch (fn_info.cc) {2067 if (!param_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
2043 .Inline => .{ .Inline = true },2068
2044 else => .{},2069 const param_type_id = try self.resolveTypeId(param_ty);
2045 },2070 const arg_result_id = self.spv.allocId();
2046 .function_type = prototype_id,2071 try self.func.prologue.emit(self.spv.gpa, .OpFunctionParameter, .{
2047 });2072 .id_result_type = param_type_id,
2073 .id_result = arg_result_id,
2074 });
2075 self.args.appendAssumeCapacity(arg_result_id);
2076 }
20482077
2049 try self.args.ensureUnusedCapacity(self.gpa, fn_info.param_types.len);2078 // TODO: This could probably be done in a better way...
2050 for (fn_info.param_types.get(ip)) |param_ty_index| {2079 const root_block_id = self.spv.allocId();
2051 const param_ty = Type.fromInterned(param_ty_index);
2052 if (!param_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
20532080
2054 const param_type_id = try self.resolveTypeId(param_ty);2081 // The root block of a function declaration should appear before OpVariable instructions,
2055 const arg_result_id = self.spv.allocId();2082 // so it is generated into the function's prologue.
2056 try self.func.prologue.emit(self.spv.gpa, .OpFunctionParameter, .{2083 try self.func.prologue.emit(self.spv.gpa, .OpLabel, .{
2057 .id_result_type = param_type_id,2084 .id_result = root_block_id,
2058 .id_result = arg_result_id,
2059 });2085 });
2060 self.args.appendAssumeCapacity(arg_result_id);2086 self.current_block_label = root_block_id;
2061 }
20622087
2063 // TODO: This could probably be done in a better way...2088 const main_body = self.air.getMainBody();
2064 const root_block_id = self.spv.allocId();2089 switch (self.control_flow) {
2090 .structured => {
2091 _ = try self.genStructuredBody(.selection, main_body);
2092 // We always expect paths to here to end, but we still need the block
2093 // to act as a dummy merge block.
2094 try self.func.body.emit(self.spv.gpa, .OpUnreachable, {});
2095 },
2096 .unstructured => {
2097 try self.genBody(main_body);
2098 },
2099 }
2100 try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {});
2101 // Append the actual code into the functions section.
2102 try self.spv.addFunction(spv_decl_index, self.func);
20652103
2066 // The root block of a function declaration should appear before OpVariable instructions,2104 const fqn = ip.stringToSlice(try decl.fullyQualifiedName(self.module));
2067 // so it is generated into the function's prologue.2105 try self.spv.debugName(result_id, fqn);
2068 try self.func.prologue.emit(self.spv.gpa, .OpLabel, .{
2069 .id_result = root_block_id,
2070 });
2071 self.current_block_label = root_block_id;
20722106
2073 const main_body = self.air.getMainBody();2107 // Temporarily generate a test kernel declaration if this is a test function.
2074 switch (self.control_flow) {2108 if (self.module.test_functions.contains(self.decl_index)) {
2075 .structured => {2109 try self.generateTestEntryPoint(fqn, spv_decl_index);
2076 _ = try self.genStructuredBody(.selection, main_body);2110 }
2077 // We always expect paths to here to end, but we still need the block2111 },
2078 // to act as a dummy merge block.2112 .global => {
2079 try self.func.body.emit(self.spv.gpa, .OpUnreachable, {});2113 const maybe_init_val: ?Value = blk: {
2080 },2114 if (decl.val.getVariable(mod)) |payload| {
2081 .unstructured => {2115 if (payload.is_extern) break :blk null;
2082 try self.genBody(main_body);2116 break :blk Value.fromInterned(payload.init);
2083 },2117 }
2084 }2118 break :blk decl.val;
2085 try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {});2119 };
2086 // Append the actual code into the functions section.2120 assert(maybe_init_val == null); // TODO
2087 try self.spv.addFunction(spv_decl_index, self.func);
20882121
2089 const fqn = ip.stringToSlice(try decl.fullyQualifiedName(self.module));2122 const final_storage_class = self.spvStorageClass(decl.@"addrspace");
2090 try self.spv.debugName(decl_id, fqn);2123 assert(final_storage_class != .Generic); // These should be instance globals
20912124
2092 // Temporarily generate a test kernel declaration if this is a test function.2125 const ptr_ty_ref = try self.ptrType(decl.ty, final_storage_class);
2093 if (self.module.test_functions.contains(self.decl_index)) {
2094 try self.generateTestEntryPoint(fqn, spv_decl_index);
2095 }
2096 } else {
2097 const opt_init_val: ?Value = blk: {
2098 if (decl.val.getVariable(mod)) |payload| {
2099 if (payload.is_extern) break :blk null;
2100 break :blk Value.fromInterned(payload.init);
2101 }
2102 break :blk decl.val;
2103 };
21042126
2105 // Generate the actual variable for the global...2127 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpVariable, .{
2106 const final_storage_class = self.spvStorageClass(decl.@"addrspace");2128 .id_result_type = self.typeId(ptr_ty_ref),
2107 const actual_storage_class = blk: {2129 .id_result = result_id,
2108 if (target.os.tag != .vulkan) {2130 .storage_class = final_storage_class,
2109 break :blk switch (final_storage_class) {2131 });
2110 .Generic => .CrossWorkgroup,
2111 else => final_storage_class,
2112 };
2113 }
2114 break :blk final_storage_class;
2115 };
21162132
2117 const ptr_ty_ref = try self.ptrType(decl.ty, actual_storage_class);2133 const fqn = ip.stringToSlice(try decl.fullyQualifiedName(self.module));
2134 try self.spv.debugName(result_id, fqn);
2135 try self.spv.declareDeclDeps(spv_decl_index, &.{});
2136 },
2137 .invocation_global => {
2138 const maybe_init_val: ?Value = blk: {
2139 if (decl.val.getVariable(mod)) |payload| {
2140 if (payload.is_extern) break :blk null;
2141 break :blk Value.fromInterned(payload.init);
2142 }
2143 break :blk decl.val;
2144 };
21182145
2119 const begin = self.spv.beginGlobal();2146 try self.spv.declareDeclDeps(spv_decl_index, &.{});
2120 try self.spv.globals.section.emit(self.spv.gpa, .OpVariable, .{
2121 .id_result_type = self.typeId(ptr_ty_ref),
2122 .id_result = decl_id,
2123 .storage_class = actual_storage_class,
2124 });
2125 const fqn = ip.stringToSlice(try decl.fullyQualifiedName(self.module));
2126 try self.spv.debugName(decl_id, fqn);
21272147
2128 if (opt_init_val) |init_val| {2148 const ptr_ty_ref = try self.ptrType(decl.ty, .Function);
2129 // Currently, initializers for CrossWorkgroup variables is not implemented
2130 // in Mesa. Therefore we generate an initialization kernel instead.
2131 const void_ty_ref = try self.resolveType(Type.void, .direct);
21322149
2133 const initializer_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{2150 if (maybe_init_val) |init_val| {
2134 .return_type = void_ty_ref,2151 // TODO: Combine with resolveAnonDecl?
2135 .parameters = &.{},2152 const void_ty_ref = try self.resolveType(Type.void, .direct);
2136 } });2153 const initializer_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{
2154 .return_type = void_ty_ref,
2155 .parameters = &.{},
2156 } });
21372157
2138 // Now emit the instructions that initialize the variable.2158 const initializer_id = self.spv.allocId();
2139 const initializer_id = self.spv.allocId();2159 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{
2140 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{2160 .id_result_type = self.typeId(void_ty_ref),
2141 .id_result_type = self.typeId(void_ty_ref),2161 .id_result = initializer_id,
2142 .id_result = initializer_id,2162 .function_control = .{},
2143 .function_control = .{},2163 .function_type = self.typeId(initializer_proto_ty_ref),
2144 .function_type = self.typeId(initializer_proto_ty_ref),2164 });
2145 });
2146 const root_block_id = self.spv.allocId();
2147 try self.func.prologue.emit(self.spv.gpa, .OpLabel, .{
2148 .id_result = root_block_id,
2149 });
2150 self.current_block_label = root_block_id;
21512165
2152 const val_id = try self.constant(decl.ty, init_val, .indirect);2166 const root_block_id = self.spv.allocId();
2153 try self.func.body.emit(self.spv.gpa, .OpStore, .{2167 try self.func.prologue.emit(self.spv.gpa, .OpLabel, .{
2154 .pointer = decl_id,2168 .id_result = root_block_id,
2155 .object = val_id,2169 });
2156 });2170 self.current_block_label = root_block_id;
21572171
2158 // TODO: We should be able to get rid of this by now...2172 const val_id = try self.constant(decl.ty, init_val, .indirect);
2159 self.spv.endGlobal(spv_decl_index, begin, decl_id, initializer_id);2173 try self.func.body.emit(self.spv.gpa, .OpStore, .{
2174 .pointer = result_id,
2175 .object = val_id,
2176 });
21602177
2161 try self.func.body.emit(self.spv.gpa, .OpReturn, {});2178 try self.func.body.emit(self.spv.gpa, .OpReturn, {});
2162 try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {});2179 try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {});
2163 try self.spv.addFunction(spv_decl_index, self.func);2180 try self.spv.addFunction(spv_decl_index, self.func);
21642181
2165 try self.spv.debugNameFmt(initializer_id, "initializer of {s}", .{fqn});2182 const fqn = ip.stringToSlice(try decl.fullyQualifiedName(self.module));
2166 } else {2183 try self.spv.debugNameFmt(initializer_id, "initializer of {s}", .{fqn});
2167 self.spv.endGlobal(spv_decl_index, begin, decl_id, null);2184
2168 try self.spv.declareDeclDeps(spv_decl_index, &.{});2185 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{
2169 }2186 .id_result_type = self.typeId(ptr_ty_ref),
2187 .id_result = result_id,
2188 .set = try self.spv.importInstructionSet(.zig),
2189 .instruction = .{ .inst = 0 }, // TODO: Put this definition somewhere...
2190 .id_ref_4 = &.{initializer_id},
2191 });
2192 } else {
2193 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{
2194 .id_result_type = self.typeId(ptr_ty_ref),
2195 .id_result = result_id,
2196 .set = try self.spv.importInstructionSet(.zig),
2197 .instruction = .{ .inst = 0 }, // TODO: Put this definition somewhere...
2198 .id_ref_4 = &.{},
2199 });
2200 }
2201 },
2170 }2202 }
2171 }2203 }
21722204
...@@ -2559,8 +2591,8 @@ const DeclGen = struct {...@@ -2559,8 +2591,8 @@ const DeclGen = struct {
2559 else => unreachable,2591 else => unreachable,
2560 };2592 };
2561 const set_id = switch (target.os.tag) {2593 const set_id = switch (target.os.tag) {
2562 .opencl => try self.spv.importInstructionSet(.opencl),2594 .opencl => try self.spv.importInstructionSet(.@"OpenCL.std"),
2563 .vulkan => try self.spv.importInstructionSet(.glsl),2595 .vulkan => try self.spv.importInstructionSet(.@"GLSL.std.450"),
2564 else => unreachable,2596 else => unreachable,
2565 };2597 };
25662598
...@@ -2734,8 +2766,8 @@ const DeclGen = struct {...@@ -2734,8 +2766,8 @@ const DeclGen = struct {
2734 else => unreachable,2766 else => unreachable,
2735 };2767 };
2736 const set_id = switch (target.os.tag) {2768 const set_id = switch (target.os.tag) {
2737 .opencl => try self.spv.importInstructionSet(.opencl),2769 .opencl => try self.spv.importInstructionSet(.@"OpenCL.std"),
2738 .vulkan => try self.spv.importInstructionSet(.glsl),2770 .vulkan => try self.spv.importInstructionSet(.@"GLSL.std.450"),
2739 else => unreachable,2771 else => unreachable,
2740 };2772 };
27412773
...@@ -5427,9 +5459,9 @@ const DeclGen = struct {...@@ -5427,9 +5459,9 @@ const DeclGen = struct {
5427 const result_id = self.spv.allocId();5459 const result_id = self.spv.allocId();
5428 const callee_id = try self.resolve(pl_op.operand);5460 const callee_id = try self.resolve(pl_op.operand);
54295461
5462 comptime assert(zig_call_abi_ver == 3);
5430 const params = try self.gpa.alloc(spec.IdRef, args.len);5463 const params = try self.gpa.alloc(spec.IdRef, args.len);
5431 defer self.gpa.free(params);5464 defer self.gpa.free(params);
5432
5433 var n_params: usize = 0;5465 var n_params: usize = 0;
5434 for (args) |arg| {5466 for (args) |arg| {
5435 // Note: resolve() might emit instructions, so we need to call it5467 // Note: resolve() might emit instructions, so we need to call it
src/codegen/spirv/Cache.zig+10-21
...@@ -134,7 +134,10 @@ const Tag = enum {...@@ -134,7 +134,10 @@ const Tag = enum {
134 /// data is (bool) type134 /// data is (bool) type
135 bool_false,135 bool_false,
136136
137 const SimpleType = enum { void, bool };137 const SimpleType = enum {
138 void,
139 bool,
140 };
138141
139 const VectorType = Key.VectorType;142 const VectorType = Key.VectorType;
140 const ArrayType = Key.ArrayType;143 const ArrayType = Key.ArrayType;
...@@ -287,11 +290,12 @@ pub const Key = union(enum) {...@@ -287,11 +290,12 @@ pub const Key = union(enum) {
287 pub const PointerType = struct {290 pub const PointerType = struct {
288 storage_class: StorageClass,291 storage_class: StorageClass,
289 child_type: Ref,292 child_type: Ref,
293 /// Ref to a .fwd_ptr_type.
290 fwd: Ref,294 fwd: Ref,
291 // TODO: Decorations:295 // TODO: Decorations:
292 // - Alignment296 // - Alignment
293 // - ArrayStride,297 // - ArrayStride
294 // - MaxByteOffset,298 // - MaxByteOffset
295 };299 };
296300
297 pub const ForwardPointerType = struct {301 pub const ForwardPointerType = struct {
...@@ -728,6 +732,9 @@ pub fn resolve(self: *Self, spv: *Module, key: Key) !Ref {...@@ -728,6 +732,9 @@ pub fn resolve(self: *Self, spv: *Module, key: Key) !Ref {
728 // },732 // },
729 .ptr_type => |ptr| Item{733 .ptr_type => |ptr| Item{
730 .tag = .type_ptr_simple,734 .tag = .type_ptr_simple,
735 // For this variant we need to steal the ID of the forward-declaration, instead
736 // of allocating one manually. This will make sure that we get a single result-id
737 // any possibly forward declared pointer type.
731 .result_id = self.resultId(ptr.fwd),738 .result_id = self.resultId(ptr.fwd),
732 .data = try self.addExtra(spv, Tag.SimplePointerType{739 .data = try self.addExtra(spv, Tag.SimplePointerType{
733 .storage_class = ptr.storage_class,740 .storage_class = ptr.storage_class,
...@@ -896,24 +903,6 @@ pub fn lookup(self: *const Self, ref: Ref) Key {...@@ -896,24 +903,6 @@ pub fn lookup(self: *const Self, ref: Ref) Key {
896 },903 },
897 };904 };
898 },905 },
899 // .type_ptr_generic => .{
900 // .ptr_type = .{
901 // .storage_class = .Generic,
902 // .child_type = @enumFromInt(data),
903 // },
904 // },
905 // .type_ptr_crosswgp => .{
906 // .ptr_type = .{
907 // .storage_class = .CrossWorkgroup,
908 // .child_type = @enumFromInt(data),
909 // },
910 // },
911 // .type_ptr_function => .{
912 // .ptr_type = .{
913 // .storage_class = .Function,
914 // .child_type = @enumFromInt(data),
915 // },
916 // },
917 .type_ptr_simple => {906 .type_ptr_simple => {
918 const payload = self.extraData(Tag.SimplePointerType, data);907 const payload = self.extraData(Tag.SimplePointerType, data);
919 return .{908 return .{
src/codegen/spirv/Module.zig+43-227
...@@ -72,9 +72,20 @@ pub const Decl = struct {...@@ -72,9 +72,20 @@ pub const Decl = struct {
72 /// Index to refer to a Decl by.72 /// Index to refer to a Decl by.
73 pub const Index = enum(u32) { _ };73 pub const Index = enum(u32) { _ };
7474
75 /// The result-id to be used for this declaration. This is the final result-id75 /// Useful to tell what kind of decl this is, and hold the result-id or field index
76 /// of the decl, which may be an OpFunction, OpVariable, or the result of a sequence76 /// to be used for this decl.
77 /// of OpSpecConstantOp operations.77 pub const Kind = enum {
78 func,
79 global,
80 invocation_global,
81 };
82
83 /// See comment on Kind
84 kind: Kind,
85 /// The result-id associated to this decl. The specific meaning of this depends on `kind`:
86 /// - For `func`, this is the result-id of the associated OpFunction instruction.
87 /// - For `global`, this is the result-id of the associated OpVariable instruction.
88 /// - For `invocation_global`, this is the result-id of the associated InvocationGlobal instruction.
78 result_id: IdRef,89 result_id: IdRef,
79 /// The offset of the first dependency of this decl in the `decl_deps` array.90 /// The offset of the first dependency of this decl in the `decl_deps` array.
80 begin_dep: u32,91 begin_dep: u32,
...@@ -82,20 +93,6 @@ pub const Decl = struct {...@@ -82,20 +93,6 @@ pub const Decl = struct {
82 end_dep: u32,93 end_dep: u32,
83};94};
8495
85/// Globals must be kept in order: operations involving globals must be ordered
86/// so that the global declaration precedes any usage.
87pub const Global = struct {
88 /// This is the result-id of the OpVariable instruction that declares the global.
89 result_id: IdRef,
90 /// The offset into `self.globals.section` of the first instruction of this global
91 /// declaration.
92 begin_inst: u32,
93 /// The past-end offset into `self.flobals.section`.
94 end_inst: u32,
95 /// The result-id of the function that initializes this value.
96 initializer_id: ?IdRef,
97};
98
99/// This models a kernel entry point.96/// This models a kernel entry point.
100pub const EntryPoint = struct {97pub const EntryPoint = struct {
101 /// The declaration that should be exported.98 /// The declaration that should be exported.
...@@ -165,18 +162,8 @@ decl_deps: std.ArrayListUnmanaged(Decl.Index) = .{},...@@ -165,18 +162,8 @@ decl_deps: std.ArrayListUnmanaged(Decl.Index) = .{},
165/// The list of entry points that should be exported from this module.162/// The list of entry points that should be exported from this module.
166entry_points: std.ArrayListUnmanaged(EntryPoint) = .{},163entry_points: std.ArrayListUnmanaged(EntryPoint) = .{},
167164
168/// The fields in this structure help to maintain the required order for global variables.
169globals: struct {
170 /// Set of globals, referred to by Decl.Index.
171 globals: std.AutoArrayHashMapUnmanaged(Decl.Index, Global) = .{},
172 /// This pseudo-section contains the initialization code for all the globals. Instructions from
173 /// here are reordered when flushing the module. Its contents should be part of the
174 /// `types_globals_constants` SPIR-V section when the module is emitted.
175 section: Section = .{},
176} = .{},
177
178/// The list of extended instruction sets that should be imported.165/// The list of extended instruction sets that should be imported.
179extended_instruction_set: std.AutoHashMapUnmanaged(ExtendedInstructionSet, IdRef) = .{},166extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, IdRef) = .{},
180167
181pub fn init(gpa: Allocator) Module {168pub fn init(gpa: Allocator) Module {
182 return .{169 return .{
...@@ -205,9 +192,6 @@ pub fn deinit(self: *Module) void {...@@ -205,9 +192,6 @@ pub fn deinit(self: *Module) void {
205192
206 self.entry_points.deinit(self.gpa);193 self.entry_points.deinit(self.gpa);
207194
208 self.globals.globals.deinit(self.gpa);
209 self.globals.section.deinit(self.gpa);
210
211 self.extended_instruction_set.deinit(self.gpa);195 self.extended_instruction_set.deinit(self.gpa);
212196
213 self.* = undefined;197 self.* = undefined;
...@@ -243,46 +227,6 @@ pub fn resolveString(self: *Module, str: []const u8) !CacheString {...@@ -243,46 +227,6 @@ pub fn resolveString(self: *Module, str: []const u8) !CacheString {
243 return try self.cache.addString(self, str);227 return try self.cache.addString(self, str);
244}228}
245229
246fn orderGlobalsInto(
247 self: *Module,
248 decl_index: Decl.Index,
249 section: *Section,
250 seen: *std.DynamicBitSetUnmanaged,
251) !void {
252 const decl = self.declPtr(decl_index);
253 const deps = self.decl_deps.items[decl.begin_dep..decl.end_dep];
254 const global = self.globalPtr(decl_index).?;
255 const insts = self.globals.section.instructions.items[global.begin_inst..global.end_inst];
256
257 seen.set(@intFromEnum(decl_index));
258
259 for (deps) |dep| {
260 if (!seen.isSet(@intFromEnum(dep))) {
261 try self.orderGlobalsInto(dep, section, seen);
262 }
263 }
264
265 try section.instructions.appendSlice(self.gpa, insts);
266}
267
268fn orderGlobals(self: *Module) !Section {
269 const globals = self.globals.globals.keys();
270
271 var seen = try std.DynamicBitSetUnmanaged.initEmpty(self.gpa, self.decls.items.len);
272 defer seen.deinit(self.gpa);
273
274 var ordered_globals = Section{};
275 errdefer ordered_globals.deinit(self.gpa);
276
277 for (globals) |decl_index| {
278 if (!seen.isSet(@intFromEnum(decl_index))) {
279 try self.orderGlobalsInto(decl_index, &ordered_globals, &seen);
280 }
281 }
282
283 return ordered_globals;
284}
285
286fn addEntryPointDeps(230fn addEntryPointDeps(
287 self: *Module,231 self: *Module,
288 decl_index: Decl.Index,232 decl_index: Decl.Index,
...@@ -298,8 +242,8 @@ fn addEntryPointDeps(...@@ -298,8 +242,8 @@ fn addEntryPointDeps(
298242
299 seen.set(@intFromEnum(decl_index));243 seen.set(@intFromEnum(decl_index));
300244
301 if (self.globalPtr(decl_index)) |global| {245 if (decl.kind == .global) {
302 try interface.append(global.result_id);246 try interface.append(decl.result_id);
303 }247 }
304248
305 for (deps) |dep| {249 for (deps) |dep| {
...@@ -335,81 +279,9 @@ fn entryPoints(self: *Module) !Section {...@@ -335,81 +279,9 @@ fn entryPoints(self: *Module) !Section {
335 return entry_points;279 return entry_points;
336}280}
337281
338/// Generate a function that calls all initialization functions,282pub fn finalize(self: *Module, a: Allocator, target: std.Target) ![]Word {
339/// in unspecified order (an order should not be required here).
340/// It generated as follows:
341/// %init = OpFunction %void None
342/// foreach %initializer:
343/// OpFunctionCall %initializer
344/// OpReturn
345/// OpFunctionEnd
346fn initializer(self: *Module, entry_points: *Section) !Section {
347 var section = Section{};
348 errdefer section.deinit(self.gpa);
349
350 // const void_ty_ref = try self.resolveType(Type.void, .direct);
351 const void_ty_ref = try self.resolve(.void_type);
352 const void_ty_id = self.resultId(void_ty_ref);
353 const init_proto_ty_ref = try self.resolve(.{ .function_type = .{
354 .return_type = void_ty_ref,
355 .parameters = &.{},
356 } });
357
358 const init_id = self.allocId();
359 try section.emit(self.gpa, .OpFunction, .{
360 .id_result_type = void_ty_id,
361 .id_result = init_id,
362 .function_control = .{},
363 .function_type = self.resultId(init_proto_ty_ref),
364 });
365 try section.emit(self.gpa, .OpLabel, .{
366 .id_result = self.allocId(),
367 });
368
369 var seen = try std.DynamicBitSetUnmanaged.initEmpty(self.gpa, self.decls.items.len);
370 defer seen.deinit(self.gpa);
371
372 var interface = std.ArrayList(IdRef).init(self.gpa);
373 defer interface.deinit();
374
375 for (self.globals.globals.keys(), self.globals.globals.values()) |decl_index, global| {
376 try self.addEntryPointDeps(decl_index, &seen, &interface);
377 if (global.initializer_id) |initializer_id| {
378 try section.emit(self.gpa, .OpFunctionCall, .{
379 .id_result_type = void_ty_id,
380 .id_result = self.allocId(),
381 .function = initializer_id,
382 });
383 }
384 }
385
386 try section.emit(self.gpa, .OpReturn, {});
387 try section.emit(self.gpa, .OpFunctionEnd, {});
388
389 try entry_points.emit(self.gpa, .OpEntryPoint, .{
390 // TODO: Rusticl does not support this because its poorly defined.
391 // Do we need to generate a workaround here?
392 .execution_model = .Kernel,
393 .entry_point = init_id,
394 .name = "zig global initializer",
395 .interface = interface.items,
396 });
397
398 try self.sections.execution_modes.emit(self.gpa, .OpExecutionMode, .{
399 .entry_point = init_id,
400 .mode = .Initializer,
401 });
402
403 return section;
404}
405
406/// Emit this module as a spir-v binary.
407pub fn flush(self: *Module, file: std.fs.File, target: std.Target) !void {
408 // See SPIR-V Spec section 2.3, "Physical Layout of a SPIR-V Module and Instruction"283 // See SPIR-V Spec section 2.3, "Physical Layout of a SPIR-V Module and Instruction"
409284 // TODO: Audit calls to allocId() in this function to make it idempotent.
410 // TODO: Perform topological sort on the globals.
411 var globals = try self.orderGlobals();
412 defer globals.deinit(self.gpa);
413285
414 var entry_points = try self.entryPoints();286 var entry_points = try self.entryPoints();
415 defer entry_points.deinit(self.gpa);287 defer entry_points.deinit(self.gpa);
...@@ -417,13 +289,6 @@ pub fn flush(self: *Module, file: std.fs.File, target: std.Target) !void {...@@ -417,13 +289,6 @@ pub fn flush(self: *Module, file: std.fs.File, target: std.Target) !void {
417 var types_constants = try self.cache.materialize(self);289 var types_constants = try self.cache.materialize(self);
418 defer types_constants.deinit(self.gpa);290 defer types_constants.deinit(self.gpa);
419291
420 // // TODO: Pass global variables as function parameters
421 // var init_func = if (target.os.tag != .vulkan)
422 // try self.initializer(&entry_points)
423 // else
424 // Section{};
425 // defer init_func.deinit(self.gpa);
426
427 const header = [_]Word{292 const header = [_]Word{
428 spec.magic_number,293 spec.magic_number,
429 // TODO: From cpu features294 // TODO: From cpu features
...@@ -436,7 +301,7 @@ pub fn flush(self: *Module, file: std.fs.File, target: std.Target) !void {...@@ -436,7 +301,7 @@ pub fn flush(self: *Module, file: std.fs.File, target: std.Target) !void {
436 else => 4,301 else => 4,
437 },302 },
438 }),303 }),
439 0, // TODO: Register Zig compiler magic number.304 spec.zig_generator_id,
440 self.idBound(),305 self.idBound(),
441 0, // Schema (currently reserved for future use)306 0, // Schema (currently reserved for future use)
442 };307 };
...@@ -468,30 +333,23 @@ pub fn flush(self: *Module, file: std.fs.File, target: std.Target) !void {...@@ -468,30 +333,23 @@ pub fn flush(self: *Module, file: std.fs.File, target: std.Target) !void {
468 self.sections.annotations.toWords(),333 self.sections.annotations.toWords(),
469 types_constants.toWords(),334 types_constants.toWords(),
470 self.sections.types_globals_constants.toWords(),335 self.sections.types_globals_constants.toWords(),
471 globals.toWords(),
472 self.sections.functions.toWords(),336 self.sections.functions.toWords(),
473 };337 };
474338
475 if (builtin.zig_backend == .stage2_x86_64) {339 var total_result_size: usize = 0;
476 for (buffers) |buf| {340 for (buffers) |buffer| {
477 try file.writeAll(std.mem.sliceAsBytes(buf));341 total_result_size += buffer.len;
478 }342 }
479 } else {343 const result = try a.alloc(Word, total_result_size);
480 // miscompiles with x86_64 backend344 errdefer a.free(result);
481 var iovc_buffers: [buffers.len]std.os.iovec_const = undefined;345
482 var file_size: u64 = 0;346 var offset: usize = 0;
483 for (&iovc_buffers, 0..) |*iovc, i| {347 for (buffers) |buffer| {
484 // Note, since spir-v supports both little and big endian we can ignore byte order here and348 @memcpy(result[offset..][0..buffer.len], buffer);
485 // just treat the words as a sequence of bytes.349 offset += buffer.len;
486 const bytes = std.mem.sliceAsBytes(buffers[i]);
487 iovc.* = .{ .iov_base = bytes.ptr, .iov_len = bytes.len };
488 file_size += bytes.len;
489 }
490
491 try file.seekTo(0);
492 try file.setEndPos(file_size);
493 try file.pwritevAll(&iovc_buffers, 0);
494 }350 }
351
352 return result;
495}353}
496354
497/// Merge the sections making up a function declaration into this module.355/// Merge the sections making up a function declaration into this module.
...@@ -501,23 +359,17 @@ pub fn addFunction(self: *Module, decl_index: Decl.Index, func: Fn) !void {...@@ -501,23 +359,17 @@ pub fn addFunction(self: *Module, decl_index: Decl.Index, func: Fn) !void {
501 try self.declareDeclDeps(decl_index, func.decl_deps.keys());359 try self.declareDeclDeps(decl_index, func.decl_deps.keys());
502}360}
503361
504pub const ExtendedInstructionSet = enum {
505 glsl,
506 opencl,
507};
508
509/// Imports or returns the existing id of an extended instruction set362/// Imports or returns the existing id of an extended instruction set
510pub fn importInstructionSet(self: *Module, set: ExtendedInstructionSet) !IdRef {363pub fn importInstructionSet(self: *Module, set: spec.InstructionSet) !IdRef {
364 assert(set != .core);
365
511 const gop = try self.extended_instruction_set.getOrPut(self.gpa, set);366 const gop = try self.extended_instruction_set.getOrPut(self.gpa, set);
512 if (gop.found_existing) return gop.value_ptr.*;367 if (gop.found_existing) return gop.value_ptr.*;
513368
514 const result_id = self.allocId();369 const result_id = self.allocId();
515 try self.sections.extended_instruction_set.emit(self.gpa, .OpExtInstImport, .{370 try self.sections.extended_instruction_set.emit(self.gpa, .OpExtInstImport, .{
516 .id_result = result_id,371 .id_result = result_id,
517 .name = switch (set) {372 .name = @tagName(set),
518 .glsl => "GLSL.std.450",
519 .opencl => "OpenCL.std",
520 },
521 });373 });
522 gop.value_ptr.* = result_id;374 gop.value_ptr.* = result_id;
523375
...@@ -631,40 +483,21 @@ pub fn decorateMember(...@@ -631,40 +483,21 @@ pub fn decorateMember(
631 });483 });
632}484}
633485
634pub const DeclKind = enum {486pub fn allocDecl(self: *Module, kind: Decl.Kind) !Decl.Index {
635 func,
636 global,
637};
638
639pub fn allocDecl(self: *Module, kind: DeclKind) !Decl.Index {
640 try self.decls.append(self.gpa, .{487 try self.decls.append(self.gpa, .{
488 .kind = kind,
641 .result_id = self.allocId(),489 .result_id = self.allocId(),
642 .begin_dep = undefined,490 .begin_dep = undefined,
643 .end_dep = undefined,491 .end_dep = undefined,
644 });492 });
645 const index = @as(Decl.Index, @enumFromInt(@as(u32, @intCast(self.decls.items.len - 1))));
646 switch (kind) {
647 .func => {},
648 // If the decl represents a global, also allocate a global node.
649 .global => try self.globals.globals.putNoClobber(self.gpa, index, .{
650 .result_id = undefined,
651 .begin_inst = undefined,
652 .end_inst = undefined,
653 .initializer_id = undefined,
654 }),
655 }
656493
657 return index;494 return @as(Decl.Index, @enumFromInt(@as(u32, @intCast(self.decls.items.len - 1))));
658}495}
659496
660pub fn declPtr(self: *Module, index: Decl.Index) *Decl {497pub fn declPtr(self: *Module, index: Decl.Index) *Decl {
661 return &self.decls.items[@intFromEnum(index)];498 return &self.decls.items[@intFromEnum(index)];
662}499}
663500
664pub fn globalPtr(self: *Module, index: Decl.Index) ?*Global {
665 return self.globals.globals.getPtr(index);
666}
667
668/// Declare ALL dependencies for a decl.501/// Declare ALL dependencies for a decl.
669pub fn declareDeclDeps(self: *Module, decl_index: Decl.Index, deps: []const Decl.Index) !void {502pub fn declareDeclDeps(self: *Module, decl_index: Decl.Index, deps: []const Decl.Index) !void {
670 const begin_dep = @as(u32, @intCast(self.decl_deps.items.len));503 const begin_dep = @as(u32, @intCast(self.decl_deps.items.len));
...@@ -676,26 +509,9 @@ pub fn declareDeclDeps(self: *Module, decl_index: Decl.Index, deps: []const Decl...@@ -676,26 +509,9 @@ pub fn declareDeclDeps(self: *Module, decl_index: Decl.Index, deps: []const Decl
676 decl.end_dep = end_dep;509 decl.end_dep = end_dep;
677}510}
678511
679pub fn beginGlobal(self: *Module) u32 {512/// Declare a SPIR-V function as an entry point. This causes an extra wrapper
680 return @as(u32, @intCast(self.globals.section.instructions.items.len));513/// function to be generated, which is then exported as the real entry point. The purpose of this
681}514/// wrapper is to allocate and initialize the structure holding the instance globals.
682
683pub fn endGlobal(
684 self: *Module,
685 global_index: Decl.Index,
686 begin_inst: u32,
687 result_id: IdRef,
688 initializer_id: ?IdRef,
689) void {
690 const global = self.globalPtr(global_index).?;
691 global.* = .{
692 .result_id = result_id,
693 .begin_inst = begin_inst,
694 .end_inst = @intCast(self.globals.section.instructions.items.len),
695 .initializer_id = initializer_id,
696 };
697}
698
699pub fn declareEntryPoint(515pub fn declareEntryPoint(
700 self: *Module,516 self: *Module,
701 decl_index: Decl.Index,517 decl_index: Decl.Index,
src/codegen/spirv/Section.zig+11
...@@ -53,6 +53,17 @@ pub fn emitRaw(...@@ -53,6 +53,17 @@ pub fn emitRaw(
53 section.writeWord((@as(Word, @intCast(word_count << 16))) | @intFromEnum(opcode));53 section.writeWord((@as(Word, @intCast(word_count << 16))) | @intFromEnum(opcode));
54}54}
5555
56/// Write an entire instruction, including all operands
57pub fn emitRawInstruction(
58 section: *Section,
59 allocator: Allocator,
60 opcode: Opcode,
61 operands: []const Word,
62) !void {
63 try section.emitRaw(allocator, opcode, operands.len);
64 section.writeWords(operands);
65}
66
56pub fn emit(67pub fn emit(
57 section: *Section,68 section: *Section,
58 allocator: Allocator,69 allocator: Allocator,
src/codegen/spirv/spec.zig+147-132
...@@ -1,5 +1,7 @@...@@ -1,5 +1,7 @@
1//! This file is auto-generated by tools/gen_spirv_spec.zig.1//! This file is auto-generated by tools/gen_spirv_spec.zig.
22
3const std = @import("std");
4
3pub const Version = packed struct(Word) {5pub const Version = packed struct(Word) {
4 padding: u8 = 0,6 padding: u8 = 0,
5 minor: u8,7 minor: u8,
...@@ -15,6 +17,18 @@ pub const Word = u32;...@@ -15,6 +17,18 @@ pub const Word = u32;
15pub const IdResult = enum(Word) {17pub const IdResult = enum(Word) {
16 none,18 none,
17 _,19 _,
20
21 pub fn format(
22 self: IdResult,
23 comptime _: []const u8,
24 _: std.fmt.FormatOptions,
25 writer: anytype,
26 ) @TypeOf(writer).Error!void {
27 switch (self) {
28 .none => try writer.writeAll("(none)"),
29 else => try writer.print("%{}", .{@intFromEnum(self)}),
30 }
31 }
18};32};
19pub const IdResultType = IdResult;33pub const IdResultType = IdResult;
20pub const IdRef = IdResult;34pub const IdRef = IdResult;
...@@ -70,6 +84,7 @@ pub const Instruction = struct {...@@ -70,6 +84,7 @@ pub const Instruction = struct {
70 operands: []const Operand,84 operands: []const Operand,
71};85};
7286
87pub const zig_generator_id: Word = 41;
73pub const version = Version{ .major = 1, .minor = 6, .patch = 1 };88pub const version = Version{ .major = 1, .minor = 6, .patch = 1 };
74pub const magic_number: Word = 0x07230203;89pub const magic_number: Word = 0x07230203;
7590
...@@ -166,25 +181,25 @@ pub const OperandKind = enum {...@@ -166,25 +181,25 @@ pub const OperandKind = enum {
166 PairLiteralIntegerIdRef,181 PairLiteralIntegerIdRef,
167 PairIdRefLiteralInteger,182 PairIdRefLiteralInteger,
168 PairIdRefIdRef,183 PairIdRefIdRef,
169 @"opencl.debuginfo.100.DebugInfoFlags",184 @"OpenCL.DebugInfo.100.DebugInfoFlags",
170 @"opencl.debuginfo.100.DebugBaseTypeAttributeEncoding",185 @"OpenCL.DebugInfo.100.DebugBaseTypeAttributeEncoding",
171 @"opencl.debuginfo.100.DebugCompositeType",186 @"OpenCL.DebugInfo.100.DebugCompositeType",
172 @"opencl.debuginfo.100.DebugTypeQualifier",187 @"OpenCL.DebugInfo.100.DebugTypeQualifier",
173 @"opencl.debuginfo.100.DebugOperation",188 @"OpenCL.DebugInfo.100.DebugOperation",
174 @"opencl.debuginfo.100.DebugImportedEntity",189 @"OpenCL.DebugInfo.100.DebugImportedEntity",
175 @"nonsemantic.shader.debuginfo.100.DebugInfoFlags",190 @"NonSemantic.Shader.DebugInfo.100.DebugInfoFlags",
176 @"nonsemantic.shader.debuginfo.100.BuildIdentifierFlags",191 @"NonSemantic.Shader.DebugInfo.100.BuildIdentifierFlags",
177 @"nonsemantic.shader.debuginfo.100.DebugBaseTypeAttributeEncoding",192 @"NonSemantic.Shader.DebugInfo.100.DebugBaseTypeAttributeEncoding",
178 @"nonsemantic.shader.debuginfo.100.DebugCompositeType",193 @"NonSemantic.Shader.DebugInfo.100.DebugCompositeType",
179 @"nonsemantic.shader.debuginfo.100.DebugTypeQualifier",194 @"NonSemantic.Shader.DebugInfo.100.DebugTypeQualifier",
180 @"nonsemantic.shader.debuginfo.100.DebugOperation",195 @"NonSemantic.Shader.DebugInfo.100.DebugOperation",
181 @"nonsemantic.shader.debuginfo.100.DebugImportedEntity",196 @"NonSemantic.Shader.DebugInfo.100.DebugImportedEntity",
182 @"nonsemantic.clspvreflection.KernelPropertyFlags",197 @"NonSemantic.ClspvReflection.6.KernelPropertyFlags",
183 @"debuginfo.DebugInfoFlags",198 @"DebugInfo.DebugInfoFlags",
184 @"debuginfo.DebugBaseTypeAttributeEncoding",199 @"DebugInfo.DebugBaseTypeAttributeEncoding",
185 @"debuginfo.DebugCompositeType",200 @"DebugInfo.DebugCompositeType",
186 @"debuginfo.DebugTypeQualifier",201 @"DebugInfo.DebugTypeQualifier",
187 @"debuginfo.DebugOperation",202 @"DebugInfo.DebugOperation",
188203
189 pub fn category(self: OperandKind) OperandCategory {204 pub fn category(self: OperandKind) OperandCategory {
190 return switch (self) {205 return switch (self) {
...@@ -252,25 +267,25 @@ pub const OperandKind = enum {...@@ -252,25 +267,25 @@ pub const OperandKind = enum {
252 .PairLiteralIntegerIdRef => .composite,267 .PairLiteralIntegerIdRef => .composite,
253 .PairIdRefLiteralInteger => .composite,268 .PairIdRefLiteralInteger => .composite,
254 .PairIdRefIdRef => .composite,269 .PairIdRefIdRef => .composite,
255 .@"opencl.debuginfo.100.DebugInfoFlags" => .bit_enum,270 .@"OpenCL.DebugInfo.100.DebugInfoFlags" => .bit_enum,
256 .@"opencl.debuginfo.100.DebugBaseTypeAttributeEncoding" => .value_enum,271 .@"OpenCL.DebugInfo.100.DebugBaseTypeAttributeEncoding" => .value_enum,
257 .@"opencl.debuginfo.100.DebugCompositeType" => .value_enum,272 .@"OpenCL.DebugInfo.100.DebugCompositeType" => .value_enum,
258 .@"opencl.debuginfo.100.DebugTypeQualifier" => .value_enum,273 .@"OpenCL.DebugInfo.100.DebugTypeQualifier" => .value_enum,
259 .@"opencl.debuginfo.100.DebugOperation" => .value_enum,274 .@"OpenCL.DebugInfo.100.DebugOperation" => .value_enum,
260 .@"opencl.debuginfo.100.DebugImportedEntity" => .value_enum,275 .@"OpenCL.DebugInfo.100.DebugImportedEntity" => .value_enum,
261 .@"nonsemantic.shader.debuginfo.100.DebugInfoFlags" => .bit_enum,276 .@"NonSemantic.Shader.DebugInfo.100.DebugInfoFlags" => .bit_enum,
262 .@"nonsemantic.shader.debuginfo.100.BuildIdentifierFlags" => .bit_enum,277 .@"NonSemantic.Shader.DebugInfo.100.BuildIdentifierFlags" => .bit_enum,
263 .@"nonsemantic.shader.debuginfo.100.DebugBaseTypeAttributeEncoding" => .value_enum,278 .@"NonSemantic.Shader.DebugInfo.100.DebugBaseTypeAttributeEncoding" => .value_enum,
264 .@"nonsemantic.shader.debuginfo.100.DebugCompositeType" => .value_enum,279 .@"NonSemantic.Shader.DebugInfo.100.DebugCompositeType" => .value_enum,
265 .@"nonsemantic.shader.debuginfo.100.DebugTypeQualifier" => .value_enum,280 .@"NonSemantic.Shader.DebugInfo.100.DebugTypeQualifier" => .value_enum,
266 .@"nonsemantic.shader.debuginfo.100.DebugOperation" => .value_enum,281 .@"NonSemantic.Shader.DebugInfo.100.DebugOperation" => .value_enum,
267 .@"nonsemantic.shader.debuginfo.100.DebugImportedEntity" => .value_enum,282 .@"NonSemantic.Shader.DebugInfo.100.DebugImportedEntity" => .value_enum,
268 .@"nonsemantic.clspvreflection.KernelPropertyFlags" => .bit_enum,283 .@"NonSemantic.ClspvReflection.6.KernelPropertyFlags" => .bit_enum,
269 .@"debuginfo.DebugInfoFlags" => .bit_enum,284 .@"DebugInfo.DebugInfoFlags" => .bit_enum,
270 .@"debuginfo.DebugBaseTypeAttributeEncoding" => .value_enum,285 .@"DebugInfo.DebugBaseTypeAttributeEncoding" => .value_enum,
271 .@"debuginfo.DebugCompositeType" => .value_enum,286 .@"DebugInfo.DebugCompositeType" => .value_enum,
272 .@"debuginfo.DebugTypeQualifier" => .value_enum,287 .@"DebugInfo.DebugTypeQualifier" => .value_enum,
273 .@"debuginfo.DebugOperation" => .value_enum,288 .@"DebugInfo.DebugOperation" => .value_enum,
274 };289 };
275 }290 }
276 pub fn enumerants(self: OperandKind) []const Enumerant {291 pub fn enumerants(self: OperandKind) []const Enumerant {
...@@ -1395,7 +1410,7 @@ pub const OperandKind = enum {...@@ -1395,7 +1410,7 @@ pub const OperandKind = enum {
1395 .PairLiteralIntegerIdRef => unreachable,1410 .PairLiteralIntegerIdRef => unreachable,
1396 .PairIdRefLiteralInteger => unreachable,1411 .PairIdRefLiteralInteger => unreachable,
1397 .PairIdRefIdRef => unreachable,1412 .PairIdRefIdRef => unreachable,
1398 .@"opencl.debuginfo.100.DebugInfoFlags" => &[_]Enumerant{1413 .@"OpenCL.DebugInfo.100.DebugInfoFlags" => &[_]Enumerant{
1399 .{ .name = "FlagIsProtected", .value = 0x01, .parameters = &[_]OperandKind{} },1414 .{ .name = "FlagIsProtected", .value = 0x01, .parameters = &[_]OperandKind{} },
1400 .{ .name = "FlagIsPrivate", .value = 0x02, .parameters = &[_]OperandKind{} },1415 .{ .name = "FlagIsPrivate", .value = 0x02, .parameters = &[_]OperandKind{} },
1401 .{ .name = "FlagIsPublic", .value = 0x03, .parameters = &[_]OperandKind{} },1416 .{ .name = "FlagIsPublic", .value = 0x03, .parameters = &[_]OperandKind{} },
...@@ -1415,7 +1430,7 @@ pub const OperandKind = enum {...@@ -1415,7 +1430,7 @@ pub const OperandKind = enum {
1415 .{ .name = "FlagTypePassByValue", .value = 0x8000, .parameters = &[_]OperandKind{} },1430 .{ .name = "FlagTypePassByValue", .value = 0x8000, .parameters = &[_]OperandKind{} },
1416 .{ .name = "FlagTypePassByReference", .value = 0x10000, .parameters = &[_]OperandKind{} },1431 .{ .name = "FlagTypePassByReference", .value = 0x10000, .parameters = &[_]OperandKind{} },
1417 },1432 },
1418 .@"opencl.debuginfo.100.DebugBaseTypeAttributeEncoding" => &[_]Enumerant{1433 .@"OpenCL.DebugInfo.100.DebugBaseTypeAttributeEncoding" => &[_]Enumerant{
1419 .{ .name = "Unspecified", .value = 0, .parameters = &[_]OperandKind{} },1434 .{ .name = "Unspecified", .value = 0, .parameters = &[_]OperandKind{} },
1420 .{ .name = "Address", .value = 1, .parameters = &[_]OperandKind{} },1435 .{ .name = "Address", .value = 1, .parameters = &[_]OperandKind{} },
1421 .{ .name = "Boolean", .value = 2, .parameters = &[_]OperandKind{} },1436 .{ .name = "Boolean", .value = 2, .parameters = &[_]OperandKind{} },
...@@ -1425,18 +1440,18 @@ pub const OperandKind = enum {...@@ -1425,18 +1440,18 @@ pub const OperandKind = enum {
1425 .{ .name = "Unsigned", .value = 6, .parameters = &[_]OperandKind{} },1440 .{ .name = "Unsigned", .value = 6, .parameters = &[_]OperandKind{} },
1426 .{ .name = "UnsignedChar", .value = 7, .parameters = &[_]OperandKind{} },1441 .{ .name = "UnsignedChar", .value = 7, .parameters = &[_]OperandKind{} },
1427 },1442 },
1428 .@"opencl.debuginfo.100.DebugCompositeType" => &[_]Enumerant{1443 .@"OpenCL.DebugInfo.100.DebugCompositeType" => &[_]Enumerant{
1429 .{ .name = "Class", .value = 0, .parameters = &[_]OperandKind{} },1444 .{ .name = "Class", .value = 0, .parameters = &[_]OperandKind{} },
1430 .{ .name = "Structure", .value = 1, .parameters = &[_]OperandKind{} },1445 .{ .name = "Structure", .value = 1, .parameters = &[_]OperandKind{} },
1431 .{ .name = "Union", .value = 2, .parameters = &[_]OperandKind{} },1446 .{ .name = "Union", .value = 2, .parameters = &[_]OperandKind{} },
1432 },1447 },
1433 .@"opencl.debuginfo.100.DebugTypeQualifier" => &[_]Enumerant{1448 .@"OpenCL.DebugInfo.100.DebugTypeQualifier" => &[_]Enumerant{
1434 .{ .name = "ConstType", .value = 0, .parameters = &[_]OperandKind{} },1449 .{ .name = "ConstType", .value = 0, .parameters = &[_]OperandKind{} },
1435 .{ .name = "VolatileType", .value = 1, .parameters = &[_]OperandKind{} },1450 .{ .name = "VolatileType", .value = 1, .parameters = &[_]OperandKind{} },
1436 .{ .name = "RestrictType", .value = 2, .parameters = &[_]OperandKind{} },1451 .{ .name = "RestrictType", .value = 2, .parameters = &[_]OperandKind{} },
1437 .{ .name = "AtomicType", .value = 3, .parameters = &[_]OperandKind{} },1452 .{ .name = "AtomicType", .value = 3, .parameters = &[_]OperandKind{} },
1438 },1453 },
1439 .@"opencl.debuginfo.100.DebugOperation" => &[_]Enumerant{1454 .@"OpenCL.DebugInfo.100.DebugOperation" => &[_]Enumerant{
1440 .{ .name = "Deref", .value = 0, .parameters = &[_]OperandKind{} },1455 .{ .name = "Deref", .value = 0, .parameters = &[_]OperandKind{} },
1441 .{ .name = "Plus", .value = 1, .parameters = &[_]OperandKind{} },1456 .{ .name = "Plus", .value = 1, .parameters = &[_]OperandKind{} },
1442 .{ .name = "Minus", .value = 2, .parameters = &[_]OperandKind{} },1457 .{ .name = "Minus", .value = 2, .parameters = &[_]OperandKind{} },
...@@ -1448,11 +1463,11 @@ pub const OperandKind = enum {...@@ -1448,11 +1463,11 @@ pub const OperandKind = enum {
1448 .{ .name = "Constu", .value = 8, .parameters = &[_]OperandKind{.LiteralInteger} },1463 .{ .name = "Constu", .value = 8, .parameters = &[_]OperandKind{.LiteralInteger} },
1449 .{ .name = "Fragment", .value = 9, .parameters = &[_]OperandKind{ .LiteralInteger, .LiteralInteger } },1464 .{ .name = "Fragment", .value = 9, .parameters = &[_]OperandKind{ .LiteralInteger, .LiteralInteger } },
1450 },1465 },
1451 .@"opencl.debuginfo.100.DebugImportedEntity" => &[_]Enumerant{1466 .@"OpenCL.DebugInfo.100.DebugImportedEntity" => &[_]Enumerant{
1452 .{ .name = "ImportedModule", .value = 0, .parameters = &[_]OperandKind{} },1467 .{ .name = "ImportedModule", .value = 0, .parameters = &[_]OperandKind{} },
1453 .{ .name = "ImportedDeclaration", .value = 1, .parameters = &[_]OperandKind{} },1468 .{ .name = "ImportedDeclaration", .value = 1, .parameters = &[_]OperandKind{} },
1454 },1469 },
1455 .@"nonsemantic.shader.debuginfo.100.DebugInfoFlags" => &[_]Enumerant{1470 .@"NonSemantic.Shader.DebugInfo.100.DebugInfoFlags" => &[_]Enumerant{
1456 .{ .name = "FlagIsProtected", .value = 0x01, .parameters = &[_]OperandKind{} },1471 .{ .name = "FlagIsProtected", .value = 0x01, .parameters = &[_]OperandKind{} },
1457 .{ .name = "FlagIsPrivate", .value = 0x02, .parameters = &[_]OperandKind{} },1472 .{ .name = "FlagIsPrivate", .value = 0x02, .parameters = &[_]OperandKind{} },
1458 .{ .name = "FlagIsPublic", .value = 0x03, .parameters = &[_]OperandKind{} },1473 .{ .name = "FlagIsPublic", .value = 0x03, .parameters = &[_]OperandKind{} },
...@@ -1473,10 +1488,10 @@ pub const OperandKind = enum {...@@ -1473,10 +1488,10 @@ pub const OperandKind = enum {
1473 .{ .name = "FlagTypePassByReference", .value = 0x10000, .parameters = &[_]OperandKind{} },1488 .{ .name = "FlagTypePassByReference", .value = 0x10000, .parameters = &[_]OperandKind{} },
1474 .{ .name = "FlagUnknownPhysicalLayout", .value = 0x20000, .parameters = &[_]OperandKind{} },1489 .{ .name = "FlagUnknownPhysicalLayout", .value = 0x20000, .parameters = &[_]OperandKind{} },
1475 },1490 },
1476 .@"nonsemantic.shader.debuginfo.100.BuildIdentifierFlags" => &[_]Enumerant{1491 .@"NonSemantic.Shader.DebugInfo.100.BuildIdentifierFlags" => &[_]Enumerant{
1477 .{ .name = "IdentifierPossibleDuplicates", .value = 0x01, .parameters = &[_]OperandKind{} },1492 .{ .name = "IdentifierPossibleDuplicates", .value = 0x01, .parameters = &[_]OperandKind{} },
1478 },1493 },
1479 .@"nonsemantic.shader.debuginfo.100.DebugBaseTypeAttributeEncoding" => &[_]Enumerant{1494 .@"NonSemantic.Shader.DebugInfo.100.DebugBaseTypeAttributeEncoding" => &[_]Enumerant{
1480 .{ .name = "Unspecified", .value = 0, .parameters = &[_]OperandKind{} },1495 .{ .name = "Unspecified", .value = 0, .parameters = &[_]OperandKind{} },
1481 .{ .name = "Address", .value = 1, .parameters = &[_]OperandKind{} },1496 .{ .name = "Address", .value = 1, .parameters = &[_]OperandKind{} },
1482 .{ .name = "Boolean", .value = 2, .parameters = &[_]OperandKind{} },1497 .{ .name = "Boolean", .value = 2, .parameters = &[_]OperandKind{} },
...@@ -1486,18 +1501,18 @@ pub const OperandKind = enum {...@@ -1486,18 +1501,18 @@ pub const OperandKind = enum {
1486 .{ .name = "Unsigned", .value = 6, .parameters = &[_]OperandKind{} },1501 .{ .name = "Unsigned", .value = 6, .parameters = &[_]OperandKind{} },
1487 .{ .name = "UnsignedChar", .value = 7, .parameters = &[_]OperandKind{} },1502 .{ .name = "UnsignedChar", .value = 7, .parameters = &[_]OperandKind{} },
1488 },1503 },
1489 .@"nonsemantic.shader.debuginfo.100.DebugCompositeType" => &[_]Enumerant{1504 .@"NonSemantic.Shader.DebugInfo.100.DebugCompositeType" => &[_]Enumerant{
1490 .{ .name = "Class", .value = 0, .parameters = &[_]OperandKind{} },1505 .{ .name = "Class", .value = 0, .parameters = &[_]OperandKind{} },
1491 .{ .name = "Structure", .value = 1, .parameters = &[_]OperandKind{} },1506 .{ .name = "Structure", .value = 1, .parameters = &[_]OperandKind{} },
1492 .{ .name = "Union", .value = 2, .parameters = &[_]OperandKind{} },1507 .{ .name = "Union", .value = 2, .parameters = &[_]OperandKind{} },
1493 },1508 },
1494 .@"nonsemantic.shader.debuginfo.100.DebugTypeQualifier" => &[_]Enumerant{1509 .@"NonSemantic.Shader.DebugInfo.100.DebugTypeQualifier" => &[_]Enumerant{
1495 .{ .name = "ConstType", .value = 0, .parameters = &[_]OperandKind{} },1510 .{ .name = "ConstType", .value = 0, .parameters = &[_]OperandKind{} },
1496 .{ .name = "VolatileType", .value = 1, .parameters = &[_]OperandKind{} },1511 .{ .name = "VolatileType", .value = 1, .parameters = &[_]OperandKind{} },
1497 .{ .name = "RestrictType", .value = 2, .parameters = &[_]OperandKind{} },1512 .{ .name = "RestrictType", .value = 2, .parameters = &[_]OperandKind{} },
1498 .{ .name = "AtomicType", .value = 3, .parameters = &[_]OperandKind{} },1513 .{ .name = "AtomicType", .value = 3, .parameters = &[_]OperandKind{} },
1499 },1514 },
1500 .@"nonsemantic.shader.debuginfo.100.DebugOperation" => &[_]Enumerant{1515 .@"NonSemantic.Shader.DebugInfo.100.DebugOperation" => &[_]Enumerant{
1501 .{ .name = "Deref", .value = 0, .parameters = &[_]OperandKind{} },1516 .{ .name = "Deref", .value = 0, .parameters = &[_]OperandKind{} },
1502 .{ .name = "Plus", .value = 1, .parameters = &[_]OperandKind{} },1517 .{ .name = "Plus", .value = 1, .parameters = &[_]OperandKind{} },
1503 .{ .name = "Minus", .value = 2, .parameters = &[_]OperandKind{} },1518 .{ .name = "Minus", .value = 2, .parameters = &[_]OperandKind{} },
...@@ -1509,14 +1524,14 @@ pub const OperandKind = enum {...@@ -1509,14 +1524,14 @@ pub const OperandKind = enum {
1509 .{ .name = "Constu", .value = 8, .parameters = &[_]OperandKind{.IdRef} },1524 .{ .name = "Constu", .value = 8, .parameters = &[_]OperandKind{.IdRef} },
1510 .{ .name = "Fragment", .value = 9, .parameters = &[_]OperandKind{ .IdRef, .IdRef } },1525 .{ .name = "Fragment", .value = 9, .parameters = &[_]OperandKind{ .IdRef, .IdRef } },
1511 },1526 },
1512 .@"nonsemantic.shader.debuginfo.100.DebugImportedEntity" => &[_]Enumerant{1527 .@"NonSemantic.Shader.DebugInfo.100.DebugImportedEntity" => &[_]Enumerant{
1513 .{ .name = "ImportedModule", .value = 0, .parameters = &[_]OperandKind{} },1528 .{ .name = "ImportedModule", .value = 0, .parameters = &[_]OperandKind{} },
1514 .{ .name = "ImportedDeclaration", .value = 1, .parameters = &[_]OperandKind{} },1529 .{ .name = "ImportedDeclaration", .value = 1, .parameters = &[_]OperandKind{} },
1515 },1530 },
1516 .@"nonsemantic.clspvreflection.KernelPropertyFlags" => &[_]Enumerant{1531 .@"NonSemantic.ClspvReflection.6.KernelPropertyFlags" => &[_]Enumerant{
1517 .{ .name = "MayUsePrintf", .value = 0x1, .parameters = &[_]OperandKind{} },1532 .{ .name = "MayUsePrintf", .value = 0x1, .parameters = &[_]OperandKind{} },
1518 },1533 },
1519 .@"debuginfo.DebugInfoFlags" => &[_]Enumerant{1534 .@"DebugInfo.DebugInfoFlags" => &[_]Enumerant{
1520 .{ .name = "FlagIsProtected", .value = 0x01, .parameters = &[_]OperandKind{} },1535 .{ .name = "FlagIsProtected", .value = 0x01, .parameters = &[_]OperandKind{} },
1521 .{ .name = "FlagIsPrivate", .value = 0x02, .parameters = &[_]OperandKind{} },1536 .{ .name = "FlagIsPrivate", .value = 0x02, .parameters = &[_]OperandKind{} },
1522 .{ .name = "FlagIsPublic", .value = 0x03, .parameters = &[_]OperandKind{} },1537 .{ .name = "FlagIsPublic", .value = 0x03, .parameters = &[_]OperandKind{} },
...@@ -1533,7 +1548,7 @@ pub const OperandKind = enum {...@@ -1533,7 +1548,7 @@ pub const OperandKind = enum {
1533 .{ .name = "FlagRValueReference", .value = 0x1000, .parameters = &[_]OperandKind{} },1548 .{ .name = "FlagRValueReference", .value = 0x1000, .parameters = &[_]OperandKind{} },
1534 .{ .name = "FlagIsOptimized", .value = 0x2000, .parameters = &[_]OperandKind{} },1549 .{ .name = "FlagIsOptimized", .value = 0x2000, .parameters = &[_]OperandKind{} },
1535 },1550 },
1536 .@"debuginfo.DebugBaseTypeAttributeEncoding" => &[_]Enumerant{1551 .@"DebugInfo.DebugBaseTypeAttributeEncoding" => &[_]Enumerant{
1537 .{ .name = "Unspecified", .value = 0, .parameters = &[_]OperandKind{} },1552 .{ .name = "Unspecified", .value = 0, .parameters = &[_]OperandKind{} },
1538 .{ .name = "Address", .value = 1, .parameters = &[_]OperandKind{} },1553 .{ .name = "Address", .value = 1, .parameters = &[_]OperandKind{} },
1539 .{ .name = "Boolean", .value = 2, .parameters = &[_]OperandKind{} },1554 .{ .name = "Boolean", .value = 2, .parameters = &[_]OperandKind{} },
...@@ -1543,17 +1558,17 @@ pub const OperandKind = enum {...@@ -1543,17 +1558,17 @@ pub const OperandKind = enum {
1543 .{ .name = "Unsigned", .value = 7, .parameters = &[_]OperandKind{} },1558 .{ .name = "Unsigned", .value = 7, .parameters = &[_]OperandKind{} },
1544 .{ .name = "UnsignedChar", .value = 8, .parameters = &[_]OperandKind{} },1559 .{ .name = "UnsignedChar", .value = 8, .parameters = &[_]OperandKind{} },
1545 },1560 },
1546 .@"debuginfo.DebugCompositeType" => &[_]Enumerant{1561 .@"DebugInfo.DebugCompositeType" => &[_]Enumerant{
1547 .{ .name = "Class", .value = 0, .parameters = &[_]OperandKind{} },1562 .{ .name = "Class", .value = 0, .parameters = &[_]OperandKind{} },
1548 .{ .name = "Structure", .value = 1, .parameters = &[_]OperandKind{} },1563 .{ .name = "Structure", .value = 1, .parameters = &[_]OperandKind{} },
1549 .{ .name = "Union", .value = 2, .parameters = &[_]OperandKind{} },1564 .{ .name = "Union", .value = 2, .parameters = &[_]OperandKind{} },
1550 },1565 },
1551 .@"debuginfo.DebugTypeQualifier" => &[_]Enumerant{1566 .@"DebugInfo.DebugTypeQualifier" => &[_]Enumerant{
1552 .{ .name = "ConstType", .value = 0, .parameters = &[_]OperandKind{} },1567 .{ .name = "ConstType", .value = 0, .parameters = &[_]OperandKind{} },
1553 .{ .name = "VolatileType", .value = 1, .parameters = &[_]OperandKind{} },1568 .{ .name = "VolatileType", .value = 1, .parameters = &[_]OperandKind{} },
1554 .{ .name = "RestrictType", .value = 2, .parameters = &[_]OperandKind{} },1569 .{ .name = "RestrictType", .value = 2, .parameters = &[_]OperandKind{} },
1555 },1570 },
1556 .@"debuginfo.DebugOperation" => &[_]Enumerant{1571 .@"DebugInfo.DebugOperation" => &[_]Enumerant{
1557 .{ .name = "Deref", .value = 0, .parameters = &[_]OperandKind{} },1572 .{ .name = "Deref", .value = 0, .parameters = &[_]OperandKind{} },
1558 .{ .name = "Plus", .value = 1, .parameters = &[_]OperandKind{} },1573 .{ .name = "Plus", .value = 1, .parameters = &[_]OperandKind{} },
1559 .{ .name = "Minus", .value = 2, .parameters = &[_]OperandKind{} },1574 .{ .name = "Minus", .value = 2, .parameters = &[_]OperandKind{} },
...@@ -4952,7 +4967,7 @@ pub const StoreCacheControl = enum(u32) {...@@ -4952,7 +4967,7 @@ pub const StoreCacheControl = enum(u32) {
4952pub const NamedMaximumNumberOfRegisters = enum(u32) {4967pub const NamedMaximumNumberOfRegisters = enum(u32) {
4953 AutoINTEL = 0,4968 AutoINTEL = 0,
4954};4969};
4955pub const @"opencl.debuginfo.100.DebugInfoFlags" = packed struct {4970pub const @"OpenCL.DebugInfo.100.DebugInfoFlags" = packed struct {
4956 FlagIsProtected: bool = false,4971 FlagIsProtected: bool = false,
4957 FlagIsPrivate: bool = false,4972 FlagIsPrivate: bool = false,
4958 FlagIsLocal: bool = false,4973 FlagIsLocal: bool = false,
...@@ -4986,7 +5001,7 @@ pub const @"opencl.debuginfo.100.DebugInfoFlags" = packed struct {...@@ -4986,7 +5001,7 @@ pub const @"opencl.debuginfo.100.DebugInfoFlags" = packed struct {
4986 _reserved_bit_30: bool = false,5001 _reserved_bit_30: bool = false,
4987 _reserved_bit_31: bool = false,5002 _reserved_bit_31: bool = false,
4988};5003};
4989pub const @"opencl.debuginfo.100.DebugBaseTypeAttributeEncoding" = enum(u32) {5004pub const @"OpenCL.DebugInfo.100.DebugBaseTypeAttributeEncoding" = enum(u32) {
4990 Unspecified = 0,5005 Unspecified = 0,
4991 Address = 1,5006 Address = 1,
4992 Boolean = 2,5007 Boolean = 2,
...@@ -4996,18 +5011,18 @@ pub const @"opencl.debuginfo.100.DebugBaseTypeAttributeEncoding" = enum(u32) {...@@ -4996,18 +5011,18 @@ pub const @"opencl.debuginfo.100.DebugBaseTypeAttributeEncoding" = enum(u32) {
4996 Unsigned = 6,5011 Unsigned = 6,
4997 UnsignedChar = 7,5012 UnsignedChar = 7,
4998};5013};
4999pub const @"opencl.debuginfo.100.DebugCompositeType" = enum(u32) {5014pub const @"OpenCL.DebugInfo.100.DebugCompositeType" = enum(u32) {
5000 Class = 0,5015 Class = 0,
5001 Structure = 1,5016 Structure = 1,
5002 Union = 2,5017 Union = 2,
5003};5018};
5004pub const @"opencl.debuginfo.100.DebugTypeQualifier" = enum(u32) {5019pub const @"OpenCL.DebugInfo.100.DebugTypeQualifier" = enum(u32) {
5005 ConstType = 0,5020 ConstType = 0,
5006 VolatileType = 1,5021 VolatileType = 1,
5007 RestrictType = 2,5022 RestrictType = 2,
5008 AtomicType = 3,5023 AtomicType = 3,
5009};5024};
5010pub const @"opencl.debuginfo.100.DebugOperation" = enum(u32) {5025pub const @"OpenCL.DebugInfo.100.DebugOperation" = enum(u32) {
5011 Deref = 0,5026 Deref = 0,
5012 Plus = 1,5027 Plus = 1,
5013 Minus = 2,5028 Minus = 2,
...@@ -5019,7 +5034,7 @@ pub const @"opencl.debuginfo.100.DebugOperation" = enum(u32) {...@@ -5019,7 +5034,7 @@ pub const @"opencl.debuginfo.100.DebugOperation" = enum(u32) {
5019 Constu = 8,5034 Constu = 8,
5020 Fragment = 9,5035 Fragment = 9,
50215036
5022 pub const Extended = union(@"opencl.debuginfo.100.DebugOperation") {5037 pub const Extended = union(@"OpenCL.DebugInfo.100.DebugOperation") {
5023 Deref,5038 Deref,
5024 Plus,5039 Plus,
5025 Minus,5040 Minus,
...@@ -5032,11 +5047,11 @@ pub const @"opencl.debuginfo.100.DebugOperation" = enum(u32) {...@@ -5032,11 +5047,11 @@ pub const @"opencl.debuginfo.100.DebugOperation" = enum(u32) {
5032 Fragment: struct { literal_integer_0: LiteralInteger, literal_integer_1: LiteralInteger },5047 Fragment: struct { literal_integer_0: LiteralInteger, literal_integer_1: LiteralInteger },
5033 };5048 };
5034};5049};
5035pub const @"opencl.debuginfo.100.DebugImportedEntity" = enum(u32) {5050pub const @"OpenCL.DebugInfo.100.DebugImportedEntity" = enum(u32) {
5036 ImportedModule = 0,5051 ImportedModule = 0,
5037 ImportedDeclaration = 1,5052 ImportedDeclaration = 1,
5038};5053};
5039pub const @"nonsemantic.shader.debuginfo.100.DebugInfoFlags" = packed struct {5054pub const @"NonSemantic.Shader.DebugInfo.100.DebugInfoFlags" = packed struct {
5040 FlagIsProtected: bool = false,5055 FlagIsProtected: bool = false,
5041 FlagIsPrivate: bool = false,5056 FlagIsPrivate: bool = false,
5042 FlagIsLocal: bool = false,5057 FlagIsLocal: bool = false,
...@@ -5070,7 +5085,7 @@ pub const @"nonsemantic.shader.debuginfo.100.DebugInfoFlags" = packed struct {...@@ -5070,7 +5085,7 @@ pub const @"nonsemantic.shader.debuginfo.100.DebugInfoFlags" = packed struct {
5070 _reserved_bit_30: bool = false,5085 _reserved_bit_30: bool = false,
5071 _reserved_bit_31: bool = false,5086 _reserved_bit_31: bool = false,
5072};5087};
5073pub const @"nonsemantic.shader.debuginfo.100.BuildIdentifierFlags" = packed struct {5088pub const @"NonSemantic.Shader.DebugInfo.100.BuildIdentifierFlags" = packed struct {
5074 IdentifierPossibleDuplicates: bool = false,5089 IdentifierPossibleDuplicates: bool = false,
5075 _reserved_bit_1: bool = false,5090 _reserved_bit_1: bool = false,
5076 _reserved_bit_2: bool = false,5091 _reserved_bit_2: bool = false,
...@@ -5104,7 +5119,7 @@ pub const @"nonsemantic.shader.debuginfo.100.BuildIdentifierFlags" = packed stru...@@ -5104,7 +5119,7 @@ pub const @"nonsemantic.shader.debuginfo.100.BuildIdentifierFlags" = packed stru
5104 _reserved_bit_30: bool = false,5119 _reserved_bit_30: bool = false,
5105 _reserved_bit_31: bool = false,5120 _reserved_bit_31: bool = false,
5106};5121};
5107pub const @"nonsemantic.shader.debuginfo.100.DebugBaseTypeAttributeEncoding" = enum(u32) {5122pub const @"NonSemantic.Shader.DebugInfo.100.DebugBaseTypeAttributeEncoding" = enum(u32) {
5108 Unspecified = 0,5123 Unspecified = 0,
5109 Address = 1,5124 Address = 1,
5110 Boolean = 2,5125 Boolean = 2,
...@@ -5114,18 +5129,18 @@ pub const @"nonsemantic.shader.debuginfo.100.DebugBaseTypeAttributeEncoding" = e...@@ -5114,18 +5129,18 @@ pub const @"nonsemantic.shader.debuginfo.100.DebugBaseTypeAttributeEncoding" = e
5114 Unsigned = 6,5129 Unsigned = 6,
5115 UnsignedChar = 7,5130 UnsignedChar = 7,
5116};5131};
5117pub const @"nonsemantic.shader.debuginfo.100.DebugCompositeType" = enum(u32) {5132pub const @"NonSemantic.Shader.DebugInfo.100.DebugCompositeType" = enum(u32) {
5118 Class = 0,5133 Class = 0,
5119 Structure = 1,5134 Structure = 1,
5120 Union = 2,5135 Union = 2,
5121};5136};
5122pub const @"nonsemantic.shader.debuginfo.100.DebugTypeQualifier" = enum(u32) {5137pub const @"NonSemantic.Shader.DebugInfo.100.DebugTypeQualifier" = enum(u32) {
5123 ConstType = 0,5138 ConstType = 0,
5124 VolatileType = 1,5139 VolatileType = 1,
5125 RestrictType = 2,5140 RestrictType = 2,
5126 AtomicType = 3,5141 AtomicType = 3,
5127};5142};
5128pub const @"nonsemantic.shader.debuginfo.100.DebugOperation" = enum(u32) {5143pub const @"NonSemantic.Shader.DebugInfo.100.DebugOperation" = enum(u32) {
5129 Deref = 0,5144 Deref = 0,
5130 Plus = 1,5145 Plus = 1,
5131 Minus = 2,5146 Minus = 2,
...@@ -5137,7 +5152,7 @@ pub const @"nonsemantic.shader.debuginfo.100.DebugOperation" = enum(u32) {...@@ -5137,7 +5152,7 @@ pub const @"nonsemantic.shader.debuginfo.100.DebugOperation" = enum(u32) {
5137 Constu = 8,5152 Constu = 8,
5138 Fragment = 9,5153 Fragment = 9,
51395154
5140 pub const Extended = union(@"nonsemantic.shader.debuginfo.100.DebugOperation") {5155 pub const Extended = union(@"NonSemantic.Shader.DebugInfo.100.DebugOperation") {
5141 Deref,5156 Deref,
5142 Plus,5157 Plus,
5143 Minus,5158 Minus,
...@@ -5150,11 +5165,11 @@ pub const @"nonsemantic.shader.debuginfo.100.DebugOperation" = enum(u32) {...@@ -5150,11 +5165,11 @@ pub const @"nonsemantic.shader.debuginfo.100.DebugOperation" = enum(u32) {
5150 Fragment: struct { id_ref_0: IdRef, id_ref_1: IdRef },5165 Fragment: struct { id_ref_0: IdRef, id_ref_1: IdRef },
5151 };5166 };
5152};5167};
5153pub const @"nonsemantic.shader.debuginfo.100.DebugImportedEntity" = enum(u32) {5168pub const @"NonSemantic.Shader.DebugInfo.100.DebugImportedEntity" = enum(u32) {
5154 ImportedModule = 0,5169 ImportedModule = 0,
5155 ImportedDeclaration = 1,5170 ImportedDeclaration = 1,
5156};5171};
5157pub const @"nonsemantic.clspvreflection.KernelPropertyFlags" = packed struct {5172pub const @"NonSemantic.ClspvReflection.6.KernelPropertyFlags" = packed struct {
5158 MayUsePrintf: bool = false,5173 MayUsePrintf: bool = false,
5159 _reserved_bit_1: bool = false,5174 _reserved_bit_1: bool = false,
5160 _reserved_bit_2: bool = false,5175 _reserved_bit_2: bool = false,
...@@ -5188,7 +5203,7 @@ pub const @"nonsemantic.clspvreflection.KernelPropertyFlags" = packed struct {...@@ -5188,7 +5203,7 @@ pub const @"nonsemantic.clspvreflection.KernelPropertyFlags" = packed struct {
5188 _reserved_bit_30: bool = false,5203 _reserved_bit_30: bool = false,
5189 _reserved_bit_31: bool = false,5204 _reserved_bit_31: bool = false,
5190};5205};
5191pub const @"debuginfo.DebugInfoFlags" = packed struct {5206pub const @"DebugInfo.DebugInfoFlags" = packed struct {
5192 FlagIsProtected: bool = false,5207 FlagIsProtected: bool = false,
5193 FlagIsPrivate: bool = false,5208 FlagIsPrivate: bool = false,
5194 FlagIsLocal: bool = false,5209 FlagIsLocal: bool = false,
...@@ -5222,7 +5237,7 @@ pub const @"debuginfo.DebugInfoFlags" = packed struct {...@@ -5222,7 +5237,7 @@ pub const @"debuginfo.DebugInfoFlags" = packed struct {
5222 _reserved_bit_30: bool = false,5237 _reserved_bit_30: bool = false,
5223 _reserved_bit_31: bool = false,5238 _reserved_bit_31: bool = false,
5224};5239};
5225pub const @"debuginfo.DebugBaseTypeAttributeEncoding" = enum(u32) {5240pub const @"DebugInfo.DebugBaseTypeAttributeEncoding" = enum(u32) {
5226 Unspecified = 0,5241 Unspecified = 0,
5227 Address = 1,5242 Address = 1,
5228 Boolean = 2,5243 Boolean = 2,
...@@ -5232,17 +5247,17 @@ pub const @"debuginfo.DebugBaseTypeAttributeEncoding" = enum(u32) {...@@ -5232,17 +5247,17 @@ pub const @"debuginfo.DebugBaseTypeAttributeEncoding" = enum(u32) {
5232 Unsigned = 7,5247 Unsigned = 7,
5233 UnsignedChar = 8,5248 UnsignedChar = 8,
5234};5249};
5235pub const @"debuginfo.DebugCompositeType" = enum(u32) {5250pub const @"DebugInfo.DebugCompositeType" = enum(u32) {
5236 Class = 0,5251 Class = 0,
5237 Structure = 1,5252 Structure = 1,
5238 Union = 2,5253 Union = 2,
5239};5254};
5240pub const @"debuginfo.DebugTypeQualifier" = enum(u32) {5255pub const @"DebugInfo.DebugTypeQualifier" = enum(u32) {
5241 ConstType = 0,5256 ConstType = 0,
5242 VolatileType = 1,5257 VolatileType = 1,
5243 RestrictType = 2,5258 RestrictType = 2,
5244};5259};
5245pub const @"debuginfo.DebugOperation" = enum(u32) {5260pub const @"DebugInfo.DebugOperation" = enum(u32) {
5246 Deref = 0,5261 Deref = 0,
5247 Plus = 1,5262 Plus = 1,
5248 Minus = 2,5263 Minus = 2,
...@@ -5253,7 +5268,7 @@ pub const @"debuginfo.DebugOperation" = enum(u32) {...@@ -5253,7 +5268,7 @@ pub const @"debuginfo.DebugOperation" = enum(u32) {
5253 StackValue = 7,5268 StackValue = 7,
5254 Constu = 8,5269 Constu = 8,
52555270
5256 pub const Extended = union(@"debuginfo.DebugOperation") {5271 pub const Extended = union(@"DebugInfo.DebugOperation") {
5257 Deref,5272 Deref,
5258 Plus,5273 Plus,
5259 Minus,5274 Minus,
...@@ -5267,19 +5282,19 @@ pub const @"debuginfo.DebugOperation" = enum(u32) {...@@ -5267,19 +5282,19 @@ pub const @"debuginfo.DebugOperation" = enum(u32) {
5267};5282};
5268pub const InstructionSet = enum {5283pub const InstructionSet = enum {
5269 core,5284 core,
5270 @"opencl.std.100",5285 @"OpenCL.std",
5271 @"glsl.std.450",5286 @"GLSL.std.450",
5272 @"opencl.debuginfo.100",5287 @"OpenCL.DebugInfo.100",
5273 @"spv-amd-shader-ballot",5288 SPV_AMD_shader_ballot,
5274 @"nonsemantic.shader.debuginfo.100",5289 @"NonSemantic.Shader.DebugInfo.100",
5275 @"nonsemantic.vkspreflection",5290 @"NonSemantic.VkspReflection",
5276 @"nonsemantic.clspvreflection",5291 @"NonSemantic.ClspvReflection.6",
5277 @"spv-amd-gcn-shader",5292 SPV_AMD_gcn_shader,
5278 @"spv-amd-shader-trinary-minmax",5293 SPV_AMD_shader_trinary_minmax,
5279 debuginfo,5294 DebugInfo,
5280 @"nonsemantic.debugprintf",5295 @"NonSemantic.DebugPrintf",
5281 @"spv-amd-shader-explicit-vertex-parameter",5296 SPV_AMD_shader_explicit_vertex_parameter,
5282 @"nonsemantic.debugbreak",5297 @"NonSemantic.DebugBreak",
5283 zig,5298 zig,
52845299
5285 pub fn instructions(self: InstructionSet) []const Instruction {5300 pub fn instructions(self: InstructionSet) []const Instruction {
...@@ -12775,7 +12790,7 @@ pub const InstructionSet = enum {...@@ -12775,7 +12790,7 @@ pub const InstructionSet = enum {
12775 },12790 },
12776 },12791 },
12777 },12792 },
12778 .@"opencl.std.100" => &[_]Instruction{12793 .@"OpenCL.std" => &[_]Instruction{
12779 .{12794 .{
12780 .name = "acos",12795 .name = "acos",
12781 .opcode = 0,12796 .opcode = 0,
...@@ -14025,7 +14040,7 @@ pub const InstructionSet = enum {...@@ -14025,7 +14040,7 @@ pub const InstructionSet = enum {
14025 },14040 },
14026 },14041 },
14027 },14042 },
14028 .@"glsl.std.450" => &[_]Instruction{14043 .@"GLSL.std.450" => &[_]Instruction{
14029 .{14044 .{
14030 .name = "Round",14045 .name = "Round",
14031 .opcode = 1,14046 .opcode = 1,
...@@ -14633,7 +14648,7 @@ pub const InstructionSet = enum {...@@ -14633,7 +14648,7 @@ pub const InstructionSet = enum {
14633 },14648 },
14634 },14649 },
14635 },14650 },
14636 .@"opencl.debuginfo.100" => &[_]Instruction{14651 .@"OpenCL.DebugInfo.100" => &[_]Instruction{
14637 .{14652 .{
14638 .name = "DebugInfoNone",14653 .name = "DebugInfoNone",
14639 .opcode = 0,14654 .opcode = 0,
...@@ -14655,7 +14670,7 @@ pub const InstructionSet = enum {...@@ -14655,7 +14670,7 @@ pub const InstructionSet = enum {
14655 .operands = &[_]Operand{14670 .operands = &[_]Operand{
14656 .{ .kind = .IdRef, .quantifier = .required },14671 .{ .kind = .IdRef, .quantifier = .required },
14657 .{ .kind = .IdRef, .quantifier = .required },14672 .{ .kind = .IdRef, .quantifier = .required },
14658 .{ .kind = .@"opencl.debuginfo.100.DebugBaseTypeAttributeEncoding", .quantifier = .required },14673 .{ .kind = .@"OpenCL.DebugInfo.100.DebugBaseTypeAttributeEncoding", .quantifier = .required },
14659 },14674 },
14660 },14675 },
14661 .{14676 .{
...@@ -14664,7 +14679,7 @@ pub const InstructionSet = enum {...@@ -14664,7 +14679,7 @@ pub const InstructionSet = enum {
14664 .operands = &[_]Operand{14679 .operands = &[_]Operand{
14665 .{ .kind = .IdRef, .quantifier = .required },14680 .{ .kind = .IdRef, .quantifier = .required },
14666 .{ .kind = .StorageClass, .quantifier = .required },14681 .{ .kind = .StorageClass, .quantifier = .required },
14667 .{ .kind = .@"opencl.debuginfo.100.DebugInfoFlags", .quantifier = .required },14682 .{ .kind = .@"OpenCL.DebugInfo.100.DebugInfoFlags", .quantifier = .required },
14668 },14683 },
14669 },14684 },
14670 .{14685 .{
...@@ -14672,7 +14687,7 @@ pub const InstructionSet = enum {...@@ -14672,7 +14687,7 @@ pub const InstructionSet = enum {
14672 .opcode = 4,14687 .opcode = 4,
14673 .operands = &[_]Operand{14688 .operands = &[_]Operand{
14674 .{ .kind = .IdRef, .quantifier = .required },14689 .{ .kind = .IdRef, .quantifier = .required },
14675 .{ .kind = .@"opencl.debuginfo.100.DebugTypeQualifier", .quantifier = .required },14690 .{ .kind = .@"OpenCL.DebugInfo.100.DebugTypeQualifier", .quantifier = .required },
14676 },14691 },
14677 },14692 },
14678 .{14693 .{
...@@ -14707,7 +14722,7 @@ pub const InstructionSet = enum {...@@ -14707,7 +14722,7 @@ pub const InstructionSet = enum {
14707 .name = "DebugTypeFunction",14722 .name = "DebugTypeFunction",
14708 .opcode = 8,14723 .opcode = 8,
14709 .operands = &[_]Operand{14724 .operands = &[_]Operand{
14710 .{ .kind = .@"opencl.debuginfo.100.DebugInfoFlags", .quantifier = .required },14725 .{ .kind = .@"OpenCL.DebugInfo.100.DebugInfoFlags", .quantifier = .required },
14711 .{ .kind = .IdRef, .quantifier = .required },14726 .{ .kind = .IdRef, .quantifier = .required },
14712 .{ .kind = .IdRef, .quantifier = .variadic },14727 .{ .kind = .IdRef, .quantifier = .variadic },
14713 },14728 },
...@@ -14723,7 +14738,7 @@ pub const InstructionSet = enum {...@@ -14723,7 +14738,7 @@ pub const InstructionSet = enum {
14723 .{ .kind = .LiteralInteger, .quantifier = .required },14738 .{ .kind = .LiteralInteger, .quantifier = .required },
14724 .{ .kind = .IdRef, .quantifier = .required },14739 .{ .kind = .IdRef, .quantifier = .required },
14725 .{ .kind = .IdRef, .quantifier = .required },14740 .{ .kind = .IdRef, .quantifier = .required },
14726 .{ .kind = .@"opencl.debuginfo.100.DebugInfoFlags", .quantifier = .required },14741 .{ .kind = .@"OpenCL.DebugInfo.100.DebugInfoFlags", .quantifier = .required },
14727 .{ .kind = .PairIdRefIdRef, .quantifier = .variadic },14742 .{ .kind = .PairIdRefIdRef, .quantifier = .variadic },
14728 },14743 },
14729 },14744 },
...@@ -14732,14 +14747,14 @@ pub const InstructionSet = enum {...@@ -14732,14 +14747,14 @@ pub const InstructionSet = enum {
14732 .opcode = 10,14747 .opcode = 10,
14733 .operands = &[_]Operand{14748 .operands = &[_]Operand{
14734 .{ .kind = .IdRef, .quantifier = .required },14749 .{ .kind = .IdRef, .quantifier = .required },
14735 .{ .kind = .@"opencl.debuginfo.100.DebugCompositeType", .quantifier = .required },14750 .{ .kind = .@"OpenCL.DebugInfo.100.DebugCompositeType", .quantifier = .required },
14736 .{ .kind = .IdRef, .quantifier = .required },14751 .{ .kind = .IdRef, .quantifier = .required },
14737 .{ .kind = .LiteralInteger, .quantifier = .required },14752 .{ .kind = .LiteralInteger, .quantifier = .required },
14738 .{ .kind = .LiteralInteger, .quantifier = .required },14753 .{ .kind = .LiteralInteger, .quantifier = .required },
14739 .{ .kind = .IdRef, .quantifier = .required },14754 .{ .kind = .IdRef, .quantifier = .required },
14740 .{ .kind = .IdRef, .quantifier = .required },14755 .{ .kind = .IdRef, .quantifier = .required },
14741 .{ .kind = .IdRef, .quantifier = .required },14756 .{ .kind = .IdRef, .quantifier = .required },
14742 .{ .kind = .@"opencl.debuginfo.100.DebugInfoFlags", .quantifier = .required },14757 .{ .kind = .@"OpenCL.DebugInfo.100.DebugInfoFlags", .quantifier = .required },
14743 .{ .kind = .IdRef, .quantifier = .variadic },14758 .{ .kind = .IdRef, .quantifier = .variadic },
14744 },14759 },
14745 },14760 },
...@@ -14755,7 +14770,7 @@ pub const InstructionSet = enum {...@@ -14755,7 +14770,7 @@ pub const InstructionSet = enum {
14755 .{ .kind = .IdRef, .quantifier = .required },14770 .{ .kind = .IdRef, .quantifier = .required },
14756 .{ .kind = .IdRef, .quantifier = .required },14771 .{ .kind = .IdRef, .quantifier = .required },
14757 .{ .kind = .IdRef, .quantifier = .required },14772 .{ .kind = .IdRef, .quantifier = .required },
14758 .{ .kind = .@"opencl.debuginfo.100.DebugInfoFlags", .quantifier = .required },14773 .{ .kind = .@"OpenCL.DebugInfo.100.DebugInfoFlags", .quantifier = .required },
14759 .{ .kind = .IdRef, .quantifier = .optional },14774 .{ .kind = .IdRef, .quantifier = .optional },
14760 },14775 },
14761 },14776 },
...@@ -14767,7 +14782,7 @@ pub const InstructionSet = enum {...@@ -14767,7 +14782,7 @@ pub const InstructionSet = enum {
14767 .{ .kind = .IdRef, .quantifier = .required },14782 .{ .kind = .IdRef, .quantifier = .required },
14768 .{ .kind = .IdRef, .quantifier = .required },14783 .{ .kind = .IdRef, .quantifier = .required },
14769 .{ .kind = .IdRef, .quantifier = .required },14784 .{ .kind = .IdRef, .quantifier = .required },
14770 .{ .kind = .@"opencl.debuginfo.100.DebugInfoFlags", .quantifier = .required },14785 .{ .kind = .@"OpenCL.DebugInfo.100.DebugInfoFlags", .quantifier = .required },
14771 },14786 },
14772 },14787 },
14773 .{14788 .{
...@@ -14832,7 +14847,7 @@ pub const InstructionSet = enum {...@@ -14832,7 +14847,7 @@ pub const InstructionSet = enum {
14832 .{ .kind = .IdRef, .quantifier = .required },14847 .{ .kind = .IdRef, .quantifier = .required },
14833 .{ .kind = .IdRef, .quantifier = .required },14848 .{ .kind = .IdRef, .quantifier = .required },
14834 .{ .kind = .IdRef, .quantifier = .required },14849 .{ .kind = .IdRef, .quantifier = .required },
14835 .{ .kind = .@"opencl.debuginfo.100.DebugInfoFlags", .quantifier = .required },14850 .{ .kind = .@"OpenCL.DebugInfo.100.DebugInfoFlags", .quantifier = .required },
14836 .{ .kind = .IdRef, .quantifier = .optional },14851 .{ .kind = .IdRef, .quantifier = .optional },
14837 },14852 },
14838 },14853 },
...@@ -14847,7 +14862,7 @@ pub const InstructionSet = enum {...@@ -14847,7 +14862,7 @@ pub const InstructionSet = enum {
14847 .{ .kind = .LiteralInteger, .quantifier = .required },14862 .{ .kind = .LiteralInteger, .quantifier = .required },
14848 .{ .kind = .IdRef, .quantifier = .required },14863 .{ .kind = .IdRef, .quantifier = .required },
14849 .{ .kind = .IdRef, .quantifier = .required },14864 .{ .kind = .IdRef, .quantifier = .required },
14850 .{ .kind = .@"opencl.debuginfo.100.DebugInfoFlags", .quantifier = .required },14865 .{ .kind = .@"OpenCL.DebugInfo.100.DebugInfoFlags", .quantifier = .required },
14851 },14866 },
14852 },14867 },
14853 .{14868 .{
...@@ -14861,7 +14876,7 @@ pub const InstructionSet = enum {...@@ -14861,7 +14876,7 @@ pub const InstructionSet = enum {
14861 .{ .kind = .LiteralInteger, .quantifier = .required },14876 .{ .kind = .LiteralInteger, .quantifier = .required },
14862 .{ .kind = .IdRef, .quantifier = .required },14877 .{ .kind = .IdRef, .quantifier = .required },
14863 .{ .kind = .IdRef, .quantifier = .required },14878 .{ .kind = .IdRef, .quantifier = .required },
14864 .{ .kind = .@"opencl.debuginfo.100.DebugInfoFlags", .quantifier = .required },14879 .{ .kind = .@"OpenCL.DebugInfo.100.DebugInfoFlags", .quantifier = .required },
14865 .{ .kind = .LiteralInteger, .quantifier = .required },14880 .{ .kind = .LiteralInteger, .quantifier = .required },
14866 .{ .kind = .IdRef, .quantifier = .required },14881 .{ .kind = .IdRef, .quantifier = .required },
14867 .{ .kind = .IdRef, .quantifier = .optional },14882 .{ .kind = .IdRef, .quantifier = .optional },
...@@ -14919,7 +14934,7 @@ pub const InstructionSet = enum {...@@ -14919,7 +14934,7 @@ pub const InstructionSet = enum {
14919 .{ .kind = .LiteralInteger, .quantifier = .required },14934 .{ .kind = .LiteralInteger, .quantifier = .required },
14920 .{ .kind = .LiteralInteger, .quantifier = .required },14935 .{ .kind = .LiteralInteger, .quantifier = .required },
14921 .{ .kind = .IdRef, .quantifier = .required },14936 .{ .kind = .IdRef, .quantifier = .required },
14922 .{ .kind = .@"opencl.debuginfo.100.DebugInfoFlags", .quantifier = .required },14937 .{ .kind = .@"OpenCL.DebugInfo.100.DebugInfoFlags", .quantifier = .required },
14923 .{ .kind = .LiteralInteger, .quantifier = .optional },14938 .{ .kind = .LiteralInteger, .quantifier = .optional },
14924 },14939 },
14925 },14940 },
...@@ -14954,7 +14969,7 @@ pub const InstructionSet = enum {...@@ -14954,7 +14969,7 @@ pub const InstructionSet = enum {
14954 .name = "DebugOperation",14969 .name = "DebugOperation",
14955 .opcode = 30,14970 .opcode = 30,
14956 .operands = &[_]Operand{14971 .operands = &[_]Operand{
14957 .{ .kind = .@"opencl.debuginfo.100.DebugOperation", .quantifier = .required },14972 .{ .kind = .@"OpenCL.DebugInfo.100.DebugOperation", .quantifier = .required },
14958 .{ .kind = .LiteralInteger, .quantifier = .variadic },14973 .{ .kind = .LiteralInteger, .quantifier = .variadic },
14959 },14974 },
14960 },14975 },
...@@ -14989,7 +15004,7 @@ pub const InstructionSet = enum {...@@ -14989,7 +15004,7 @@ pub const InstructionSet = enum {
14989 .opcode = 34,15004 .opcode = 34,
14990 .operands = &[_]Operand{15005 .operands = &[_]Operand{
14991 .{ .kind = .IdRef, .quantifier = .required },15006 .{ .kind = .IdRef, .quantifier = .required },
14992 .{ .kind = .@"opencl.debuginfo.100.DebugImportedEntity", .quantifier = .required },15007 .{ .kind = .@"OpenCL.DebugInfo.100.DebugImportedEntity", .quantifier = .required },
14993 .{ .kind = .IdRef, .quantifier = .required },15008 .{ .kind = .IdRef, .quantifier = .required },
14994 .{ .kind = .IdRef, .quantifier = .required },15009 .{ .kind = .IdRef, .quantifier = .required },
14995 .{ .kind = .LiteralInteger, .quantifier = .required },15010 .{ .kind = .LiteralInteger, .quantifier = .required },
...@@ -15020,7 +15035,7 @@ pub const InstructionSet = enum {...@@ -15020,7 +15035,7 @@ pub const InstructionSet = enum {
15020 },15035 },
15021 },15036 },
15022 },15037 },
15023 .@"spv-amd-shader-ballot" => &[_]Instruction{15038 .SPV_AMD_shader_ballot => &[_]Instruction{
15024 .{15039 .{
15025 .name = "SwizzleInvocationsAMD",15040 .name = "SwizzleInvocationsAMD",
15026 .opcode = 1,15041 .opcode = 1,
...@@ -15054,7 +15069,7 @@ pub const InstructionSet = enum {...@@ -15054,7 +15069,7 @@ pub const InstructionSet = enum {
15054 },15069 },
15055 },15070 },
15056 },15071 },
15057 .@"nonsemantic.shader.debuginfo.100" => &[_]Instruction{15072 .@"NonSemantic.Shader.DebugInfo.100" => &[_]Instruction{
15058 .{15073 .{
15059 .name = "DebugInfoNone",15074 .name = "DebugInfoNone",
15060 .opcode = 0,15075 .opcode = 0,
...@@ -15491,7 +15506,7 @@ pub const InstructionSet = enum {...@@ -15491,7 +15506,7 @@ pub const InstructionSet = enum {
15491 },15506 },
15492 },15507 },
15493 },15508 },
15494 .@"nonsemantic.vkspreflection" => &[_]Instruction{15509 .@"NonSemantic.VkspReflection" => &[_]Instruction{
15495 .{15510 .{
15496 .name = "Configuration",15511 .name = "Configuration",
15497 .opcode = 1,15512 .opcode = 1,
...@@ -15623,7 +15638,7 @@ pub const InstructionSet = enum {...@@ -15623,7 +15638,7 @@ pub const InstructionSet = enum {
15623 },15638 },
15624 },15639 },
15625 },15640 },
15626 .@"nonsemantic.clspvreflection" => &[_]Instruction{15641 .@"NonSemantic.ClspvReflection.6" => &[_]Instruction{
15627 .{15642 .{
15628 .name = "Kernel",15643 .name = "Kernel",
15629 .opcode = 1,15644 .opcode = 1,
...@@ -16030,7 +16045,7 @@ pub const InstructionSet = enum {...@@ -16030,7 +16045,7 @@ pub const InstructionSet = enum {
16030 },16045 },
16031 },16046 },
16032 },16047 },
16033 .@"spv-amd-gcn-shader" => &[_]Instruction{16048 .SPV_AMD_gcn_shader => &[_]Instruction{
16034 .{16049 .{
16035 .name = "CubeFaceIndexAMD",16050 .name = "CubeFaceIndexAMD",
16036 .opcode = 1,16051 .opcode = 1,
...@@ -16051,7 +16066,7 @@ pub const InstructionSet = enum {...@@ -16051,7 +16066,7 @@ pub const InstructionSet = enum {
16051 .operands = &[_]Operand{},16066 .operands = &[_]Operand{},
16052 },16067 },
16053 },16068 },
16054 .@"spv-amd-shader-trinary-minmax" => &[_]Instruction{16069 .SPV_AMD_shader_trinary_minmax => &[_]Instruction{
16055 .{16070 .{
16056 .name = "FMin3AMD",16071 .name = "FMin3AMD",
16057 .opcode = 1,16072 .opcode = 1,
...@@ -16134,7 +16149,7 @@ pub const InstructionSet = enum {...@@ -16134,7 +16149,7 @@ pub const InstructionSet = enum {
16134 },16149 },
16135 },16150 },
16136 },16151 },
16137 .debuginfo => &[_]Instruction{16152 .DebugInfo => &[_]Instruction{
16138 .{16153 .{
16139 .name = "DebugInfoNone",16154 .name = "DebugInfoNone",
16140 .opcode = 0,16155 .opcode = 0,
...@@ -16155,7 +16170,7 @@ pub const InstructionSet = enum {...@@ -16155,7 +16170,7 @@ pub const InstructionSet = enum {
16155 .operands = &[_]Operand{16170 .operands = &[_]Operand{
16156 .{ .kind = .IdRef, .quantifier = .required },16171 .{ .kind = .IdRef, .quantifier = .required },
16157 .{ .kind = .IdRef, .quantifier = .required },16172 .{ .kind = .IdRef, .quantifier = .required },
16158 .{ .kind = .@"debuginfo.DebugBaseTypeAttributeEncoding", .quantifier = .required },16173 .{ .kind = .@"DebugInfo.DebugBaseTypeAttributeEncoding", .quantifier = .required },
16159 },16174 },
16160 },16175 },
16161 .{16176 .{
...@@ -16164,7 +16179,7 @@ pub const InstructionSet = enum {...@@ -16164,7 +16179,7 @@ pub const InstructionSet = enum {
16164 .operands = &[_]Operand{16179 .operands = &[_]Operand{
16165 .{ .kind = .IdRef, .quantifier = .required },16180 .{ .kind = .IdRef, .quantifier = .required },
16166 .{ .kind = .StorageClass, .quantifier = .required },16181 .{ .kind = .StorageClass, .quantifier = .required },
16167 .{ .kind = .@"debuginfo.DebugInfoFlags", .quantifier = .required },16182 .{ .kind = .@"DebugInfo.DebugInfoFlags", .quantifier = .required },
16168 },16183 },
16169 },16184 },
16170 .{16185 .{
...@@ -16172,7 +16187,7 @@ pub const InstructionSet = enum {...@@ -16172,7 +16187,7 @@ pub const InstructionSet = enum {
16172 .opcode = 4,16187 .opcode = 4,
16173 .operands = &[_]Operand{16188 .operands = &[_]Operand{
16174 .{ .kind = .IdRef, .quantifier = .required },16189 .{ .kind = .IdRef, .quantifier = .required },
16175 .{ .kind = .@"debuginfo.DebugTypeQualifier", .quantifier = .required },16190 .{ .kind = .@"DebugInfo.DebugTypeQualifier", .quantifier = .required },
16176 },16191 },
16177 },16192 },
16178 .{16193 .{
...@@ -16222,7 +16237,7 @@ pub const InstructionSet = enum {...@@ -16222,7 +16237,7 @@ pub const InstructionSet = enum {
16222 .{ .kind = .LiteralInteger, .quantifier = .required },16237 .{ .kind = .LiteralInteger, .quantifier = .required },
16223 .{ .kind = .IdRef, .quantifier = .required },16238 .{ .kind = .IdRef, .quantifier = .required },
16224 .{ .kind = .IdRef, .quantifier = .required },16239 .{ .kind = .IdRef, .quantifier = .required },
16225 .{ .kind = .@"debuginfo.DebugInfoFlags", .quantifier = .required },16240 .{ .kind = .@"DebugInfo.DebugInfoFlags", .quantifier = .required },
16226 .{ .kind = .PairIdRefIdRef, .quantifier = .variadic },16241 .{ .kind = .PairIdRefIdRef, .quantifier = .variadic },
16227 },16242 },
16228 },16243 },
...@@ -16231,13 +16246,13 @@ pub const InstructionSet = enum {...@@ -16231,13 +16246,13 @@ pub const InstructionSet = enum {
16231 .opcode = 10,16246 .opcode = 10,
16232 .operands = &[_]Operand{16247 .operands = &[_]Operand{
16233 .{ .kind = .IdRef, .quantifier = .required },16248 .{ .kind = .IdRef, .quantifier = .required },
16234 .{ .kind = .@"debuginfo.DebugCompositeType", .quantifier = .required },16249 .{ .kind = .@"DebugInfo.DebugCompositeType", .quantifier = .required },
16235 .{ .kind = .IdRef, .quantifier = .required },16250 .{ .kind = .IdRef, .quantifier = .required },
16236 .{ .kind = .LiteralInteger, .quantifier = .required },16251 .{ .kind = .LiteralInteger, .quantifier = .required },
16237 .{ .kind = .LiteralInteger, .quantifier = .required },16252 .{ .kind = .LiteralInteger, .quantifier = .required },
16238 .{ .kind = .IdRef, .quantifier = .required },16253 .{ .kind = .IdRef, .quantifier = .required },
16239 .{ .kind = .IdRef, .quantifier = .required },16254 .{ .kind = .IdRef, .quantifier = .required },
16240 .{ .kind = .@"debuginfo.DebugInfoFlags", .quantifier = .required },16255 .{ .kind = .@"DebugInfo.DebugInfoFlags", .quantifier = .required },
16241 .{ .kind = .IdRef, .quantifier = .variadic },16256 .{ .kind = .IdRef, .quantifier = .variadic },
16242 },16257 },
16243 },16258 },
...@@ -16253,7 +16268,7 @@ pub const InstructionSet = enum {...@@ -16253,7 +16268,7 @@ pub const InstructionSet = enum {
16253 .{ .kind = .IdRef, .quantifier = .required },16268 .{ .kind = .IdRef, .quantifier = .required },
16254 .{ .kind = .IdRef, .quantifier = .required },16269 .{ .kind = .IdRef, .quantifier = .required },
16255 .{ .kind = .IdRef, .quantifier = .required },16270 .{ .kind = .IdRef, .quantifier = .required },
16256 .{ .kind = .@"debuginfo.DebugInfoFlags", .quantifier = .required },16271 .{ .kind = .@"DebugInfo.DebugInfoFlags", .quantifier = .required },
16257 .{ .kind = .IdRef, .quantifier = .optional },16272 .{ .kind = .IdRef, .quantifier = .optional },
16258 },16273 },
16259 },16274 },
...@@ -16265,7 +16280,7 @@ pub const InstructionSet = enum {...@@ -16265,7 +16280,7 @@ pub const InstructionSet = enum {
16265 .{ .kind = .IdRef, .quantifier = .required },16280 .{ .kind = .IdRef, .quantifier = .required },
16266 .{ .kind = .IdRef, .quantifier = .required },16281 .{ .kind = .IdRef, .quantifier = .required },
16267 .{ .kind = .IdRef, .quantifier = .required },16282 .{ .kind = .IdRef, .quantifier = .required },
16268 .{ .kind = .@"debuginfo.DebugInfoFlags", .quantifier = .required },16283 .{ .kind = .@"DebugInfo.DebugInfoFlags", .quantifier = .required },
16269 },16284 },
16270 },16285 },
16271 .{16286 .{
...@@ -16330,7 +16345,7 @@ pub const InstructionSet = enum {...@@ -16330,7 +16345,7 @@ pub const InstructionSet = enum {
16330 .{ .kind = .IdRef, .quantifier = .required },16345 .{ .kind = .IdRef, .quantifier = .required },
16331 .{ .kind = .IdRef, .quantifier = .required },16346 .{ .kind = .IdRef, .quantifier = .required },
16332 .{ .kind = .IdRef, .quantifier = .required },16347 .{ .kind = .IdRef, .quantifier = .required },
16333 .{ .kind = .@"debuginfo.DebugInfoFlags", .quantifier = .required },16348 .{ .kind = .@"DebugInfo.DebugInfoFlags", .quantifier = .required },
16334 .{ .kind = .IdRef, .quantifier = .optional },16349 .{ .kind = .IdRef, .quantifier = .optional },
16335 },16350 },
16336 },16351 },
...@@ -16345,7 +16360,7 @@ pub const InstructionSet = enum {...@@ -16345,7 +16360,7 @@ pub const InstructionSet = enum {
16345 .{ .kind = .LiteralInteger, .quantifier = .required },16360 .{ .kind = .LiteralInteger, .quantifier = .required },
16346 .{ .kind = .IdRef, .quantifier = .required },16361 .{ .kind = .IdRef, .quantifier = .required },
16347 .{ .kind = .IdRef, .quantifier = .required },16362 .{ .kind = .IdRef, .quantifier = .required },
16348 .{ .kind = .@"debuginfo.DebugInfoFlags", .quantifier = .required },16363 .{ .kind = .@"DebugInfo.DebugInfoFlags", .quantifier = .required },
16349 },16364 },
16350 },16365 },
16351 .{16366 .{
...@@ -16359,7 +16374,7 @@ pub const InstructionSet = enum {...@@ -16359,7 +16374,7 @@ pub const InstructionSet = enum {
16359 .{ .kind = .LiteralInteger, .quantifier = .required },16374 .{ .kind = .LiteralInteger, .quantifier = .required },
16360 .{ .kind = .IdRef, .quantifier = .required },16375 .{ .kind = .IdRef, .quantifier = .required },
16361 .{ .kind = .IdRef, .quantifier = .required },16376 .{ .kind = .IdRef, .quantifier = .required },
16362 .{ .kind = .@"debuginfo.DebugInfoFlags", .quantifier = .required },16377 .{ .kind = .@"DebugInfo.DebugInfoFlags", .quantifier = .required },
16363 .{ .kind = .LiteralInteger, .quantifier = .required },16378 .{ .kind = .LiteralInteger, .quantifier = .required },
16364 .{ .kind = .IdRef, .quantifier = .required },16379 .{ .kind = .IdRef, .quantifier = .required },
16365 .{ .kind = .IdRef, .quantifier = .optional },16380 .{ .kind = .IdRef, .quantifier = .optional },
...@@ -16450,7 +16465,7 @@ pub const InstructionSet = enum {...@@ -16450,7 +16465,7 @@ pub const InstructionSet = enum {
16450 .name = "DebugOperation",16465 .name = "DebugOperation",
16451 .opcode = 30,16466 .opcode = 30,
16452 .operands = &[_]Operand{16467 .operands = &[_]Operand{
16453 .{ .kind = .@"debuginfo.DebugOperation", .quantifier = .required },16468 .{ .kind = .@"DebugInfo.DebugOperation", .quantifier = .required },
16454 .{ .kind = .LiteralInteger, .quantifier = .variadic },16469 .{ .kind = .LiteralInteger, .quantifier = .variadic },
16455 },16470 },
16456 },16471 },
...@@ -16481,7 +16496,7 @@ pub const InstructionSet = enum {...@@ -16481,7 +16496,7 @@ pub const InstructionSet = enum {
16481 },16496 },
16482 },16497 },
16483 },16498 },
16484 .@"nonsemantic.debugprintf" => &[_]Instruction{16499 .@"NonSemantic.DebugPrintf" => &[_]Instruction{
16485 .{16500 .{
16486 .name = "DebugPrintf",16501 .name = "DebugPrintf",
16487 .opcode = 1,16502 .opcode = 1,
...@@ -16491,7 +16506,7 @@ pub const InstructionSet = enum {...@@ -16491,7 +16506,7 @@ pub const InstructionSet = enum {
16491 },16506 },
16492 },16507 },
16493 },16508 },
16494 .@"spv-amd-shader-explicit-vertex-parameter" => &[_]Instruction{16509 .SPV_AMD_shader_explicit_vertex_parameter => &[_]Instruction{
16495 .{16510 .{
16496 .name = "InterpolateAtVertexAMD",16511 .name = "InterpolateAtVertexAMD",
16497 .opcode = 1,16512 .opcode = 1,
...@@ -16501,7 +16516,7 @@ pub const InstructionSet = enum {...@@ -16501,7 +16516,7 @@ pub const InstructionSet = enum {
16501 },16516 },
16502 },16517 },
16503 },16518 },
16504 .@"nonsemantic.debugbreak" => &[_]Instruction{16519 .@"NonSemantic.DebugBreak" => &[_]Instruction{
16505 .{16520 .{
16506 .name = "DebugBreak",16521 .name = "DebugBreak",
16507 .opcode = 1,16522 .opcode = 1,
src/link/SpirV.zig+31-6
...@@ -39,8 +39,12 @@ const Liveness = @import("../Liveness.zig");...@@ -39,8 +39,12 @@ const Liveness = @import("../Liveness.zig");
39const Value = @import("../Value.zig");39const Value = @import("../Value.zig");
4040
41const SpvModule = @import("../codegen/spirv/Module.zig");41const SpvModule = @import("../codegen/spirv/Module.zig");
42const Section = @import("../codegen/spirv/Section.zig");
42const spec = @import("../codegen/spirv/spec.zig");43const spec = @import("../codegen/spirv/spec.zig");
43const IdResult = spec.IdResult;44const IdResult = spec.IdResult;
45const Word = spec.Word;
46
47const BinaryModule = @import("SpirV/BinaryModule.zig");
4448
45base: link.File,49base: link.File,
4650
...@@ -163,6 +167,7 @@ pub fn updateExports(...@@ -163,6 +167,7 @@ pub fn updateExports(
163 .Vertex => spec.ExecutionModel.Vertex,167 .Vertex => spec.ExecutionModel.Vertex,
164 .Fragment => spec.ExecutionModel.Fragment,168 .Fragment => spec.ExecutionModel.Fragment,
165 .Kernel => spec.ExecutionModel.Kernel,169 .Kernel => spec.ExecutionModel.Kernel,
170 .C => return, // TODO: What to do here?
166 else => unreachable,171 else => unreachable,
167 };172 };
168 const is_vulkan = target.os.tag == .vulkan;173 const is_vulkan = target.os.tag == .vulkan;
...@@ -197,8 +202,6 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node...@@ -197,8 +202,6 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node
197 @panic("Attempted to compile for architecture that was disabled by build configuration");202 @panic("Attempted to compile for architecture that was disabled by build configuration");
198 }203 }
199204
200 _ = arena; // Has the same lifetime as the call to Compilation.update.
201
202 const tracy = trace(@src());205 const tracy = trace(@src());
203 defer tracy.end();206 defer tracy.end();
204207
...@@ -223,9 +226,9 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node...@@ -223,9 +226,9 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node
223 defer error_info.deinit();226 defer error_info.deinit();
224227
225 try error_info.appendSlice("zig_errors");228 try error_info.appendSlice("zig_errors");
226 const module = self.base.comp.module.?;229 const mod = self.base.comp.module.?;
227 for (module.global_error_set.keys()) |name_nts| {230 for (mod.global_error_set.keys()) |name_nts| {
228 const name = module.intern_pool.stringToSlice(name_nts);231 const name = mod.intern_pool.stringToSlice(name_nts);
229 // Errors can contain pretty much any character - to encode them in a string we must escape232 // Errors can contain pretty much any character - to encode them in a string we must escape
230 // them somehow. Easiest here is to use some established scheme, one which also preseves the233 // them somehow. Easiest here is to use some established scheme, one which also preseves the
231 // name if it contains no strange characters is nice for debugging. URI encoding fits the bill.234 // name if it contains no strange characters is nice for debugging. URI encoding fits the bill.
...@@ -239,7 +242,29 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node...@@ -239,7 +242,29 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node
239 .extension = error_info.items,242 .extension = error_info.items,
240 });243 });
241244
242 try spv.flush(self.base.file.?, target);245 const module = try spv.finalize(arena, target);
246 errdefer arena.free(module);
247
248 const new_module = self.lowerInstanceGlobals(arena, module) catch |err| switch (err) {
249 error.OutOfMemory => return error.OutOfMemory,
250 else => |other| {
251 std.debug.print("error while lowering instance globals: {s}\n", .{@errorName(other)});
252 return error.FlushFailure;
253 },
254 };
255 defer arena.free(new_module);
256
257 try self.base.file.?.writeAll(std.mem.sliceAsBytes(new_module));
258}
259
260fn lowerInstanceGlobals(self: *SpirV, a: Allocator, module: []Word) ![]Word {
261 _ = self;
262
263 var parser = try BinaryModule.Parser.init(a);
264 defer parser.deinit();
265 const binary = try parser.parse(module);
266 const lower_invocation_globals = @import("SpirV/lower_invocation_globals.zig");
267 return try lower_invocation_globals.run(&parser, binary);
243}268}
244269
245fn writeCapabilities(spv: *SpvModule, target: std.Target) !void {270fn writeCapabilities(spv: *SpvModule, target: std.Target) !void {
src/link/SpirV/BinaryModule.zig+20-174
...@@ -33,6 +33,11 @@ ext_inst_map: std.AutoHashMapUnmanaged(ResultId, InstructionSet),...@@ -33,6 +33,11 @@ ext_inst_map: std.AutoHashMapUnmanaged(ResultId, InstructionSet),
33/// of Op(Spec)Constant and OpSwitch.33/// of Op(Spec)Constant and OpSwitch.
34arith_type_width: std.AutoHashMapUnmanaged(ResultId, u16),34arith_type_width: std.AutoHashMapUnmanaged(ResultId, u16),
3535
36/// The starting offsets of some sections
37sections: struct {
38 functions: usize,
39},
40
36pub fn deinit(self: *BinaryModule, a: Allocator) void {41pub fn deinit(self: *BinaryModule, a: Allocator) void {
37 self.ext_inst_map.deinit(a);42 self.ext_inst_map.deinit(a);
38 self.arith_type_width.deinit(a);43 self.arith_type_width.deinit(a);
...@@ -43,6 +48,10 @@ pub fn iterateInstructions(self: BinaryModule) Instruction.Iterator {...@@ -43,6 +48,10 @@ pub fn iterateInstructions(self: BinaryModule) Instruction.Iterator {
43 return Instruction.Iterator.init(self.instructions);48 return Instruction.Iterator.init(self.instructions);
44}49}
4550
51pub fn iterateInstructionsFrom(self: BinaryModule, offset: usize) Instruction.Iterator {
52 return Instruction.Iterator.init(self.instructions[offset..]);
53}
54
46/// Errors that can be raised when the module is not correct.55/// Errors that can be raised when the module is not correct.
47/// Note that the parser doesn't validate SPIR-V modules by a56/// Note that the parser doesn't validate SPIR-V modules by a
48/// long shot. It only yields errors that critically prevent57/// long shot. It only yields errors that critically prevent
...@@ -107,97 +116,6 @@ pub const Instruction = struct {...@@ -107,97 +116,6 @@ pub const Instruction = struct {
107 operands: []const Word,116 operands: []const Word,
108};117};
109118
110/// This struct is used to return information about
111/// a module's functions - entry points, functions,
112/// list of callees.
113pub const FunctionInfo = struct {
114 /// Information that is gathered about a particular function.
115 pub const Fn = struct {
116 /// The word-offset of the first word (of the OpFunction instruction)
117 /// of this instruction.
118 begin_offset: usize,
119 /// The past-end offset of the end (including operands) of the last
120 /// instruction of the function.
121 end_offset: usize,
122 /// The index of the first callee in `callee_store`.
123 first_callee: usize,
124 /// The module offset of the OpTypeFunction instruction corresponding
125 /// to this function.
126 /// We use an offset so that we don't need to keep a separate map.
127 type_offset: usize,
128 };
129
130 /// Maps function result-id -> Function information structure.
131 functions: std.AutoArrayHashMapUnmanaged(ResultId, Fn),
132 /// List of entry points in this module. Contains OpFunction result-ids.
133 entry_points: []const ResultId,
134 /// For each function, a list of function result-ids that it calls.
135 callee_store: []const ResultId,
136
137 pub fn deinit(self: *FunctionInfo, a: Allocator) void {
138 self.functions.deinit(a);
139 a.free(self.entry_points);
140 a.free(self.callee_store);
141 self.* = undefined;
142 }
143
144 /// Fetch the list of callees per function. Guaranteed to contain only unique IDs.
145 pub fn callees(self: FunctionInfo, fn_id: ResultId) []const ResultId {
146 const fn_index = self.functions.getIndex(fn_id).?;
147 const values = self.functions.values();
148 const first_callee = values[fn_index].first_callee;
149 if (fn_index == values.len - 1) {
150 return self.callee_store[first_callee..];
151 } else {
152 const next_first_callee = values[fn_index + 1].first_callee;
153 return self.callee_store[first_callee..next_first_callee];
154 }
155 }
156
157 /// Returns a topological ordering of the functions: For each item
158 /// in the returned list of OpFunction result-ids, it is guaranteed that
159 /// the callees have a lower index. Note that SPIR-V does not support
160 /// any recursion, so this always works.
161 pub fn topologicalSort(self: FunctionInfo, a: Allocator) ![]const ResultId {
162 var sort = std.ArrayList(ResultId).init(a);
163 defer sort.deinit();
164
165 var seen = try std.DynamicBitSetUnmanaged.initEmpty(a, self.functions.count());
166 defer seen.deinit(a);
167
168 var stack = std.ArrayList(ResultId).init(a);
169 defer stack.deinit();
170
171 for (self.functions.keys()) |id| {
172 try self.topologicalSortStep(id, &sort, &seen);
173 }
174
175 return try sort.toOwnedSlice();
176 }
177
178 fn topologicalSortStep(
179 self: FunctionInfo,
180 id: ResultId,
181 sort: *std.ArrayList(ResultId),
182 seen: *std.DynamicBitSetUnmanaged,
183 ) !void {
184 const fn_index = self.functions.getIndex(id) orelse {
185 log.err("function calls invalid callee-id {}", .{@intFromEnum(id)});
186 return error.InvalidId;
187 };
188 if (seen.isSet(fn_index)) {
189 return;
190 }
191
192 seen.set(fn_index);
193 for (self.callees(id)) |callee| {
194 try self.topologicalSortStep(callee, sort, seen);
195 }
196
197 try sort.append(id);
198 }
199};
200
201/// This parser contains information (acceleration tables)119/// This parser contains information (acceleration tables)
202/// that can be persisted across different modules. This is120/// that can be persisted across different modules. This is
203/// used to initialize the module, and is also used when121/// used to initialize the module, and is also used when
...@@ -256,8 +174,11 @@ pub const Parser = struct {...@@ -256,8 +174,11 @@ pub const Parser = struct {
256 .instructions = module[header_words..],174 .instructions = module[header_words..],
257 .ext_inst_map = .{},175 .ext_inst_map = .{},
258 .arith_type_width = .{},176 .arith_type_width = .{},
177 .sections = undefined,
259 };178 };
260179
180 var maybe_function_section: ?usize = null;
181
261 // First pass through the module to verify basic structure and182 // First pass through the module to verify basic structure and
262 // to gather some initial stuff for more detailed analysis.183 // to gather some initial stuff for more detailed analysis.
263 // We want to check some stuff that Instruction.Iterator is no good for,184 // We want to check some stuff that Instruction.Iterator is no good for,
...@@ -297,6 +218,9 @@ pub const Parser = struct {...@@ -297,6 +218,9 @@ pub const Parser = struct {
297 if (entry.found_existing) return error.DuplicateId;218 if (entry.found_existing) return error.DuplicateId;
298 entry.value_ptr.* = std.math.cast(u16, operands[1]) orelse return error.InvalidOperands;219 entry.value_ptr.* = std.math.cast(u16, operands[1]) orelse return error.InvalidOperands;
299 },220 },
221 .OpFunction => if (maybe_function_section == null) {
222 maybe_function_section = offset;
223 },
300 else => {},224 else => {},
301 }225 }
302226
...@@ -317,89 +241,11 @@ pub const Parser = struct {...@@ -317,89 +241,11 @@ pub const Parser = struct {
317 }241 }
318 }242 }
319243
320 return binary;244 binary.sections = .{
321 }245 .functions = maybe_function_section orelse binary.instructions.len,
322
323 pub fn parseFunctionInfo(self: *Parser, binary: BinaryModule) ParseError!FunctionInfo {
324 var entry_points = std.AutoArrayHashMap(ResultId, void).init(self.a);
325 defer entry_points.deinit();
326
327 var functions = std.AutoArrayHashMap(ResultId, FunctionInfo.Fn).init(self.a);
328 errdefer functions.deinit();
329
330 var fn_ty_decls = std.AutoHashMap(ResultId, usize).init(self.a);
331 defer fn_ty_decls.deinit();
332
333 var calls = std.AutoArrayHashMap(ResultId, void).init(self.a);
334 defer calls.deinit();
335
336 var callee_store = std.ArrayList(ResultId).init(self.a);
337 defer callee_store.deinit();
338
339 var maybe_current_function: ?ResultId = null;
340 var begin: usize = undefined;
341 var fn_ty_id: ResultId = undefined;
342
343 var it = binary.iterateInstructions();
344 while (it.next()) |inst| {
345 switch (inst.opcode) {
346 .OpEntryPoint => {
347 const entry = try entry_points.getOrPut(@enumFromInt(inst.operands[1]));
348 if (entry.found_existing) return error.DuplicateId;
349 },
350 .OpTypeFunction => {
351 const entry = try fn_ty_decls.getOrPut(@enumFromInt(inst.operands[0]));
352 if (entry.found_existing) return error.DuplicateId;
353 entry.value_ptr.* = inst.offset;
354 },
355 .OpFunction => {
356 maybe_current_function = @enumFromInt(inst.operands[1]);
357 begin = inst.offset;
358 fn_ty_id = @enumFromInt(inst.operands[3]);
359 },
360 .OpFunctionCall => {
361 const callee: ResultId = @enumFromInt(inst.operands[2]);
362 try calls.put(callee, {});
363 },
364 .OpFunctionEnd => {
365 const current_function = maybe_current_function orelse {
366 log.err("encountered OpFunctionEnd without corresponding OpFunction", .{});
367 return error.InvalidPhysicalFormat;
368 };
369 const entry = try functions.getOrPut(current_function);
370 if (entry.found_existing) return error.DuplicateId;
371
372 const first_callee = callee_store.items.len;
373 try callee_store.appendSlice(calls.keys());
374
375 const type_offset = fn_ty_decls.get(fn_ty_id) orelse {
376 log.err("Invalid OpFunction type", .{});
377 return error.InvalidId;
378 };
379
380 entry.value_ptr.* = .{
381 .begin_offset = begin,
382 .end_offset = it.offset, // Use past-end offset
383 .first_callee = first_callee,
384 .type_offset = type_offset,
385 };
386 maybe_current_function = null;
387 calls.clearRetainingCapacity();
388 },
389 else => {},
390 }
391 }
392
393 if (maybe_current_function != null) {
394 log.err("final OpFunction does not have an OpFunctionEnd", .{});
395 return error.InvalidPhysicalFormat;
396 }
397
398 return FunctionInfo{
399 .functions = functions.unmanaged,
400 .entry_points = try self.a.dupe(ResultId, entry_points.keys()),
401 .callee_store = try callee_store.toOwnedSlice(),
402 };246 };
247
248 return binary;
403 }249 }
404250
405 /// Parse offsets in the instruction that contain result-ids.251 /// Parse offsets in the instruction that contain result-ids.
...@@ -438,7 +284,7 @@ pub const Parser = struct {...@@ -438,7 +284,7 @@ pub const Parser = struct {
438 if (offset + 1 >= inst.operands.len) return error.InvalidPhysicalFormat;284 if (offset + 1 >= inst.operands.len) return error.InvalidPhysicalFormat;
439 const set_id: ResultId = @enumFromInt(inst.operands[offset]);285 const set_id: ResultId = @enumFromInt(inst.operands[offset]);
440 const set = binary.ext_inst_map.get(set_id) orelse {286 const set = binary.ext_inst_map.get(set_id) orelse {
441 log.err("Invalid instruction set {}", .{@intFromEnum(set_id)});287 log.err("invalid instruction set {}", .{@intFromEnum(set_id)});
442 return error.InvalidId;288 return error.InvalidId;
443 };289 };
444 const ext_opcode = std.math.cast(u16, inst.operands[offset + 1]) orelse return error.InvalidPhysicalFormat;290 const ext_opcode = std.math.cast(u16, inst.operands[offset + 1]) orelse return error.InvalidPhysicalFormat;
src/link/SpirV/lower_invocation_globals.zig created+714
...@@ -0,0 +1,714 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const assert = std.debug.assert;
4const log = std.log.scoped(.spirv_link);
5
6const BinaryModule = @import("BinaryModule.zig");
7const Section = @import("../../codegen/spirv/Section.zig");
8const spec = @import("../../codegen/spirv/spec.zig");
9const ResultId = spec.IdResult;
10const Word = spec.Word;
11
12/// This structure contains all the stuff that we need to parse from the module in
13/// order to run this pass, as well as some functions to ease its use.
14const ModuleInfo = struct {
15 /// Information about a particular function.
16 const Fn = struct {
17 /// The index of the first callee in `callee_store`.
18 first_callee: usize,
19 /// The return type id of this function
20 return_type: ResultId,
21 /// The parameter types of this function
22 param_types: []const ResultId,
23 /// The set of (result-id's of) invocation globals that are accessed
24 /// in this function, or after resolution, that are accessed in this
25 /// function or any of it's callees.
26 invocation_globals: std.AutoArrayHashMapUnmanaged(ResultId, void),
27 };
28
29 /// Information about a particular invocation global
30 const InvocationGlobal = struct {
31 /// The list of invocation globals that this invocation global
32 /// depends on.
33 dependencies: std.AutoArrayHashMapUnmanaged(ResultId, void),
34 /// The invocation global's type
35 ty: ResultId,
36 /// Initializer function. May be `none`.
37 /// Note that if the initializer is `none`, then `dependencies` is empty.
38 initializer: ResultId,
39 };
40
41 /// Maps function result-id -> Fn information structure.
42 functions: std.AutoArrayHashMapUnmanaged(ResultId, Fn),
43 /// Set of OpFunction result-ids in this module.
44 entry_points: std.AutoArrayHashMapUnmanaged(ResultId, void),
45 /// For each function, a list of function result-ids that it calls.
46 callee_store: []const ResultId,
47 /// Maps each invocation global result-id to a type-id.
48 invocation_globals: std.AutoArrayHashMapUnmanaged(ResultId, InvocationGlobal),
49
50 /// Fetch the list of callees per function. Guaranteed to contain only unique IDs.
51 fn callees(self: ModuleInfo, fn_id: ResultId) []const ResultId {
52 const fn_index = self.functions.getIndex(fn_id).?;
53 const values = self.functions.values();
54 const first_callee = values[fn_index].first_callee;
55 if (fn_index == values.len - 1) {
56 return self.callee_store[first_callee..];
57 } else {
58 const next_first_callee = values[fn_index + 1].first_callee;
59 return self.callee_store[first_callee..next_first_callee];
60 }
61 }
62
63 /// Extract most of the required information from the binary. The remaining info is
64 /// constructed by `resolve()`.
65 fn parse(
66 arena: Allocator,
67 parser: *BinaryModule.Parser,
68 binary: BinaryModule,
69 ) BinaryModule.ParseError!ModuleInfo {
70 var entry_points = std.AutoArrayHashMap(ResultId, void).init(arena);
71 var functions = std.AutoArrayHashMap(ResultId, Fn).init(arena);
72 var fn_types = std.AutoHashMap(ResultId, struct {
73 return_type: ResultId,
74 param_types: []const ResultId,
75 }).init(arena);
76 var calls = std.AutoArrayHashMap(ResultId, void).init(arena);
77 var callee_store = std.ArrayList(ResultId).init(arena);
78 var function_invocation_globals = std.AutoArrayHashMap(ResultId, void).init(arena);
79 var result_id_offsets = std.ArrayList(u16).init(arena);
80 var invocation_globals = std.AutoArrayHashMap(ResultId, InvocationGlobal).init(arena);
81
82 var maybe_current_function: ?ResultId = null;
83 var fn_ty_id: ResultId = undefined;
84
85 var it = binary.iterateInstructions();
86 while (it.next()) |inst| {
87 result_id_offsets.items.len = 0;
88 try parser.parseInstructionResultIds(binary, inst, &result_id_offsets);
89
90 switch (inst.opcode) {
91 .OpEntryPoint => {
92 const entry_point: ResultId = @enumFromInt(inst.operands[1]);
93 const entry = try entry_points.getOrPut(entry_point);
94 if (entry.found_existing) {
95 log.err("Entry point type {} has duplicate definition", .{entry_point});
96 return error.DuplicateId;
97 }
98 },
99 .OpTypeFunction => {
100 const fn_type: ResultId = @enumFromInt(inst.operands[0]);
101 const return_type: ResultId = @enumFromInt(inst.operands[1]);
102 const param_types: []const ResultId = @ptrCast(inst.operands[2..]);
103
104 const entry = try fn_types.getOrPut(fn_type);
105 if (entry.found_existing) {
106 log.err("Function type {} has duplicate definition", .{fn_type});
107 return error.DuplicateId;
108 }
109
110 entry.value_ptr.* = .{
111 .return_type = return_type,
112 .param_types = param_types,
113 };
114 },
115 .OpExtInst => {
116 // Note: format and set are already verified by parseInstructionResultIds().
117 const global_type: ResultId = @enumFromInt(inst.operands[0]);
118 const result_id: ResultId = @enumFromInt(inst.operands[1]);
119 const set_id: ResultId = @enumFromInt(inst.operands[2]);
120 const set_inst = inst.operands[3];
121
122 const set = binary.ext_inst_map.get(set_id).?;
123 if (set == .zig and set_inst == 0) {
124 const initializer: ResultId = if (inst.operands.len >= 5)
125 @enumFromInt(inst.operands[4])
126 else
127 .none;
128
129 try invocation_globals.put(result_id, .{
130 .dependencies = .{},
131 .ty = global_type,
132 .initializer = initializer,
133 });
134 }
135 },
136 .OpFunction => {
137 if (maybe_current_function) |current_function| {
138 log.err("OpFunction {} does not have an OpFunctionEnd", .{current_function});
139 return error.InvalidPhysicalFormat;
140 }
141
142 maybe_current_function = @enumFromInt(inst.operands[1]);
143 fn_ty_id = @enumFromInt(inst.operands[3]);
144 function_invocation_globals.clearRetainingCapacity();
145 },
146 .OpFunctionCall => {
147 const callee: ResultId = @enumFromInt(inst.operands[2]);
148 try calls.put(callee, {});
149 },
150 .OpFunctionEnd => {
151 const current_function = maybe_current_function orelse {
152 log.err("encountered OpFunctionEnd without corresponding OpFunction", .{});
153 return error.InvalidPhysicalFormat;
154 };
155 const entry = try functions.getOrPut(current_function);
156 if (entry.found_existing) {
157 log.err("Function {} has duplicate definition", .{current_function});
158 return error.DuplicateId;
159 }
160
161 const first_callee = callee_store.items.len;
162 try callee_store.appendSlice(calls.keys());
163
164 const fn_type = fn_types.get(fn_ty_id) orelse {
165 log.err("Function {} has invalid OpFunction type", .{current_function});
166 return error.InvalidId;
167 };
168
169 entry.value_ptr.* = .{
170 .first_callee = first_callee,
171 .return_type = fn_type.return_type,
172 .param_types = fn_type.param_types,
173 .invocation_globals = try function_invocation_globals.unmanaged.clone(arena),
174 };
175 maybe_current_function = null;
176 calls.clearRetainingCapacity();
177 },
178 else => {},
179 }
180
181 for (result_id_offsets.items) |off| {
182 const result_id: ResultId = @enumFromInt(inst.operands[off]);
183 if (invocation_globals.contains(result_id)) {
184 try function_invocation_globals.put(result_id, {});
185 }
186 }
187 }
188
189 if (maybe_current_function) |current_function| {
190 log.err("OpFunction {} does not have an OpFunctionEnd", .{current_function});
191 return error.InvalidPhysicalFormat;
192 }
193
194 return ModuleInfo{
195 .functions = functions.unmanaged,
196 .entry_points = entry_points.unmanaged,
197 .callee_store = callee_store.items,
198 .invocation_globals = invocation_globals.unmanaged,
199 };
200 }
201
202 /// Derive the remaining info from the structures filled in by parsing.
203 fn resolve(self: *ModuleInfo, arena: Allocator) !void {
204 try self.resolveInvocationGlobalUsage(arena);
205 try self.resolveInvocationGlobalDependencies(arena);
206 }
207
208 /// For each function, extend the list of `invocation_globals` with the
209 /// invocation globals that ALL of its dependencies use.
210 fn resolveInvocationGlobalUsage(self: *ModuleInfo, arena: Allocator) !void {
211 var seen = try std.DynamicBitSetUnmanaged.initEmpty(arena, self.functions.count());
212
213 for (self.functions.keys()) |id| {
214 try self.resolveInvocationGlobalUsageStep(arena, id, &seen);
215 }
216 }
217
218 fn resolveInvocationGlobalUsageStep(
219 self: *ModuleInfo,
220 arena: Allocator,
221 id: ResultId,
222 seen: *std.DynamicBitSetUnmanaged,
223 ) !void {
224 const index = self.functions.getIndex(id) orelse {
225 log.err("function calls invalid function {}", .{id});
226 return error.InvalidId;
227 };
228
229 if (seen.isSet(index)) {
230 return;
231 }
232 seen.set(index);
233
234 const info = &self.functions.values()[index];
235 for (self.callees(id)) |callee| {
236 try self.resolveInvocationGlobalUsageStep(arena, callee, seen);
237 const callee_info = self.functions.get(callee).?;
238 for (callee_info.invocation_globals.keys()) |global| {
239 try info.invocation_globals.put(arena, global, {});
240 }
241 }
242 }
243
244 /// For each invocation global, populate and fully resolve the `dependencies` set.
245 /// This requires `resolveInvocationGlobalUsage()` to be already done.
246 fn resolveInvocationGlobalDependencies(
247 self: *ModuleInfo,
248 arena: Allocator,
249 ) !void {
250 var seen = try std.DynamicBitSetUnmanaged.initEmpty(arena, self.invocation_globals.count());
251
252 for (self.invocation_globals.keys()) |id| {
253 try self.resolveInvocationGlobalDependenciesStep(arena, id, &seen);
254 }
255 }
256
257 fn resolveInvocationGlobalDependenciesStep(
258 self: *ModuleInfo,
259 arena: Allocator,
260 id: ResultId,
261 seen: *std.DynamicBitSetUnmanaged,
262 ) !void {
263 const index = self.invocation_globals.getIndex(id) orelse {
264 log.err("invalid invocation global {}", .{id});
265 return error.InvalidId;
266 };
267
268 if (seen.isSet(index)) {
269 return;
270 }
271 seen.set(index);
272
273 const info = &self.invocation_globals.values()[index];
274 if (info.initializer == .none) {
275 return;
276 }
277
278 const initializer = self.functions.get(info.initializer) orelse {
279 log.err("invocation global {} has invalid initializer {}", .{ id, info.initializer });
280 return error.InvalidId;
281 };
282
283 for (initializer.invocation_globals.keys()) |dependency| {
284 if (dependency == id) {
285 // The set of invocation global dependencies includes the dependency itself,
286 // so we need to skip that case.
287 continue;
288 }
289
290 try info.dependencies.put(arena, dependency, {});
291 try self.resolveInvocationGlobalDependenciesStep(arena, dependency, seen);
292
293 const dep_info = self.invocation_globals.getPtr(dependency).?;
294
295 for (dep_info.dependencies.keys()) |global| {
296 try info.dependencies.put(arena, global, {});
297 }
298 }
299 }
300};
301
302const ModuleBuilder = struct {
303 const FunctionType = struct {
304 return_type: ResultId,
305 param_types: []const ResultId,
306
307 const Context = struct {
308 pub fn hash(_: @This(), ty: FunctionType) u32 {
309 var hasher = std.hash.Wyhash.init(0);
310 hasher.update(std.mem.asBytes(&ty.return_type));
311 hasher.update(std.mem.sliceAsBytes(ty.param_types));
312 return @truncate(hasher.final());
313 }
314
315 pub fn eql(_: @This(), a: FunctionType, b: FunctionType, _: usize) bool {
316 if (a.return_type != b.return_type) return false;
317 return std.mem.eql(ResultId, a.param_types, b.param_types);
318 }
319 };
320 };
321
322 const FunctionNewInfo = struct {
323 /// This is here just so that we don't need to allocate the new
324 /// param_types multiple times.
325 new_function_type: ResultId,
326 /// The first ID of the parameters for the invocation globals.
327 /// Each global is allocate here according to the index in
328 /// `ModuleInfo.Fn.invocation_globals`.
329 global_id_base: u32,
330
331 fn invocationGlobalId(self: FunctionNewInfo, index: usize) ResultId {
332 return @enumFromInt(self.global_id_base + @as(u32, @intCast(index)));
333 }
334 };
335
336 arena: Allocator,
337 section: Section,
338 /// The ID bound of the new module.
339 id_bound: u32,
340 /// The first ID of the new entry points. Entry points are allocated from
341 /// here according to their index in `info.entry_points`.
342 entry_point_new_id_base: u32,
343 /// A set of all function types in the new program. SPIR-V mandates that these are unique,
344 /// and until a general type deduplication pass is programmed, we just handle it here via this.
345 function_types: std.ArrayHashMapUnmanaged(FunctionType, ResultId, FunctionType.Context, true) = .{},
346 /// Maps functions to new information required for creating the module
347 function_new_info: std.AutoArrayHashMapUnmanaged(ResultId, FunctionNewInfo) = .{},
348
349 fn init(arena: Allocator, binary: BinaryModule, info: ModuleInfo) !ModuleBuilder {
350 var section = Section{};
351
352 try section.instructions.appendSlice(arena, &.{
353 spec.magic_number,
354 @bitCast(binary.version),
355 spec.zig_generator_id,
356 0, // Filled in in finalize()
357 0, // Schema (reserved)
358 });
359
360 var self = ModuleBuilder{
361 .arena = arena,
362 .section = section,
363 .id_bound = binary.id_bound,
364 .entry_point_new_id_base = undefined,
365 };
366 self.entry_point_new_id_base = @intFromEnum(self.allocIds(@intCast(info.entry_points.count())));
367 return self;
368 }
369
370 fn allocId(self: *ModuleBuilder) ResultId {
371 return self.allocIds(1);
372 }
373
374 fn allocIds(self: *ModuleBuilder, n: u32) ResultId {
375 defer self.id_bound += n;
376 return @enumFromInt(self.id_bound);
377 }
378
379 fn finalize(self: *ModuleBuilder, a: Allocator) ![]Word {
380 self.section.instructions.items[3] = self.id_bound;
381 return try a.dupe(Word, self.section.instructions.items);
382 }
383
384 /// Process everything from `binary` up to the first function and emit it into the builder.
385 fn processPreamble(self: *ModuleBuilder, binary: BinaryModule, info: ModuleInfo) !void {
386 var it = binary.iterateInstructions();
387 while (it.next()) |inst| {
388 switch (inst.opcode) {
389 // TODO: We should remove this instruction using something that eliminates unreferenced instructions.
390 // For now, this is the only place where the .zig instruction set is being referenced, so its safe
391 // to remove it here.
392 .OpExtInstImport => {
393 const set_id: ResultId = @enumFromInt(inst.operands[0]);
394 const set = binary.ext_inst_map.get(set_id).?;
395 if (set == .zig) {
396 continue;
397 }
398 },
399 .OpExtInst => {
400 const set_id: ResultId = @enumFromInt(inst.operands[2]);
401 const set_inst = inst.operands[3];
402 const set = binary.ext_inst_map.get(set_id).?;
403 if (set == .zig and set_inst == 0) {
404 continue;
405 }
406 },
407 .OpEntryPoint => {
408 const original_id: ResultId = @enumFromInt(inst.operands[1]);
409 const new_id_index = info.entry_points.getIndex(original_id).?;
410 const new_id: ResultId = @enumFromInt(self.entry_point_new_id_base + new_id_index);
411 try self.section.emitRaw(self.arena, .OpEntryPoint, inst.operands.len);
412 self.section.writeWord(inst.operands[0]);
413 self.section.writeOperand(ResultId, new_id);
414 self.section.writeWords(inst.operands[2..]);
415 continue;
416 },
417 .OpTypeFunction => {
418 // Re-emitted in `emitFunctionTypes()`. We can do this because
419 // OpTypeFunction's may not currently be used anywhere that is not
420 // directly with an OpFunction. For now we igore Intels function
421 // pointers extension, that is not a problem with a generalized
422 // pass anyway.
423 continue;
424 },
425 .OpFunction => break,
426 else => {},
427 }
428
429 try self.section.emitRawInstruction(self.arena, inst.opcode, inst.operands);
430 }
431 }
432
433 /// Derive new information required for further emitting this module,
434 fn deriveNewFnInfo(self: *ModuleBuilder, info: ModuleInfo) !void {
435 for (info.functions.keys(), info.functions.values()) |func, fn_info| {
436 const invocation_global_count = fn_info.invocation_globals.count();
437 const new_param_types = try self.arena.alloc(ResultId, fn_info.param_types.len + invocation_global_count);
438 for (fn_info.invocation_globals.keys(), 0..) |global, i| {
439 new_param_types[i] = info.invocation_globals.get(global).?.ty;
440 }
441 @memcpy(new_param_types[invocation_global_count..], fn_info.param_types);
442
443 const new_type = try self.internFunctionType(fn_info.return_type, new_param_types);
444 try self.function_new_info.put(self.arena, func, .{
445 .new_function_type = new_type,
446 .global_id_base = @intFromEnum(self.allocIds(@intCast(invocation_global_count))),
447 });
448 }
449 }
450
451 /// Emit the new function types, which include the parameters for the invocation globals.
452 /// Currently, this function re-emits ALL function types to ensure that there are
453 /// no duplicates in the final program.
454 /// TODO: The above should be resolved by a generalized deduplication pass, and then
455 /// we only need to emit the new function pointers type here.
456 fn emitFunctionTypes(self: *ModuleBuilder, info: ModuleInfo) !void {
457 // TODO: Handle decorators. Function types usually don't have those
458 // though, but stuff like OpName could be a possibility.
459
460 // Entry points retain their old function type, so make sure to emit
461 // those in the `function_types` set.
462 for (info.entry_points.keys()) |func| {
463 const fn_info = info.functions.get(func).?;
464 _ = try self.internFunctionType(fn_info.return_type, fn_info.param_types);
465 }
466
467 for (self.function_types.keys(), self.function_types.values()) |fn_type, result_id| {
468 try self.section.emit(self.arena, .OpTypeFunction, .{
469 .id_result = result_id,
470 .return_type = fn_type.return_type,
471 .id_ref_2 = fn_type.param_types,
472 });
473 }
474 }
475
476 fn internFunctionType(self: *ModuleBuilder, return_type: ResultId, param_types: []const ResultId) !ResultId {
477 const entry = try self.function_types.getOrPut(self.arena, .{
478 .return_type = return_type,
479 .param_types = param_types,
480 });
481
482 if (!entry.found_existing) {
483 const new_id = self.allocId();
484 entry.value_ptr.* = new_id;
485 }
486
487 return entry.value_ptr.*;
488 }
489
490 /// Rewrite the modules' functions and emit them with the new parameter types.
491 fn rewriteFunctions(
492 self: *ModuleBuilder,
493 parser: *BinaryModule.Parser,
494 binary: BinaryModule,
495 info: ModuleInfo,
496 ) !void {
497 var result_id_offsets = std.ArrayList(u16).init(self.arena);
498 var operands = std.ArrayList(u32).init(self.arena);
499
500 var maybe_current_function: ?ResultId = null;
501 var it = binary.iterateInstructionsFrom(binary.sections.functions);
502 while (it.next()) |inst| {
503 result_id_offsets.items.len = 0;
504 try parser.parseInstructionResultIds(binary, inst, &result_id_offsets);
505
506 operands.items.len = 0;
507 try operands.appendSlice(inst.operands);
508
509 // Replace the result-ids with the global's new result-id if required.
510 for (result_id_offsets.items) |off| {
511 const result_id: ResultId = @enumFromInt(operands.items[off]);
512 if (info.invocation_globals.contains(result_id)) {
513 const func = maybe_current_function.?;
514 const new_info = self.function_new_info.get(func).?;
515 const fn_info = info.functions.get(func).?;
516 const index = fn_info.invocation_globals.getIndex(result_id).?;
517 operands.items[off] = @intFromEnum(new_info.invocationGlobalId(index));
518 }
519 }
520
521 switch (inst.opcode) {
522 .OpFunction => {
523 // Re-declare the function with the new parameters.
524 const func: ResultId = @enumFromInt(operands.items[1]);
525 const fn_info = info.functions.get(func).?;
526 const new_info = self.function_new_info.get(func).?;
527
528 try self.section.emitRaw(self.arena, .OpFunction, 4);
529 self.section.writeOperand(ResultId, fn_info.return_type);
530 self.section.writeOperand(ResultId, func);
531 self.section.writeWord(operands.items[2]);
532 self.section.writeOperand(ResultId, new_info.new_function_type);
533
534 // Emit the OpFunctionParameters for the invocation globals. The functions
535 // actual parameters are emitted unchanged from their original form, so
536 // we don't need to handle those here.
537
538 for (fn_info.invocation_globals.keys(), 0..) |global, index| {
539 const ty = info.invocation_globals.get(global).?.ty;
540 const id = new_info.invocationGlobalId(index);
541 try self.section.emit(self.arena, .OpFunctionParameter, .{
542 .id_result_type = ty,
543 .id_result = id,
544 });
545 }
546
547 maybe_current_function = func;
548 },
549 .OpFunctionCall => {
550 // Add the required invocation globals to the function's new parameter list.
551 const caller = maybe_current_function.?;
552 const callee: ResultId = @enumFromInt(operands.items[2]);
553 const caller_info = info.functions.get(caller).?;
554 const callee_info = info.functions.get(callee).?;
555 const caller_new_info = self.function_new_info.get(caller).?;
556 const total_params = callee_info.invocation_globals.count() + callee_info.param_types.len;
557
558 try self.section.emitRaw(self.arena, .OpFunctionCall, 3 + total_params);
559 self.section.writeWord(operands.items[0]); // Copy result type-id
560 self.section.writeWord(operands.items[1]); // Copy result-id
561 self.section.writeOperand(ResultId, callee);
562
563 // Add the new arguments
564 for (callee_info.invocation_globals.keys()) |global| {
565 const caller_global_index = caller_info.invocation_globals.getIndex(global).?;
566 const id = caller_new_info.invocationGlobalId(caller_global_index);
567 self.section.writeOperand(ResultId, id);
568 }
569
570 // Add the original arguments
571 self.section.writeWords(operands.items[3..]);
572 },
573 else => {
574 try self.section.emitRawInstruction(self.arena, inst.opcode, operands.items);
575 },
576 }
577 }
578 }
579
580 fn emitNewEntryPoints(self: *ModuleBuilder, info: ModuleInfo) !void {
581 var all_function_invocation_globals = std.AutoArrayHashMap(ResultId, void).init(self.arena);
582
583 for (info.entry_points.keys(), 0..) |func, entry_point_index| {
584 const fn_info = info.functions.get(func).?;
585 const ep_id: ResultId = @enumFromInt(self.entry_point_new_id_base + @as(u32, @intCast(entry_point_index)));
586 const fn_type = self.function_types.get(.{
587 .return_type = fn_info.return_type,
588 .param_types = fn_info.param_types,
589 }).?;
590
591 try self.section.emit(self.arena, .OpFunction, .{
592 .id_result_type = fn_info.return_type,
593 .id_result = ep_id,
594 .function_control = .{}, // TODO: Copy the attributes from the original function maybe?
595 .function_type = fn_type,
596 });
597
598 // Emit OpFunctionParameter instructions for the original kernel's parameters.
599 const params_id_base: u32 = @intFromEnum(self.allocIds(@intCast(fn_info.param_types.len)));
600 for (fn_info.param_types, 0..) |param_type, i| {
601 const id: ResultId = @enumFromInt(params_id_base + @as(u32, @intCast(i)));
602 try self.section.emit(self.arena, .OpFunctionParameter, .{
603 .id_result_type = param_type,
604 .id_result = id,
605 });
606 }
607
608 try self.section.emit(self.arena, .OpLabel, .{
609 .id_result = self.allocId(),
610 });
611
612 // Besides the IDs of the main kernel, we also need the
613 // dependencies of the globals.
614 // Just quickly construct that set here.
615 all_function_invocation_globals.clearRetainingCapacity();
616 for (fn_info.invocation_globals.keys()) |global| {
617 try all_function_invocation_globals.put(global, {});
618 const global_info = info.invocation_globals.get(global).?;
619 for (global_info.dependencies.keys()) |dependency| {
620 try all_function_invocation_globals.put(dependency, {});
621 }
622 }
623
624 // Declare the IDs of the invocation globals.
625 const global_id_base: u32 = @intFromEnum(self.allocIds(@intCast(all_function_invocation_globals.count())));
626 for (all_function_invocation_globals.keys(), 0..) |global, i| {
627 const global_info = info.invocation_globals.get(global).?;
628
629 const id: ResultId = @enumFromInt(global_id_base + @as(u32, @intCast(i)));
630 try self.section.emit(self.arena, .OpVariable, .{
631 .id_result_type = global_info.ty,
632 .id_result = id,
633 .storage_class = .Function,
634 .initializer = null,
635 });
636 }
637
638 // Call initializers for invocation globals that need it
639 for (all_function_invocation_globals.keys()) |global| {
640 const global_info = info.invocation_globals.get(global).?;
641 if (global_info.initializer == .none) continue;
642
643 const initializer_info = info.functions.get(global_info.initializer).?;
644 assert(initializer_info.param_types.len == 0);
645
646 try self.callWithGlobalsAndLinearParams(
647 all_function_invocation_globals,
648 global_info.initializer,
649 initializer_info,
650 global_id_base,
651 undefined,
652 );
653 }
654
655 // Call the main kernel entry
656 try self.callWithGlobalsAndLinearParams(
657 all_function_invocation_globals,
658 func,
659 fn_info,
660 global_id_base,
661 params_id_base,
662 );
663
664 try self.section.emit(self.arena, .OpReturn, {});
665 try self.section.emit(self.arena, .OpFunctionEnd, {});
666 }
667 }
668
669 fn callWithGlobalsAndLinearParams(
670 self: *ModuleBuilder,
671 all_globals: std.AutoArrayHashMap(ResultId, void),
672 func: ResultId,
673 callee_info: ModuleInfo.Fn,
674 global_id_base: u32,
675 params_id_base: u32,
676 ) !void {
677 const total_arguments = callee_info.invocation_globals.count() + callee_info.param_types.len;
678 try self.section.emitRaw(self.arena, .OpFunctionCall, 3 + total_arguments);
679 self.section.writeOperand(ResultId, callee_info.return_type);
680 self.section.writeOperand(ResultId, self.allocId());
681 self.section.writeOperand(ResultId, func);
682
683 // Add the invocation globals
684 for (callee_info.invocation_globals.keys()) |global| {
685 const index = all_globals.getIndex(global).?;
686 const id: ResultId = @enumFromInt(global_id_base + @as(u32, @intCast(index)));
687 self.section.writeOperand(ResultId, id);
688 }
689
690 // Add the arguments
691 for (0..callee_info.param_types.len) |index| {
692 const id: ResultId = @enumFromInt(params_id_base + @as(u32, @intCast(index)));
693 self.section.writeOperand(ResultId, id);
694 }
695 }
696};
697
698pub fn run(parser: *BinaryModule.Parser, binary: BinaryModule) ![]Word {
699 var arena = std.heap.ArenaAllocator.init(parser.a);
700 defer arena.deinit();
701 const a = arena.allocator();
702
703 var info = try ModuleInfo.parse(a, parser, binary);
704 try info.resolve(a);
705
706 var builder = try ModuleBuilder.init(a, binary, info);
707 try builder.deriveNewFnInfo(info);
708 try builder.processPreamble(binary, info);
709 try builder.emitFunctionTypes(info);
710 try builder.rewriteFunctions(parser, binary, info);
711 try builder.emitNewEntryPoints(info);
712
713 return builder.finalize(parser.a);
714}
test/behavior/basic.zig+1
...@@ -757,6 +757,7 @@ test "extern variable with non-pointer opaque type" {...@@ -757,6 +757,7 @@ test "extern variable with non-pointer opaque type" {
757 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO757 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
758 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO758 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
759 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;759 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
760 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
760761
761 @export(var_to_export, .{ .name = "opaque_extern_var" });762 @export(var_to_export, .{ .name = "opaque_extern_var" });
762 try expect(@as(*align(1) u32, @ptrCast(&opaque_extern_var)).* == 42);763 try expect(@as(*align(1) u32, @ptrCast(&opaque_extern_var)).* == 42);
tools/gen_spirv_spec.zig+38-3
...@@ -42,6 +42,26 @@ const StringPairContext = struct {...@@ -42,6 +42,26 @@ const StringPairContext = struct {
4242
43const OperandKindMap = std.ArrayHashMap(StringPair, OperandKind, StringPairContext, true);43const OperandKindMap = std.ArrayHashMap(StringPair, OperandKind, StringPairContext, true);
4444
45/// Khronos made it so that these names are not defined explicitly, so
46/// we need to hardcode it (like they did).
47/// See https://github.com/KhronosGroup/SPIRV-Registry/
48const set_names = std.ComptimeStringMap([]const u8, .{
49 .{ "opencl.std.100", "OpenCL.std" },
50 .{ "glsl.std.450", "GLSL.std.450" },
51 .{ "opencl.debuginfo.100", "OpenCL.DebugInfo.100" },
52 .{ "spv-amd-shader-ballot", "SPV_AMD_shader_ballot" },
53 .{ "nonsemantic.shader.debuginfo.100", "NonSemantic.Shader.DebugInfo.100" },
54 .{ "nonsemantic.vkspreflection", "NonSemantic.VkspReflection" },
55 .{ "nonsemantic.clspvreflection", "NonSemantic.ClspvReflection.6" }, // This version needs to be handled manually
56 .{ "spv-amd-gcn-shader", "SPV_AMD_gcn_shader" },
57 .{ "spv-amd-shader-trinary-minmax", "SPV_AMD_shader_trinary_minmax" },
58 .{ "debuginfo", "DebugInfo" },
59 .{ "nonsemantic.debugprintf", "NonSemantic.DebugPrintf" },
60 .{ "spv-amd-shader-explicit-vertex-parameter", "SPV_AMD_shader_explicit_vertex_parameter" },
61 .{ "nonsemantic.debugbreak", "NonSemantic.DebugBreak" },
62 .{ "zig", "zig" },
63});
64
45pub fn main() !void {65pub fn main() !void {
46 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);66 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
47 defer arena.deinit();67 defer arena.deinit();
...@@ -88,7 +108,7 @@ fn readExtRegistry(exts: *std.ArrayList(Extension), a: Allocator, dir: std.fs.Di...@@ -88,7 +108,7 @@ fn readExtRegistry(exts: *std.ArrayList(Extension), a: Allocator, dir: std.fs.Di
88108
89 std.sort.block(Instruction, spec.instructions, CmpInst{}, CmpInst.lt);109 std.sort.block(Instruction, spec.instructions, CmpInst{}, CmpInst.lt);
90110
91 try exts.append(.{ .name = try a.dupe(u8, name), .spec = spec });111 try exts.append(.{ .name = set_names.get(name).?, .spec = spec });
92}112}
93113
94fn readRegistry(comptime RegistryType: type, a: Allocator, dir: std.fs.Dir, path: []const u8) !RegistryType {114fn readRegistry(comptime RegistryType: type, a: Allocator, dir: std.fs.Dir, path: []const u8) !RegistryType {
...@@ -150,6 +170,8 @@ fn render(writer: anytype, a: Allocator, registry: CoreRegistry, extensions: []c...@@ -150,6 +170,8 @@ fn render(writer: anytype, a: Allocator, registry: CoreRegistry, extensions: []c
150 try writer.writeAll(170 try writer.writeAll(
151 \\//! This file is auto-generated by tools/gen_spirv_spec.zig.171 \\//! This file is auto-generated by tools/gen_spirv_spec.zig.
152 \\172 \\
173 \\const std = @import("std");
174 \\
153 \\pub const Version = packed struct(Word) {175 \\pub const Version = packed struct(Word) {
154 \\ padding: u8 = 0,176 \\ padding: u8 = 0,
155 \\ minor: u8,177 \\ minor: u8,
...@@ -163,8 +185,20 @@ fn render(writer: anytype, a: Allocator, registry: CoreRegistry, extensions: []c...@@ -163,8 +185,20 @@ fn render(writer: anytype, a: Allocator, registry: CoreRegistry, extensions: []c
163 \\185 \\
164 \\pub const Word = u32;186 \\pub const Word = u32;
165 \\pub const IdResult = enum(Word) {187 \\pub const IdResult = enum(Word) {
166 \\ none,188 \\ none,
167 \\ _,189 \\ _,
190 \\
191 \\ pub fn format(
192 \\ self: IdResult,
193 \\ comptime _: []const u8,
194 \\ _: std.fmt.FormatOptions,
195 \\ writer: anytype,
196 \\ ) @TypeOf(writer).Error!void {
197 \\ switch (self) {
198 \\ .none => try writer.writeAll("(none)"),
199 \\ else => try writer.print("%{}", .{@intFromEnum(self)}),
200 \\ }
201 \\ }
168 \\};202 \\};
169 \\pub const IdResultType = IdResult;203 \\pub const IdResultType = IdResult;
170 \\pub const IdRef = IdResult;204 \\pub const IdRef = IdResult;
...@@ -220,6 +254,7 @@ fn render(writer: anytype, a: Allocator, registry: CoreRegistry, extensions: []c...@@ -220,6 +254,7 @@ fn render(writer: anytype, a: Allocator, registry: CoreRegistry, extensions: []c
220 \\ operands: []const Operand,254 \\ operands: []const Operand,
221 \\};255 \\};
222 \\256 \\
257 \\pub const zig_generator_id: Word = 41;
223 \\258 \\
224 );259 );
225260