mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
spirv: snake-case the spec
This commit is contained in:
parent
2f3cd175d3
commit
f43f89a705
File diff suppressed because it is too large
Load Diff
@ -7,8 +7,7 @@ const assert = std.debug.assert;
|
|||||||
const spec = @import("spec.zig");
|
const spec = @import("spec.zig");
|
||||||
const Opcode = spec.Opcode;
|
const Opcode = spec.Opcode;
|
||||||
const Word = spec.Word;
|
const Word = spec.Word;
|
||||||
const IdRef = spec.IdRef;
|
const Id = spec.Id;
|
||||||
const IdResult = spec.IdResult;
|
|
||||||
const StorageClass = spec.StorageClass;
|
const StorageClass = spec.StorageClass;
|
||||||
|
|
||||||
const SpvModule = @import("Module.zig");
|
const SpvModule = @import("Module.zig");
|
||||||
@ -127,10 +126,10 @@ const AsmValue = union(enum) {
|
|||||||
unresolved_forward_reference,
|
unresolved_forward_reference,
|
||||||
|
|
||||||
/// This result-value is a normal result produced by a different instruction.
|
/// This result-value is a normal result produced by a different instruction.
|
||||||
value: IdRef,
|
value: Id,
|
||||||
|
|
||||||
/// This result-value represents a type registered into the module's type system.
|
/// This result-value represents a type registered into the module's type system.
|
||||||
ty: IdRef,
|
ty: Id,
|
||||||
|
|
||||||
/// This is a pre-supplied constant integer value.
|
/// This is a pre-supplied constant integer value.
|
||||||
constant: u32,
|
constant: u32,
|
||||||
@ -141,7 +140,7 @@ const AsmValue = union(enum) {
|
|||||||
/// Retrieve the result-id of this AsmValue. Asserts that this AsmValue
|
/// Retrieve the result-id of this AsmValue. Asserts that this AsmValue
|
||||||
/// is of a variant that allows the result to be obtained (not an unresolved
|
/// is of a variant that allows the result to be obtained (not an unresolved
|
||||||
/// forward declaration, not in the process of being declared, etc).
|
/// forward declaration, not in the process of being declared, etc).
|
||||||
pub fn resultId(self: AsmValue) IdRef {
|
pub fn resultId(self: AsmValue) Id {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.just_declared,
|
.just_declared,
|
||||||
.unresolved_forward_reference,
|
.unresolved_forward_reference,
|
||||||
@ -314,7 +313,7 @@ fn processInstruction(self: *Assembler) !void {
|
|||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
else => switch (self.inst.opcode.class()) {
|
else => switch (self.inst.opcode.class()) {
|
||||||
.TypeDeclaration => try self.processTypeInstruction(),
|
.type_declaration => try self.processTypeInstruction(),
|
||||||
else => (try self.processGenericInstruction()) orelse return,
|
else => (try self.processGenericInstruction()) orelse return,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -392,7 +391,7 @@ fn processTypeInstruction(self: *Assembler) !AsmValue {
|
|||||||
break :blk result_id;
|
break :blk result_id;
|
||||||
},
|
},
|
||||||
.OpTypeStruct => blk: {
|
.OpTypeStruct => blk: {
|
||||||
const ids = try self.gpa.alloc(IdRef, operands[1..].len);
|
const ids = try self.gpa.alloc(Id, operands[1..].len);
|
||||||
defer self.gpa.free(ids);
|
defer self.gpa.free(ids);
|
||||||
for (operands[1..], ids) |op, *id| id.* = try self.resolveRefId(op.ref_id);
|
for (operands[1..], ids) |op, *id| id.* = try self.resolveRefId(op.ref_id);
|
||||||
const result_id = self.spv.allocId();
|
const result_id = self.spv.allocId();
|
||||||
@ -429,7 +428,7 @@ fn processTypeInstruction(self: *Assembler) !AsmValue {
|
|||||||
const param_operands = operands[2..];
|
const param_operands = operands[2..];
|
||||||
const return_type = try self.resolveRefId(operands[1].ref_id);
|
const return_type = try self.resolveRefId(operands[1].ref_id);
|
||||||
|
|
||||||
const param_types = try self.spv.gpa.alloc(IdRef, param_operands.len);
|
const param_types = try self.spv.gpa.alloc(Id, param_operands.len);
|
||||||
defer self.spv.gpa.free(param_types);
|
defer self.spv.gpa.free(param_types);
|
||||||
for (param_types, param_operands) |*param, operand| {
|
for (param_types, param_operands) |*param, operand| {
|
||||||
param.* = try self.resolveRefId(operand.ref_id);
|
param.* = try self.resolveRefId(operand.ref_id);
|
||||||
@ -457,17 +456,17 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue {
|
|||||||
const operands = self.inst.operands.items;
|
const operands = self.inst.operands.items;
|
||||||
var maybe_spv_decl_index: ?SpvModule.Decl.Index = null;
|
var maybe_spv_decl_index: ?SpvModule.Decl.Index = null;
|
||||||
const section = switch (self.inst.opcode.class()) {
|
const section = switch (self.inst.opcode.class()) {
|
||||||
.ConstantCreation => &self.spv.sections.types_globals_constants,
|
.constant_creation => &self.spv.sections.types_globals_constants,
|
||||||
.Annotation => &self.spv.sections.annotations,
|
.annotation => &self.spv.sections.annotations,
|
||||||
.TypeDeclaration => unreachable, // Handled elsewhere.
|
.type_declaration => unreachable, // Handled elsewhere.
|
||||||
else => switch (self.inst.opcode) {
|
else => switch (self.inst.opcode) {
|
||||||
.OpEntryPoint => unreachable,
|
.OpEntryPoint => unreachable,
|
||||||
.OpExecutionMode, .OpExecutionModeId => &self.spv.sections.execution_modes,
|
.OpExecutionMode, .OpExecutionModeId => &self.spv.sections.execution_modes,
|
||||||
.OpVariable => section: {
|
.OpVariable => section: {
|
||||||
const storage_class: spec.StorageClass = @enumFromInt(operands[2].value);
|
const storage_class: spec.StorageClass = @enumFromInt(operands[2].value);
|
||||||
if (storage_class == .Function) break :section &self.func.prologue;
|
if (storage_class == .function) break :section &self.func.prologue;
|
||||||
maybe_spv_decl_index = try self.spv.allocDecl(.global);
|
maybe_spv_decl_index = try self.spv.allocDecl(.global);
|
||||||
if (self.spv.version.minor < 4 and storage_class != .Input and storage_class != .Output) {
|
if (self.spv.version.minor < 4 and storage_class != .input and storage_class != .output) {
|
||||||
// Before version 1.4, the interface’s storage classes are limited to the Input and Output
|
// Before version 1.4, the interface’s storage classes are limited to the Input and Output
|
||||||
break :section &self.spv.sections.types_globals_constants;
|
break :section &self.spv.sections.types_globals_constants;
|
||||||
}
|
}
|
||||||
@ -481,7 +480,7 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var maybe_result_id: ?IdResult = null;
|
var maybe_result_id: ?Id = null;
|
||||||
const first_word = section.instructions.items.len;
|
const first_word = section.instructions.items.len;
|
||||||
// At this point we're not quite sure how many operands this instruction is going to have,
|
// At this point we're not quite sure how many operands this instruction is going to have,
|
||||||
// so insert 0 and patch up the actual opcode word later.
|
// so insert 0 and patch up the actual opcode word later.
|
||||||
@ -504,12 +503,12 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue {
|
|||||||
else
|
else
|
||||||
self.spv.allocId();
|
self.spv.allocId();
|
||||||
try section.ensureUnusedCapacity(self.spv.gpa, 1);
|
try section.ensureUnusedCapacity(self.spv.gpa, 1);
|
||||||
section.writeOperand(IdResult, maybe_result_id.?);
|
section.writeOperand(Id, maybe_result_id.?);
|
||||||
},
|
},
|
||||||
.ref_id => |index| {
|
.ref_id => |index| {
|
||||||
const result = try self.resolveRef(index);
|
const result = try self.resolveRef(index);
|
||||||
try section.ensureUnusedCapacity(self.spv.gpa, 1);
|
try section.ensureUnusedCapacity(self.spv.gpa, 1);
|
||||||
section.writeOperand(spec.IdRef, result.resultId());
|
section.writeOperand(spec.Id, result.resultId());
|
||||||
},
|
},
|
||||||
.string => |offset| {
|
.string => |offset| {
|
||||||
const text = std.mem.sliceTo(self.inst.string_bytes.items[offset..], 0);
|
const text = std.mem.sliceTo(self.inst.string_bytes.items[offset..], 0);
|
||||||
@ -558,7 +557,7 @@ fn resolveRef(self: *Assembler, ref: AsmValue.Ref) !AsmValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolveRefId(self: *Assembler, ref: AsmValue.Ref) !IdRef {
|
fn resolveRefId(self: *Assembler, ref: AsmValue.Ref) !Id {
|
||||||
const value = try self.resolveRef(ref);
|
const value = try self.resolveRef(ref);
|
||||||
return value.resultId();
|
return value.resultId();
|
||||||
}
|
}
|
||||||
@ -600,7 +599,7 @@ fn parseInstruction(self: *Assembler) !void {
|
|||||||
const expected_operands = inst.operands;
|
const expected_operands = inst.operands;
|
||||||
// This is a loop because the result-id is not always the first operand.
|
// This is a loop because the result-id is not always the first operand.
|
||||||
const requires_lhs_result = for (expected_operands) |op| {
|
const requires_lhs_result = for (expected_operands) |op| {
|
||||||
if (op.kind == .IdResult) break true;
|
if (op.kind == .id_result) break true;
|
||||||
} else false;
|
} else false;
|
||||||
|
|
||||||
if (requires_lhs_result and maybe_lhs_result == null) {
|
if (requires_lhs_result and maybe_lhs_result == null) {
|
||||||
@ -614,7 +613,7 @@ fn parseInstruction(self: *Assembler) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (expected_operands) |operand| {
|
for (expected_operands) |operand| {
|
||||||
if (operand.kind == .IdResult) {
|
if (operand.kind == .id_result) {
|
||||||
try self.inst.operands.append(self.gpa, .{ .result_id = maybe_lhs_result.? });
|
try self.inst.operands.append(self.gpa, .{ .result_id = maybe_lhs_result.? });
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -646,11 +645,11 @@ fn parseOperand(self: *Assembler, kind: spec.OperandKind) Error!void {
|
|||||||
.value_enum => try self.parseValueEnum(kind),
|
.value_enum => try self.parseValueEnum(kind),
|
||||||
.id => try self.parseRefId(),
|
.id => try self.parseRefId(),
|
||||||
else => switch (kind) {
|
else => switch (kind) {
|
||||||
.LiteralInteger => try self.parseLiteralInteger(),
|
.literal_integer => try self.parseLiteralInteger(),
|
||||||
.LiteralString => try self.parseString(),
|
.literal_string => try self.parseString(),
|
||||||
.LiteralContextDependentNumber => try self.parseContextDependentNumber(),
|
.literal_context_dependent_number => try self.parseContextDependentNumber(),
|
||||||
.LiteralExtInstInteger => try self.parseLiteralExtInstInteger(),
|
.literal_ext_inst_integer => try self.parseLiteralExtInstInteger(),
|
||||||
.PairIdRefIdRef => try self.parsePhiSource(),
|
.pair_id_ref_id_ref => try self.parsePhiSource(),
|
||||||
else => return self.todo("parse operand of type {s}", .{@tagName(kind)}),
|
else => return self.todo("parse operand of type {s}", .{@tagName(kind)}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,9 +15,7 @@ const Wyhash = std.hash.Wyhash;
|
|||||||
|
|
||||||
const spec = @import("spec.zig");
|
const spec = @import("spec.zig");
|
||||||
const Word = spec.Word;
|
const Word = spec.Word;
|
||||||
const IdRef = spec.IdRef;
|
const Id = spec.Id;
|
||||||
const IdResult = spec.IdResult;
|
|
||||||
const IdResultType = spec.IdResultType;
|
|
||||||
|
|
||||||
const Section = @import("Section.zig");
|
const Section = @import("Section.zig");
|
||||||
|
|
||||||
@ -82,7 +80,7 @@ pub const Decl = struct {
|
|||||||
/// - For `func`, this is the result-id of the associated OpFunction instruction.
|
/// - For `func`, this is the result-id of the associated OpFunction instruction.
|
||||||
/// - For `global`, this is the result-id of the associated OpVariable instruction.
|
/// - For `global`, this is the result-id of the associated OpVariable instruction.
|
||||||
/// - For `invocation_global`, this is the result-id of the associated InvocationGlobal instruction.
|
/// - For `invocation_global`, this is the result-id of the associated InvocationGlobal instruction.
|
||||||
result_id: IdRef,
|
result_id: Id,
|
||||||
/// The offset of the first dependency of this decl in the `decl_deps` array.
|
/// The offset of the first dependency of this decl in the `decl_deps` array.
|
||||||
begin_dep: u32,
|
begin_dep: u32,
|
||||||
/// The past-end offset of the dependencies of this decl in the `decl_deps` array.
|
/// The past-end offset of the dependencies of this decl in the `decl_deps` array.
|
||||||
@ -150,7 +148,7 @@ sections: struct {
|
|||||||
next_result_id: Word,
|
next_result_id: Word,
|
||||||
|
|
||||||
/// Cache for results of OpString instructions.
|
/// Cache for results of OpString instructions.
|
||||||
strings: std.StringArrayHashMapUnmanaged(IdRef) = .empty,
|
strings: std.StringArrayHashMapUnmanaged(Id) = .empty,
|
||||||
|
|
||||||
/// Some types shouldn't be emitted more than one time, but cannot be caught by
|
/// Some types shouldn't be emitted more than one time, but cannot be caught by
|
||||||
/// the `intern_map` during codegen. Sometimes, IDs are compared to check if
|
/// the `intern_map` during codegen. Sometimes, IDs are compared to check if
|
||||||
@ -161,20 +159,20 @@ strings: std.StringArrayHashMapUnmanaged(IdRef) = .empty,
|
|||||||
/// Additionally, this is used for other values which can be cached, for example,
|
/// Additionally, this is used for other values which can be cached, for example,
|
||||||
/// built-in variables.
|
/// built-in variables.
|
||||||
cache: struct {
|
cache: struct {
|
||||||
bool_type: ?IdRef = null,
|
bool_type: ?Id = null,
|
||||||
void_type: ?IdRef = null,
|
void_type: ?Id = null,
|
||||||
int_types: std.AutoHashMapUnmanaged(std.builtin.Type.Int, IdRef) = .empty,
|
int_types: std.AutoHashMapUnmanaged(std.builtin.Type.Int, Id) = .empty,
|
||||||
float_types: std.AutoHashMapUnmanaged(std.builtin.Type.Float, IdRef) = .empty,
|
float_types: std.AutoHashMapUnmanaged(std.builtin.Type.Float, Id) = .empty,
|
||||||
vector_types: std.AutoHashMapUnmanaged(struct { IdRef, u32 }, IdRef) = .empty,
|
vector_types: std.AutoHashMapUnmanaged(struct { Id, u32 }, Id) = .empty,
|
||||||
array_types: std.AutoHashMapUnmanaged(struct { IdRef, IdRef }, IdRef) = .empty,
|
array_types: std.AutoHashMapUnmanaged(struct { Id, Id }, Id) = .empty,
|
||||||
|
|
||||||
capabilities: std.AutoHashMapUnmanaged(spec.Capability, void) = .empty,
|
capabilities: std.AutoHashMapUnmanaged(spec.Capability, void) = .empty,
|
||||||
extensions: std.StringHashMapUnmanaged(void) = .empty,
|
extensions: std.StringHashMapUnmanaged(void) = .empty,
|
||||||
extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, IdRef) = .empty,
|
extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, Id) = .empty,
|
||||||
decorations: std.AutoHashMapUnmanaged(struct { IdRef, spec.Decoration }, void) = .empty,
|
decorations: std.AutoHashMapUnmanaged(struct { Id, spec.Decoration }, void) = .empty,
|
||||||
builtins: std.AutoHashMapUnmanaged(struct { IdRef, spec.BuiltIn }, Decl.Index) = .empty,
|
builtins: std.AutoHashMapUnmanaged(struct { Id, spec.BuiltIn }, Decl.Index) = .empty,
|
||||||
|
|
||||||
bool_const: [2]?IdRef = .{ null, null },
|
bool_const: [2]?Id = .{ null, null },
|
||||||
} = .{},
|
} = .{},
|
||||||
|
|
||||||
/// Set of Decls, referred to by Decl.Index.
|
/// Set of Decls, referred to by Decl.Index.
|
||||||
@ -185,7 +183,7 @@ decls: std.ArrayListUnmanaged(Decl) = .empty,
|
|||||||
decl_deps: std.ArrayListUnmanaged(Decl.Index) = .empty,
|
decl_deps: std.ArrayListUnmanaged(Decl.Index) = .empty,
|
||||||
|
|
||||||
/// The list of entry points that should be exported from this module.
|
/// The list of entry points that should be exported from this module.
|
||||||
entry_points: std.AutoArrayHashMapUnmanaged(IdRef, EntryPoint) = .empty,
|
entry_points: std.AutoArrayHashMapUnmanaged(Id, EntryPoint) = .empty,
|
||||||
|
|
||||||
pub fn init(gpa: Allocator, target: *const std.Target) Module {
|
pub fn init(gpa: Allocator, target: *const std.Target) Module {
|
||||||
const version_minor: u8 = blk: {
|
const version_minor: u8 = blk: {
|
||||||
@ -245,7 +243,7 @@ pub const IdRange = struct {
|
|||||||
base: u32,
|
base: u32,
|
||||||
len: u32,
|
len: u32,
|
||||||
|
|
||||||
pub fn at(range: IdRange, i: usize) IdResult {
|
pub fn at(range: IdRange, i: usize) Id {
|
||||||
assert(i < range.len);
|
assert(i < range.len);
|
||||||
return @enumFromInt(range.base + i);
|
return @enumFromInt(range.base + i);
|
||||||
}
|
}
|
||||||
@ -259,7 +257,7 @@ pub fn allocIds(self: *Module, n: u32) IdRange {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocId(self: *Module) IdResult {
|
pub fn allocId(self: *Module) Id {
|
||||||
return self.allocIds(1).at(0);
|
return self.allocIds(1).at(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +273,7 @@ fn addEntryPointDeps(
|
|||||||
self: *Module,
|
self: *Module,
|
||||||
decl_index: Decl.Index,
|
decl_index: Decl.Index,
|
||||||
seen: *std.DynamicBitSetUnmanaged,
|
seen: *std.DynamicBitSetUnmanaged,
|
||||||
interface: *std.ArrayList(IdRef),
|
interface: *std.ArrayList(Id),
|
||||||
) !void {
|
) !void {
|
||||||
const decl = self.declPtr(decl_index);
|
const decl = self.declPtr(decl_index);
|
||||||
const deps = self.decl_deps.items[decl.begin_dep..decl.end_dep];
|
const deps = self.decl_deps.items[decl.begin_dep..decl.end_dep];
|
||||||
@ -299,7 +297,7 @@ fn entryPoints(self: *Module) !Section {
|
|||||||
var entry_points = Section{};
|
var entry_points = Section{};
|
||||||
errdefer entry_points.deinit(self.gpa);
|
errdefer entry_points.deinit(self.gpa);
|
||||||
|
|
||||||
var interface = std.ArrayList(IdRef).init(self.gpa);
|
var interface = std.ArrayList(Id).init(self.gpa);
|
||||||
defer interface.deinit();
|
defer interface.deinit();
|
||||||
|
|
||||||
var seen = try std.DynamicBitSetUnmanaged.initEmpty(self.gpa, self.decls.items.len);
|
var seen = try std.DynamicBitSetUnmanaged.initEmpty(self.gpa, self.decls.items.len);
|
||||||
@ -317,12 +315,12 @@ fn entryPoints(self: *Module) !Section {
|
|||||||
.interface = interface.items,
|
.interface = interface.items,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (entry_point.exec_mode == null and entry_point.exec_model == .Fragment) {
|
if (entry_point.exec_mode == null and entry_point.exec_model == .fragment) {
|
||||||
switch (self.target.os.tag) {
|
switch (self.target.os.tag) {
|
||||||
.vulkan, .opengl => |tag| {
|
.vulkan, .opengl => |tag| {
|
||||||
try self.sections.execution_modes.emit(self.gpa, .OpExecutionMode, .{
|
try self.sections.execution_modes.emit(self.gpa, .OpExecutionMode, .{
|
||||||
.entry_point = entry_point_id,
|
.entry_point = entry_point_id,
|
||||||
.mode = if (tag == .vulkan) .OriginUpperLeft else .OriginLowerLeft,
|
.mode = if (tag == .vulkan) .origin_upper_left else .origin_lower_left,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.opencl => {},
|
.opencl => {},
|
||||||
@ -338,59 +336,59 @@ pub fn finalize(self: *Module, a: Allocator) ![]Word {
|
|||||||
// Emit capabilities and extensions
|
// Emit capabilities and extensions
|
||||||
switch (self.target.os.tag) {
|
switch (self.target.os.tag) {
|
||||||
.opengl => {
|
.opengl => {
|
||||||
try self.addCapability(.Shader);
|
try self.addCapability(.shader);
|
||||||
try self.addCapability(.Matrix);
|
try self.addCapability(.matrix);
|
||||||
},
|
},
|
||||||
.vulkan => {
|
.vulkan => {
|
||||||
try self.addCapability(.Shader);
|
try self.addCapability(.shader);
|
||||||
try self.addCapability(.Matrix);
|
try self.addCapability(.matrix);
|
||||||
if (self.target.cpu.arch == .spirv64) {
|
if (self.target.cpu.arch == .spirv64) {
|
||||||
try self.addExtension("SPV_KHR_physical_storage_buffer");
|
try self.addExtension("SPV_KHR_physical_storage_buffer");
|
||||||
try self.addCapability(.PhysicalStorageBufferAddresses);
|
try self.addCapability(.physical_storage_buffer_addresses);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.opencl, .amdhsa => {
|
.opencl, .amdhsa => {
|
||||||
try self.addCapability(.Kernel);
|
try self.addCapability(.kernel);
|
||||||
try self.addCapability(.Addresses);
|
try self.addCapability(.addresses);
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
if (self.target.cpu.arch == .spirv64) try self.addCapability(.Int64);
|
if (self.target.cpu.arch == .spirv64) try self.addCapability(.int64);
|
||||||
if (self.target.cpu.has(.spirv, .int64)) try self.addCapability(.Int64);
|
if (self.target.cpu.has(.spirv, .int64)) try self.addCapability(.int64);
|
||||||
if (self.target.cpu.has(.spirv, .float16)) try self.addCapability(.Float16);
|
if (self.target.cpu.has(.spirv, .float16)) try self.addCapability(.float16);
|
||||||
if (self.target.cpu.has(.spirv, .float64)) try self.addCapability(.Float64);
|
if (self.target.cpu.has(.spirv, .float64)) try self.addCapability(.float64);
|
||||||
if (self.target.cpu.has(.spirv, .generic_pointer)) try self.addCapability(.GenericPointer);
|
if (self.target.cpu.has(.spirv, .generic_pointer)) try self.addCapability(.generic_pointer);
|
||||||
if (self.target.cpu.has(.spirv, .vector16)) try self.addCapability(.Vector16);
|
if (self.target.cpu.has(.spirv, .vector16)) try self.addCapability(.vector16);
|
||||||
if (self.target.cpu.has(.spirv, .storage_push_constant16)) {
|
if (self.target.cpu.has(.spirv, .storage_push_constant16)) {
|
||||||
try self.addExtension("SPV_KHR_16bit_storage");
|
try self.addExtension("SPV_KHR_16bit_storage");
|
||||||
try self.addCapability(.StoragePushConstant16);
|
try self.addCapability(.storage_push_constant16);
|
||||||
}
|
}
|
||||||
if (self.target.cpu.has(.spirv, .arbitrary_precision_integers)) {
|
if (self.target.cpu.has(.spirv, .arbitrary_precision_integers)) {
|
||||||
try self.addExtension("SPV_INTEL_arbitrary_precision_integers");
|
try self.addExtension("SPV_INTEL_arbitrary_precision_integers");
|
||||||
try self.addCapability(.ArbitraryPrecisionIntegersINTEL);
|
try self.addCapability(.arbitrary_precision_integers_intel);
|
||||||
}
|
}
|
||||||
if (self.target.cpu.has(.spirv, .variable_pointers)) {
|
if (self.target.cpu.has(.spirv, .variable_pointers)) {
|
||||||
try self.addExtension("SPV_KHR_variable_pointers");
|
try self.addExtension("SPV_KHR_variable_pointers");
|
||||||
try self.addCapability(.VariablePointersStorageBuffer);
|
try self.addCapability(.variable_pointers_storage_buffer);
|
||||||
try self.addCapability(.VariablePointers);
|
try self.addCapability(.variable_pointers);
|
||||||
}
|
}
|
||||||
// These are well supported
|
// These are well supported
|
||||||
try self.addCapability(.Int8);
|
try self.addCapability(.int8);
|
||||||
try self.addCapability(.Int16);
|
try self.addCapability(.int16);
|
||||||
|
|
||||||
// Emit memory model
|
// Emit memory model
|
||||||
const addressing_model: spec.AddressingModel = switch (self.target.os.tag) {
|
const addressing_model: spec.AddressingModel = switch (self.target.os.tag) {
|
||||||
.opengl => .Logical,
|
.opengl => .logical,
|
||||||
.vulkan => if (self.target.cpu.arch == .spirv32) .Logical else .PhysicalStorageBuffer64,
|
.vulkan => if (self.target.cpu.arch == .spirv32) .logical else .physical_storage_buffer64,
|
||||||
.opencl => if (self.target.cpu.arch == .spirv32) .Physical32 else .Physical64,
|
.opencl => if (self.target.cpu.arch == .spirv32) .physical32 else .physical64,
|
||||||
.amdhsa => .Physical64,
|
.amdhsa => .physical64,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
try self.sections.memory_model.emit(self.gpa, .OpMemoryModel, .{
|
try self.sections.memory_model.emit(self.gpa, .OpMemoryModel, .{
|
||||||
.addressing_model = addressing_model,
|
.addressing_model = addressing_model,
|
||||||
.memory_model = switch (self.target.os.tag) {
|
.memory_model = switch (self.target.os.tag) {
|
||||||
.opencl => .OpenCL,
|
.opencl => .open_cl,
|
||||||
.vulkan, .opengl => .GLSL450,
|
.vulkan, .opengl => .glsl450,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -411,7 +409,7 @@ pub fn finalize(self: *Module, a: Allocator) ![]Word {
|
|||||||
var source = Section{};
|
var source = Section{};
|
||||||
defer source.deinit(self.gpa);
|
defer source.deinit(self.gpa);
|
||||||
try self.sections.debug_strings.emit(self.gpa, .OpSource, .{
|
try self.sections.debug_strings.emit(self.gpa, .OpSource, .{
|
||||||
.source_language = .Zig,
|
.source_language = .zig,
|
||||||
.version = 0,
|
.version = 0,
|
||||||
// We cannot emit these because the Khronos translator does not parse this instruction
|
// We cannot emit these because the Khronos translator does not parse this instruction
|
||||||
// correctly.
|
// correctly.
|
||||||
@ -473,7 +471,7 @@ pub fn addExtension(self: *Module, ext: []const u8) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Imports or returns the existing id of an extended instruction set
|
/// Imports or returns the existing id of an extended instruction set
|
||||||
pub fn importInstructionSet(self: *Module, set: spec.InstructionSet) !IdRef {
|
pub fn importInstructionSet(self: *Module, set: spec.InstructionSet) !Id {
|
||||||
assert(set != .core);
|
assert(set != .core);
|
||||||
|
|
||||||
const gop = try self.cache.extended_instruction_set.getOrPut(self.gpa, set);
|
const gop = try self.cache.extended_instruction_set.getOrPut(self.gpa, set);
|
||||||
@ -490,7 +488,7 @@ pub fn importInstructionSet(self: *Module, set: spec.InstructionSet) !IdRef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch the result-id of an instruction corresponding to a string.
|
/// Fetch the result-id of an instruction corresponding to a string.
|
||||||
pub fn resolveString(self: *Module, string: []const u8) !IdRef {
|
pub fn resolveString(self: *Module, string: []const u8) !Id {
|
||||||
if (self.strings.get(string)) |id| {
|
if (self.strings.get(string)) |id| {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -506,7 +504,7 @@ pub fn resolveString(self: *Module, string: []const u8) !IdRef {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn structType(self: *Module, result_id: IdResult, types: []const IdRef, maybe_names: ?[]const []const u8) !void {
|
pub fn structType(self: *Module, result_id: Id, types: []const Id, maybe_names: ?[]const []const u8) !void {
|
||||||
try self.sections.types_globals_constants.emit(self.gpa, .OpTypeStruct, .{
|
try self.sections.types_globals_constants.emit(self.gpa, .OpTypeStruct, .{
|
||||||
.id_result = result_id,
|
.id_result = result_id,
|
||||||
.id_ref = types,
|
.id_ref = types,
|
||||||
@ -520,7 +518,7 @@ pub fn structType(self: *Module, result_id: IdResult, types: []const IdRef, mayb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn boolType(self: *Module) !IdRef {
|
pub fn boolType(self: *Module) !Id {
|
||||||
if (self.cache.bool_type) |id| return id;
|
if (self.cache.bool_type) |id| return id;
|
||||||
|
|
||||||
const result_id = self.allocId();
|
const result_id = self.allocId();
|
||||||
@ -531,7 +529,7 @@ pub fn boolType(self: *Module) !IdRef {
|
|||||||
return result_id;
|
return result_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn voidType(self: *Module) !IdRef {
|
pub fn voidType(self: *Module) !Id {
|
||||||
if (self.cache.void_type) |id| return id;
|
if (self.cache.void_type) |id| return id;
|
||||||
|
|
||||||
const result_id = self.allocId();
|
const result_id = self.allocId();
|
||||||
@ -543,7 +541,7 @@ pub fn voidType(self: *Module) !IdRef {
|
|||||||
return result_id;
|
return result_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn intType(self: *Module, signedness: std.builtin.Signedness, bits: u16) !IdRef {
|
pub fn intType(self: *Module, signedness: std.builtin.Signedness, bits: u16) !Id {
|
||||||
assert(bits > 0);
|
assert(bits > 0);
|
||||||
const entry = try self.cache.int_types.getOrPut(self.gpa, .{ .signedness = signedness, .bits = bits });
|
const entry = try self.cache.int_types.getOrPut(self.gpa, .{ .signedness = signedness, .bits = bits });
|
||||||
if (!entry.found_existing) {
|
if (!entry.found_existing) {
|
||||||
@ -566,7 +564,7 @@ pub fn intType(self: *Module, signedness: std.builtin.Signedness, bits: u16) !Id
|
|||||||
return entry.value_ptr.*;
|
return entry.value_ptr.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn floatType(self: *Module, bits: u16) !IdRef {
|
pub fn floatType(self: *Module, bits: u16) !Id {
|
||||||
assert(bits > 0);
|
assert(bits > 0);
|
||||||
const entry = try self.cache.float_types.getOrPut(self.gpa, .{ .bits = bits });
|
const entry = try self.cache.float_types.getOrPut(self.gpa, .{ .bits = bits });
|
||||||
if (!entry.found_existing) {
|
if (!entry.found_existing) {
|
||||||
@ -581,7 +579,7 @@ pub fn floatType(self: *Module, bits: u16) !IdRef {
|
|||||||
return entry.value_ptr.*;
|
return entry.value_ptr.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vectorType(self: *Module, len: u32, child_ty_id: IdRef) !IdRef {
|
pub fn vectorType(self: *Module, len: u32, child_ty_id: Id) !Id {
|
||||||
const entry = try self.cache.vector_types.getOrPut(self.gpa, .{ child_ty_id, len });
|
const entry = try self.cache.vector_types.getOrPut(self.gpa, .{ child_ty_id, len });
|
||||||
if (!entry.found_existing) {
|
if (!entry.found_existing) {
|
||||||
const result_id = self.allocId();
|
const result_id = self.allocId();
|
||||||
@ -595,7 +593,7 @@ pub fn vectorType(self: *Module, len: u32, child_ty_id: IdRef) !IdRef {
|
|||||||
return entry.value_ptr.*;
|
return entry.value_ptr.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn arrayType(self: *Module, len_id: IdRef, child_ty_id: IdRef) !IdRef {
|
pub fn arrayType(self: *Module, len_id: Id, child_ty_id: Id) !Id {
|
||||||
const entry = try self.cache.array_types.getOrPut(self.gpa, .{ child_ty_id, len_id });
|
const entry = try self.cache.array_types.getOrPut(self.gpa, .{ child_ty_id, len_id });
|
||||||
if (!entry.found_existing) {
|
if (!entry.found_existing) {
|
||||||
const result_id = self.allocId();
|
const result_id = self.allocId();
|
||||||
@ -609,7 +607,7 @@ pub fn arrayType(self: *Module, len_id: IdRef, child_ty_id: IdRef) !IdRef {
|
|||||||
return entry.value_ptr.*;
|
return entry.value_ptr.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn functionType(self: *Module, return_ty_id: IdRef, param_type_ids: []const IdRef) !IdRef {
|
pub fn functionType(self: *Module, return_ty_id: Id, param_type_ids: []const Id) !Id {
|
||||||
const result_id = self.allocId();
|
const result_id = self.allocId();
|
||||||
try self.sections.types_globals_constants.emit(self.gpa, .OpTypeFunction, .{
|
try self.sections.types_globals_constants.emit(self.gpa, .OpTypeFunction, .{
|
||||||
.id_result = result_id,
|
.id_result = result_id,
|
||||||
@ -619,7 +617,7 @@ pub fn functionType(self: *Module, return_ty_id: IdRef, param_type_ids: []const
|
|||||||
return result_id;
|
return result_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn constant(self: *Module, result_ty_id: IdRef, value: spec.LiteralContextDependentNumber) !IdRef {
|
pub fn constant(self: *Module, result_ty_id: Id, value: spec.LiteralContextDependentNumber) !Id {
|
||||||
const result_id = self.allocId();
|
const result_id = self.allocId();
|
||||||
const section = &self.sections.types_globals_constants;
|
const section = &self.sections.types_globals_constants;
|
||||||
try section.emit(self.gpa, .OpConstant, .{
|
try section.emit(self.gpa, .OpConstant, .{
|
||||||
@ -630,7 +628,7 @@ pub fn constant(self: *Module, result_ty_id: IdRef, value: spec.LiteralContextDe
|
|||||||
return result_id;
|
return result_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn constBool(self: *Module, value: bool) !IdRef {
|
pub fn constBool(self: *Module, value: bool) !Id {
|
||||||
if (self.cache.bool_const[@intFromBool(value)]) |b| return b;
|
if (self.cache.bool_const[@intFromBool(value)]) |b| return b;
|
||||||
|
|
||||||
const result_ty_id = try self.boolType();
|
const result_ty_id = try self.boolType();
|
||||||
@ -653,7 +651,7 @@ pub fn constBool(self: *Module, value: bool) !IdRef {
|
|||||||
|
|
||||||
/// Return a pointer to a builtin variable. `result_ty_id` must be a **pointer**
|
/// Return a pointer to a builtin variable. `result_ty_id` must be a **pointer**
|
||||||
/// with storage class `.Input`.
|
/// with storage class `.Input`.
|
||||||
pub fn builtin(self: *Module, result_ty_id: IdRef, spirv_builtin: spec.BuiltIn) !Decl.Index {
|
pub fn builtin(self: *Module, result_ty_id: Id, spirv_builtin: spec.BuiltIn) !Decl.Index {
|
||||||
const entry = try self.cache.builtins.getOrPut(self.gpa, .{ result_ty_id, spirv_builtin });
|
const entry = try self.cache.builtins.getOrPut(self.gpa, .{ result_ty_id, spirv_builtin });
|
||||||
if (!entry.found_existing) {
|
if (!entry.found_existing) {
|
||||||
const decl_index = try self.allocDecl(.global);
|
const decl_index = try self.allocDecl(.global);
|
||||||
@ -662,15 +660,15 @@ pub fn builtin(self: *Module, result_ty_id: IdRef, spirv_builtin: spec.BuiltIn)
|
|||||||
try self.sections.types_globals_constants.emit(self.gpa, .OpVariable, .{
|
try self.sections.types_globals_constants.emit(self.gpa, .OpVariable, .{
|
||||||
.id_result_type = result_ty_id,
|
.id_result_type = result_ty_id,
|
||||||
.id_result = result_id,
|
.id_result = result_id,
|
||||||
.storage_class = .Input,
|
.storage_class = .input,
|
||||||
});
|
});
|
||||||
try self.decorate(result_id, .{ .BuiltIn = .{ .built_in = spirv_builtin } });
|
try self.decorate(result_id, .{ .built_in = .{ .built_in = spirv_builtin } });
|
||||||
try self.declareDeclDeps(decl_index, &.{});
|
try self.declareDeclDeps(decl_index, &.{});
|
||||||
}
|
}
|
||||||
return entry.value_ptr.*;
|
return entry.value_ptr.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn constUndef(self: *Module, ty_id: IdRef) !IdRef {
|
pub fn constUndef(self: *Module, ty_id: Id) !Id {
|
||||||
const result_id = self.allocId();
|
const result_id = self.allocId();
|
||||||
try self.sections.types_globals_constants.emit(self.gpa, .OpUndef, .{
|
try self.sections.types_globals_constants.emit(self.gpa, .OpUndef, .{
|
||||||
.id_result_type = ty_id,
|
.id_result_type = ty_id,
|
||||||
@ -679,7 +677,7 @@ pub fn constUndef(self: *Module, ty_id: IdRef) !IdRef {
|
|||||||
return result_id;
|
return result_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn constNull(self: *Module, ty_id: IdRef) !IdRef {
|
pub fn constNull(self: *Module, ty_id: Id) !Id {
|
||||||
const result_id = self.allocId();
|
const result_id = self.allocId();
|
||||||
try self.sections.types_globals_constants.emit(self.gpa, .OpConstantNull, .{
|
try self.sections.types_globals_constants.emit(self.gpa, .OpConstantNull, .{
|
||||||
.id_result_type = ty_id,
|
.id_result_type = ty_id,
|
||||||
@ -691,7 +689,7 @@ pub fn constNull(self: *Module, ty_id: IdRef) !IdRef {
|
|||||||
/// Decorate a result-id.
|
/// Decorate a result-id.
|
||||||
pub fn decorate(
|
pub fn decorate(
|
||||||
self: *Module,
|
self: *Module,
|
||||||
target: IdRef,
|
target: Id,
|
||||||
decoration: spec.Decoration.Extended,
|
decoration: spec.Decoration.Extended,
|
||||||
) !void {
|
) !void {
|
||||||
const entry = try self.cache.decorations.getOrPut(self.gpa, .{ target, decoration });
|
const entry = try self.cache.decorations.getOrPut(self.gpa, .{ target, decoration });
|
||||||
@ -707,7 +705,7 @@ pub fn decorate(
|
|||||||
/// We really don't have to and shouldn't need to cache this.
|
/// We really don't have to and shouldn't need to cache this.
|
||||||
pub fn decorateMember(
|
pub fn decorateMember(
|
||||||
self: *Module,
|
self: *Module,
|
||||||
structure_type: IdRef,
|
structure_type: Id,
|
||||||
member: u32,
|
member: u32,
|
||||||
decoration: spec.Decoration.Extended,
|
decoration: spec.Decoration.Extended,
|
||||||
) !void {
|
) !void {
|
||||||
@ -762,20 +760,20 @@ pub fn declareEntryPoint(
|
|||||||
if (!gop.found_existing) gop.value_ptr.exec_mode = exec_mode;
|
if (!gop.found_existing) gop.value_ptr.exec_mode = exec_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debugName(self: *Module, target: IdResult, name: []const u8) !void {
|
pub fn debugName(self: *Module, target: Id, name: []const u8) !void {
|
||||||
try self.sections.debug_names.emit(self.gpa, .OpName, .{
|
try self.sections.debug_names.emit(self.gpa, .OpName, .{
|
||||||
.target = target,
|
.target = target,
|
||||||
.name = name,
|
.name = name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debugNameFmt(self: *Module, target: IdResult, comptime fmt: []const u8, args: anytype) !void {
|
pub fn debugNameFmt(self: *Module, target: Id, comptime fmt: []const u8, args: anytype) !void {
|
||||||
const name = try std.fmt.allocPrint(self.gpa, fmt, args);
|
const name = try std.fmt.allocPrint(self.gpa, fmt, args);
|
||||||
defer self.gpa.free(name);
|
defer self.gpa.free(name);
|
||||||
try self.debugName(target, name);
|
try self.debugName(target, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn memberDebugName(self: *Module, target: IdResult, member: u32, name: []const u8) !void {
|
pub fn memberDebugName(self: *Module, target: Id, member: u32, name: []const u8) !void {
|
||||||
try self.sections.debug_names.emit(self.gpa, .OpMemberName, .{
|
try self.sections.debug_names.emit(self.gpa, .OpMemberName, .{
|
||||||
.type = target,
|
.type = target,
|
||||||
.member = member,
|
.member = member,
|
||||||
|
|||||||
@ -79,7 +79,7 @@ pub fn emit(
|
|||||||
pub fn emitBranch(
|
pub fn emitBranch(
|
||||||
section: *Section,
|
section: *Section,
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
target_label: spec.IdRef,
|
target_label: spec.Id,
|
||||||
) !void {
|
) !void {
|
||||||
try section.emit(allocator, .OpBranch, .{
|
try section.emit(allocator, .OpBranch, .{
|
||||||
.target_label = target_label,
|
.target_label = target_label,
|
||||||
@ -94,8 +94,8 @@ pub fn emitSpecConstantOp(
|
|||||||
) !void {
|
) !void {
|
||||||
const word_count = operandsSize(opcode.Operands(), operands);
|
const word_count = operandsSize(opcode.Operands(), operands);
|
||||||
try section.emitRaw(allocator, .OpSpecConstantOp, 1 + word_count);
|
try section.emitRaw(allocator, .OpSpecConstantOp, 1 + word_count);
|
||||||
section.writeOperand(spec.IdRef, operands.id_result_type);
|
section.writeOperand(spec.Id, operands.id_result_type);
|
||||||
section.writeOperand(spec.IdRef, operands.id_result);
|
section.writeOperand(spec.Id, operands.id_result);
|
||||||
section.writeOperand(Opcode, opcode);
|
section.writeOperand(Opcode, opcode);
|
||||||
|
|
||||||
const fields = @typeInfo(opcode.Operands()).@"struct".fields;
|
const fields = @typeInfo(opcode.Operands()).@"struct".fields;
|
||||||
@ -134,7 +134,7 @@ fn writeOperands(section: *Section, comptime Operands: type, operands: Operands)
|
|||||||
|
|
||||||
pub fn writeOperand(section: *Section, comptime Operand: type, operand: Operand) void {
|
pub fn writeOperand(section: *Section, comptime Operand: type, operand: Operand) void {
|
||||||
switch (Operand) {
|
switch (Operand) {
|
||||||
spec.IdResult => section.writeWord(@intFromEnum(operand)),
|
spec.Id => section.writeWord(@intFromEnum(operand)),
|
||||||
|
|
||||||
spec.LiteralInteger => section.writeWord(operand),
|
spec.LiteralInteger => section.writeWord(operand),
|
||||||
|
|
||||||
@ -266,7 +266,7 @@ fn operandsSize(comptime Operands: type, operands: Operands) usize {
|
|||||||
|
|
||||||
fn operandSize(comptime Operand: type, operand: Operand) usize {
|
fn operandSize(comptime Operand: type, operand: Operand) usize {
|
||||||
return switch (Operand) {
|
return switch (Operand) {
|
||||||
spec.IdResult,
|
spec.Id,
|
||||||
spec.LiteralInteger,
|
spec.LiteralInteger,
|
||||||
spec.LiteralExtInstInteger,
|
spec.LiteralExtInstInteger,
|
||||||
=> 1,
|
=> 1,
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
{
|
{
|
||||||
"version": 0,
|
"version": 0,
|
||||||
"revision": 0,
|
"revision": 0,
|
||||||
"instructions": [
|
"instructions": [
|
||||||
{
|
{
|
||||||
"opname": "InvocationGlobal",
|
"opname": "InvocationGlobal",
|
||||||
"opcode": 0,
|
"opcode": 0,
|
||||||
"operands": [
|
"operands": [{ "kind": "IdRef", "name": "initializer function" }]
|
||||||
{ "kind": "IdRef", "name": "initializer function" }
|
}
|
||||||
]
|
]
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -42,7 +42,7 @@ const Value = @import("../Value.zig");
|
|||||||
const SpvModule = @import("../codegen/spirv/Module.zig");
|
const SpvModule = @import("../codegen/spirv/Module.zig");
|
||||||
const Section = @import("../codegen/spirv/Section.zig");
|
const Section = @import("../codegen/spirv/Section.zig");
|
||||||
const spec = @import("../codegen/spirv/spec.zig");
|
const spec = @import("../codegen/spirv/spec.zig");
|
||||||
const IdResult = spec.IdResult;
|
const Id = spec.Id;
|
||||||
const Word = spec.Word;
|
const Word = spec.Word;
|
||||||
|
|
||||||
const BinaryModule = @import("SpirV/BinaryModule.zig");
|
const BinaryModule = @import("SpirV/BinaryModule.zig");
|
||||||
@ -144,15 +144,15 @@ pub fn updateExports(
|
|||||||
const cc = Type.fromInterned(nav_ty).fnCallingConvention(zcu);
|
const cc = Type.fromInterned(nav_ty).fnCallingConvention(zcu);
|
||||||
const exec_model: spec.ExecutionModel = switch (target.os.tag) {
|
const exec_model: spec.ExecutionModel = switch (target.os.tag) {
|
||||||
.vulkan, .opengl => switch (cc) {
|
.vulkan, .opengl => switch (cc) {
|
||||||
.spirv_vertex => .Vertex,
|
.spirv_vertex => .vertex,
|
||||||
.spirv_fragment => .Fragment,
|
.spirv_fragment => .fragment,
|
||||||
.spirv_kernel => .GLCompute,
|
.spirv_kernel => .gl_compute,
|
||||||
// TODO: We should integrate with the Linkage capability and export this function
|
// TODO: We should integrate with the Linkage capability and export this function
|
||||||
.spirv_device => return,
|
.spirv_device => return,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
.opencl => switch (cc) {
|
.opencl => switch (cc) {
|
||||||
.spirv_kernel => .Kernel,
|
.spirv_kernel => .kernel,
|
||||||
// TODO: We should integrate with the Linkage capability and export this function
|
// TODO: We should integrate with the Linkage capability and export this function
|
||||||
.spirv_device => return,
|
.spirv_device => return,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
|
|||||||
@ -7,7 +7,7 @@ const spec = @import("../../codegen/spirv/spec.zig");
|
|||||||
const Opcode = spec.Opcode;
|
const Opcode = spec.Opcode;
|
||||||
const Word = spec.Word;
|
const Word = spec.Word;
|
||||||
const InstructionSet = spec.InstructionSet;
|
const InstructionSet = spec.InstructionSet;
|
||||||
const ResultId = spec.IdResult;
|
const ResultId = spec.Id;
|
||||||
|
|
||||||
const BinaryModule = @This();
|
const BinaryModule = @This();
|
||||||
|
|
||||||
@ -254,8 +254,8 @@ pub const Parser = struct {
|
|||||||
// with ALL operations that return an int or float.
|
// with ALL operations that return an int or float.
|
||||||
const spec_operands = inst_spec.operands;
|
const spec_operands = inst_spec.operands;
|
||||||
if (spec_operands.len >= 2 and
|
if (spec_operands.len >= 2 and
|
||||||
spec_operands[0].kind == .IdResultType and
|
spec_operands[0].kind == .id_result_type and
|
||||||
spec_operands[1].kind == .IdResult)
|
spec_operands[1].kind == .id_result)
|
||||||
{
|
{
|
||||||
if (operands.len < 2) return error.InvalidOperands;
|
if (operands.len < 2) return error.InvalidOperands;
|
||||||
if (binary.arith_type_width.get(@enumFromInt(operands[0]))) |width| {
|
if (binary.arith_type_width.get(@enumFromInt(operands[0]))) |width| {
|
||||||
@ -288,8 +288,8 @@ pub const Parser = struct {
|
|||||||
var offset: usize = 0;
|
var offset: usize = 0;
|
||||||
switch (inst.opcode) {
|
switch (inst.opcode) {
|
||||||
.OpSpecConstantOp => {
|
.OpSpecConstantOp => {
|
||||||
assert(operands[0].kind == .IdResultType);
|
assert(operands[0].kind == .id_result_type);
|
||||||
assert(operands[1].kind == .IdResult);
|
assert(operands[1].kind == .id_result);
|
||||||
offset = try self.parseOperandsResultIds(binary, inst, operands[0..2], offset, offsets);
|
offset = try self.parseOperandsResultIds(binary, inst, operands[0..2], offset, offsets);
|
||||||
|
|
||||||
if (offset >= inst.operands.len) return error.InvalidPhysicalFormat;
|
if (offset >= inst.operands.len) return error.InvalidPhysicalFormat;
|
||||||
@ -297,13 +297,13 @@ pub const Parser = struct {
|
|||||||
const spec_index = self.opcode_table.get(mapSetAndOpcode(.core, spec_opcode)) orelse
|
const spec_index = self.opcode_table.get(mapSetAndOpcode(.core, spec_opcode)) orelse
|
||||||
return error.InvalidPhysicalFormat;
|
return error.InvalidPhysicalFormat;
|
||||||
const spec_operands = InstructionSet.core.instructions()[spec_index].operands;
|
const spec_operands = InstructionSet.core.instructions()[spec_index].operands;
|
||||||
assert(spec_operands[0].kind == .IdResultType);
|
assert(spec_operands[0].kind == .id_result_type);
|
||||||
assert(spec_operands[1].kind == .IdResult);
|
assert(spec_operands[1].kind == .id_result);
|
||||||
offset = try self.parseOperandsResultIds(binary, inst, spec_operands[2..], offset + 1, offsets);
|
offset = try self.parseOperandsResultIds(binary, inst, spec_operands[2..], offset + 1, offsets);
|
||||||
},
|
},
|
||||||
.OpExtInst => {
|
.OpExtInst => {
|
||||||
assert(operands[0].kind == .IdResultType);
|
assert(operands[0].kind == .id_result_type);
|
||||||
assert(operands[1].kind == .IdResult);
|
assert(operands[1].kind == .id_result);
|
||||||
offset = try self.parseOperandsResultIds(binary, inst, operands[0..2], offset, offsets);
|
offset = try self.parseOperandsResultIds(binary, inst, operands[0..2], offset, offsets);
|
||||||
|
|
||||||
if (offset + 1 >= inst.operands.len) return error.InvalidPhysicalFormat;
|
if (offset + 1 >= inst.operands.len) return error.InvalidPhysicalFormat;
|
||||||
@ -405,8 +405,8 @@ pub const Parser = struct {
|
|||||||
offset += 1;
|
offset += 1;
|
||||||
},
|
},
|
||||||
else => switch (kind) {
|
else => switch (kind) {
|
||||||
.LiteralInteger, .LiteralFloat => offset += 1,
|
.literal_integer, .literal_float => offset += 1,
|
||||||
.LiteralString => while (true) {
|
.literal_string => while (true) {
|
||||||
if (offset >= inst.operands.len) return error.InvalidPhysicalFormat;
|
if (offset >= inst.operands.len) return error.InvalidPhysicalFormat;
|
||||||
const word = inst.operands[offset];
|
const word = inst.operands[offset];
|
||||||
offset += 1;
|
offset += 1;
|
||||||
@ -419,7 +419,7 @@ pub const Parser = struct {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.LiteralContextDependentNumber => {
|
.literal_context_dependent_number => {
|
||||||
assert(inst.opcode == .OpConstant or inst.opcode == .OpSpecConstantOp);
|
assert(inst.opcode == .OpConstant or inst.opcode == .OpSpecConstantOp);
|
||||||
const bit_width = binary.arith_type_width.get(@enumFromInt(inst.operands[0])) orelse {
|
const bit_width = binary.arith_type_width.get(@enumFromInt(inst.operands[0])) orelse {
|
||||||
log.err("invalid LiteralContextDependentNumber type {}", .{inst.operands[0]});
|
log.err("invalid LiteralContextDependentNumber type {}", .{inst.operands[0]});
|
||||||
@ -431,9 +431,9 @@ pub const Parser = struct {
|
|||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
.LiteralExtInstInteger => unreachable,
|
.literal_ext_inst_integer => unreachable,
|
||||||
.LiteralSpecConstantOpInteger => unreachable,
|
.literal_spec_constant_op_integer => unreachable,
|
||||||
.PairLiteralIntegerIdRef => { // Switch case
|
.pair_literal_integer_id_ref => { // Switch case
|
||||||
assert(inst.opcode == .OpSwitch);
|
assert(inst.opcode == .OpSwitch);
|
||||||
const bit_width = binary.arith_type_width.get(@enumFromInt(inst.operands[0])) orelse {
|
const bit_width = binary.arith_type_width.get(@enumFromInt(inst.operands[0])) orelse {
|
||||||
log.err("invalid OpSwitch type {}", .{inst.operands[0]});
|
log.err("invalid OpSwitch type {}", .{inst.operands[0]});
|
||||||
@ -447,11 +447,11 @@ pub const Parser = struct {
|
|||||||
try offsets.append(@intCast(offset));
|
try offsets.append(@intCast(offset));
|
||||||
offset += 1;
|
offset += 1;
|
||||||
},
|
},
|
||||||
.PairIdRefLiteralInteger => {
|
.pair_id_ref_literal_integer => {
|
||||||
try offsets.append(@intCast(offset));
|
try offsets.append(@intCast(offset));
|
||||||
offset += 2;
|
offset += 2;
|
||||||
},
|
},
|
||||||
.PairIdRefIdRef => {
|
.pair_id_ref_id_ref => {
|
||||||
try offsets.append(@intCast(offset));
|
try offsets.append(@intCast(offset));
|
||||||
try offsets.append(@intCast(offset + 1));
|
try offsets.append(@intCast(offset + 1));
|
||||||
offset += 2;
|
offset += 2;
|
||||||
|
|||||||
@ -7,7 +7,7 @@ const BinaryModule = @import("BinaryModule.zig");
|
|||||||
const Section = @import("../../codegen/spirv/Section.zig");
|
const Section = @import("../../codegen/spirv/Section.zig");
|
||||||
const spec = @import("../../codegen/spirv/spec.zig");
|
const spec = @import("../../codegen/spirv/spec.zig");
|
||||||
const Opcode = spec.Opcode;
|
const Opcode = spec.Opcode;
|
||||||
const ResultId = spec.IdResult;
|
const ResultId = spec.Id;
|
||||||
const Word = spec.Word;
|
const Word = spec.Word;
|
||||||
|
|
||||||
fn canDeduplicate(opcode: Opcode) bool {
|
fn canDeduplicate(opcode: Opcode) bool {
|
||||||
@ -20,9 +20,9 @@ fn canDeduplicate(opcode: Opcode) bool {
|
|||||||
// Debug decoration-style instructions
|
// Debug decoration-style instructions
|
||||||
.OpName, .OpMemberName => true,
|
.OpName, .OpMemberName => true,
|
||||||
else => switch (opcode.class()) {
|
else => switch (opcode.class()) {
|
||||||
.TypeDeclaration,
|
.type_declaration,
|
||||||
.ConstantCreation,
|
.constant_creation,
|
||||||
.Annotation,
|
.annotation,
|
||||||
=> true,
|
=> true,
|
||||||
else => false,
|
else => false,
|
||||||
},
|
},
|
||||||
@ -86,8 +86,8 @@ const ModuleInfo = struct {
|
|||||||
if (!canDeduplicate(inst.opcode)) continue;
|
if (!canDeduplicate(inst.opcode)) continue;
|
||||||
|
|
||||||
const result_id_index: u16 = switch (inst.opcode.class()) {
|
const result_id_index: u16 = switch (inst.opcode.class()) {
|
||||||
.TypeDeclaration, .Annotation, .Debug => 0,
|
.type_declaration, .annotation, .debug => 0,
|
||||||
.ConstantCreation => 1,
|
.constant_creation => 1,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -101,13 +101,13 @@ const ModuleInfo = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
switch (inst.opcode.class()) {
|
switch (inst.opcode.class()) {
|
||||||
.Annotation, .Debug => {
|
.annotation, .debug => {
|
||||||
try decorations.append(arena, .{
|
try decorations.append(arena, .{
|
||||||
.target_id = result_id,
|
.target_id = result_id,
|
||||||
.entity = entity,
|
.entity = entity,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.TypeDeclaration, .ConstantCreation => {
|
.type_declaration, .constant_creation => {
|
||||||
const entry = try entities.getOrPut(result_id);
|
const entry = try entities.getOrPut(result_id);
|
||||||
if (entry.found_existing) {
|
if (entry.found_existing) {
|
||||||
log.err("type or constant {f} has duplicate definition", .{result_id});
|
log.err("type or constant {f} has duplicate definition", .{result_id});
|
||||||
@ -469,7 +469,7 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: std.Pr
|
|||||||
const inst_spec = parser.getInstSpec(inst.opcode).?;
|
const inst_spec = parser.getInstSpec(inst.opcode).?;
|
||||||
|
|
||||||
const maybe_result_id_offset: ?u16 = for (0..2) |i| {
|
const maybe_result_id_offset: ?u16 = for (0..2) |i| {
|
||||||
if (inst_spec.operands.len > i and inst_spec.operands[i].kind == .IdResult) {
|
if (inst_spec.operands.len > i and inst_spec.operands[i].kind == .id_result) {
|
||||||
break @intCast(i);
|
break @intCast(i);
|
||||||
}
|
}
|
||||||
} else null;
|
} else null;
|
||||||
@ -488,7 +488,7 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: std.Pr
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (inst.opcode.class()) {
|
switch (inst.opcode.class()) {
|
||||||
.Annotation, .Debug => {
|
.annotation, .debug => {
|
||||||
// For decoration-style instructions, only emit them
|
// For decoration-style instructions, only emit them
|
||||||
// if the target is not removed.
|
// if the target is not removed.
|
||||||
const target: ResultId = @enumFromInt(inst.operands[0]);
|
const target: ResultId = @enumFromInt(inst.operands[0]);
|
||||||
@ -515,7 +515,7 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: std.Pr
|
|||||||
// Debug and Annotation instructions don't need the forward pointer, and it
|
// Debug and Annotation instructions don't need the forward pointer, and it
|
||||||
// messes up the logical layout of the module.
|
// messes up the logical layout of the module.
|
||||||
switch (inst.opcode.class()) {
|
switch (inst.opcode.class()) {
|
||||||
.TypeDeclaration, .ConstantCreation, .Memory => {},
|
.type_declaration, .constant_creation, .memory => {},
|
||||||
else => continue,
|
else => continue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ const log = std.log.scoped(.spirv_link);
|
|||||||
const BinaryModule = @import("BinaryModule.zig");
|
const BinaryModule = @import("BinaryModule.zig");
|
||||||
const Section = @import("../../codegen/spirv/Section.zig");
|
const Section = @import("../../codegen/spirv/Section.zig");
|
||||||
const spec = @import("../../codegen/spirv/spec.zig");
|
const spec = @import("../../codegen/spirv/spec.zig");
|
||||||
const ResultId = spec.IdResult;
|
const ResultId = spec.Id;
|
||||||
const Word = spec.Word;
|
const Word = spec.Word;
|
||||||
|
|
||||||
/// This structure contains all the stuff that we need to parse from the module in
|
/// This structure contains all the stuff that we need to parse from the module in
|
||||||
@ -626,7 +626,7 @@ const ModuleBuilder = struct {
|
|||||||
try self.section.emit(self.arena, .OpVariable, .{
|
try self.section.emit(self.arena, .OpVariable, .{
|
||||||
.id_result_type = global_info.ty,
|
.id_result_type = global_info.ty,
|
||||||
.id_result = id,
|
.id_result = id,
|
||||||
.storage_class = .Function,
|
.storage_class = .function,
|
||||||
.initializer = null,
|
.initializer = null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,14 +15,14 @@ const BinaryModule = @import("BinaryModule.zig");
|
|||||||
const Section = @import("../../codegen/spirv/Section.zig");
|
const Section = @import("../../codegen/spirv/Section.zig");
|
||||||
const spec = @import("../../codegen/spirv/spec.zig");
|
const spec = @import("../../codegen/spirv/spec.zig");
|
||||||
const Opcode = spec.Opcode;
|
const Opcode = spec.Opcode;
|
||||||
const ResultId = spec.IdResult;
|
const ResultId = spec.Id;
|
||||||
const Word = spec.Word;
|
const Word = spec.Word;
|
||||||
|
|
||||||
/// Return whether a particular opcode's instruction can be pruned.
|
/// Return whether a particular opcode's instruction can be pruned.
|
||||||
/// These are idempotent instructions at globals scope and instructions
|
/// These are idempotent instructions at globals scope and instructions
|
||||||
/// within functions that do not have any side effects.
|
/// within functions that do not have any side effects.
|
||||||
/// The opcodes that return true here do not necessarily need to
|
/// The opcodes that return true here do not necessarily need to
|
||||||
/// have an .IdResult. If they don't, then they are regarded
|
/// have an .Id. If they don't, then they are regarded
|
||||||
/// as 'decoration'-style instructions that don't keep their
|
/// as 'decoration'-style instructions that don't keep their
|
||||||
/// operands alive, but will be emitted if they are.
|
/// operands alive, but will be emitted if they are.
|
||||||
fn canPrune(op: Opcode) bool {
|
fn canPrune(op: Opcode) bool {
|
||||||
@ -34,12 +34,12 @@ fn canPrune(op: Opcode) bool {
|
|||||||
// instruction has any non-trivial side effects (like OpLoad
|
// instruction has any non-trivial side effects (like OpLoad
|
||||||
// with the Volatile memory semantics).
|
// with the Volatile memory semantics).
|
||||||
return switch (op.class()) {
|
return switch (op.class()) {
|
||||||
.TypeDeclaration,
|
.type_declaration,
|
||||||
.Conversion,
|
.conversion,
|
||||||
.Arithmetic,
|
.arithmetic,
|
||||||
.RelationalAndLogical,
|
.relational_and_logical,
|
||||||
.Bit,
|
.bit,
|
||||||
.Annotation,
|
.annotation,
|
||||||
=> true,
|
=> true,
|
||||||
else => switch (op) {
|
else => switch (op) {
|
||||||
.OpFunction,
|
.OpFunction,
|
||||||
@ -111,7 +111,7 @@ const ModuleInfo = struct {
|
|||||||
|
|
||||||
// Result-id can only be the first or second operand
|
// Result-id can only be the first or second operand
|
||||||
const maybe_result_id: ?ResultId = for (0..2) |i| {
|
const maybe_result_id: ?ResultId = for (0..2) |i| {
|
||||||
if (inst_spec.operands.len > i and inst_spec.operands[i].kind == .IdResult) {
|
if (inst_spec.operands.len > i and inst_spec.operands[i].kind == .id_result) {
|
||||||
break @enumFromInt(inst.operands[i]);
|
break @enumFromInt(inst.operands[i]);
|
||||||
}
|
}
|
||||||
} else null;
|
} else null;
|
||||||
@ -305,7 +305,7 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: std.Pr
|
|||||||
|
|
||||||
// Result-id can only be the first or second operand
|
// Result-id can only be the first or second operand
|
||||||
const result_id: ResultId = for (0..2) |i| {
|
const result_id: ResultId = for (0..2) |i| {
|
||||||
if (inst_spec.operands.len > i and inst_spec.operands[i].kind == .IdResult) {
|
if (inst_spec.operands.len > i and inst_spec.operands[i].kind == .id_result) {
|
||||||
break @enumFromInt(inst.operands[i]);
|
break @enumFromInt(inst.operands[i]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -59,26 +59,28 @@ const set_names = std.StaticStringMap([]const u8).initComptime(.{
|
|||||||
.{ "nonsemantic.debugprintf", "NonSemantic.DebugPrintf" },
|
.{ "nonsemantic.debugprintf", "NonSemantic.DebugPrintf" },
|
||||||
.{ "spv-amd-shader-explicit-vertex-parameter", "SPV_AMD_shader_explicit_vertex_parameter" },
|
.{ "spv-amd-shader-explicit-vertex-parameter", "SPV_AMD_shader_explicit_vertex_parameter" },
|
||||||
.{ "nonsemantic.debugbreak", "NonSemantic.DebugBreak" },
|
.{ "nonsemantic.debugbreak", "NonSemantic.DebugBreak" },
|
||||||
|
.{ "tosa.001000.1", "SPV_EXT_INST_TYPE_TOSA_001000_1" },
|
||||||
.{ "zig", "zig" },
|
.{ "zig", "zig" },
|
||||||
});
|
});
|
||||||
|
|
||||||
pub fn main() !void {
|
var arena = std.heap.ArenaAllocator.init(std.heap.smp_allocator);
|
||||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
const allocator = arena.allocator();
|
||||||
defer arena.deinit();
|
|
||||||
const a = arena.allocator();
|
|
||||||
|
|
||||||
const args = try std.process.argsAlloc(a);
|
pub fn main() !void {
|
||||||
|
defer arena.deinit();
|
||||||
|
|
||||||
|
const args = try std.process.argsAlloc(allocator);
|
||||||
if (args.len != 3) {
|
if (args.len != 3) {
|
||||||
usageAndExit(args[0], 1);
|
usageAndExit(args[0], 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const json_path = try std.fs.path.join(a, &.{ args[1], "include/spirv/unified1/" });
|
const json_path = try std.fs.path.join(allocator, &.{ args[1], "include/spirv/unified1/" });
|
||||||
const dir = try std.fs.cwd().openDir(json_path, .{ .iterate = true });
|
const dir = try std.fs.cwd().openDir(json_path, .{ .iterate = true });
|
||||||
|
|
||||||
const core_spec = try readRegistry(CoreRegistry, a, dir, "spirv.core.grammar.json");
|
const core_spec = try readRegistry(CoreRegistry, dir, "spirv.core.grammar.json");
|
||||||
std.sort.block(Instruction, core_spec.instructions, CmpInst{}, CmpInst.lt);
|
std.sort.block(Instruction, core_spec.instructions, CmpInst{}, CmpInst.lt);
|
||||||
|
|
||||||
var exts = std.ArrayList(Extension).init(a);
|
var exts = std.ArrayList(Extension).init(allocator);
|
||||||
|
|
||||||
var it = dir.iterate();
|
var it = dir.iterate();
|
||||||
while (try it.next()) |entry| {
|
while (try it.next()) |entry| {
|
||||||
@ -86,18 +88,43 @@ pub fn main() !void {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try readExtRegistry(&exts, a, dir, entry.name);
|
try readExtRegistry(&exts, dir, entry.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
try readExtRegistry(&exts, a, std.fs.cwd(), args[2]);
|
try readExtRegistry(&exts, std.fs.cwd(), args[2]);
|
||||||
|
|
||||||
var buffer: [4000]u8 = undefined;
|
const output_buf = try allocator.alloc(u8, 1024 * 1024);
|
||||||
var w = std.fs.File.stdout().writerStreaming(&buffer);
|
var fbs = std.io.fixedBufferStream(output_buf);
|
||||||
try render(&w, a, core_spec, exts.items);
|
var adapter = fbs.writer().adaptToNewApi();
|
||||||
try w.flush();
|
const w = &adapter.new_interface;
|
||||||
|
try render(w, core_spec, exts.items);
|
||||||
|
var output: [:0]u8 = @ptrCast(fbs.getWritten());
|
||||||
|
output[output.len] = 0;
|
||||||
|
|
||||||
|
var tree = try std.zig.Ast.parse(allocator, output, .zig);
|
||||||
|
var color: std.zig.Color = .on;
|
||||||
|
|
||||||
|
if (tree.errors.len != 0) {
|
||||||
|
try std.zig.printAstErrorsToStderr(allocator, tree, "", color);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var zir = try std.zig.AstGen.generate(allocator, tree);
|
||||||
|
if (zir.hasCompileErrors()) {
|
||||||
|
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||||
|
try wip_errors.init(allocator);
|
||||||
|
defer wip_errors.deinit();
|
||||||
|
try wip_errors.addZirErrorMessages(zir, tree, output, "");
|
||||||
|
var error_bundle = try wip_errors.toOwnedBundle("");
|
||||||
|
defer error_bundle.deinit(allocator);
|
||||||
|
error_bundle.renderToStdErr(color.renderOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatted_output = try tree.render(allocator);
|
||||||
|
_ = try std.fs.File.stdout().write(formatted_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readExtRegistry(exts: *std.ArrayList(Extension), a: Allocator, dir: std.fs.Dir, sub_path: []const u8) !void {
|
fn readExtRegistry(exts: *std.ArrayList(Extension), dir: std.fs.Dir, sub_path: []const u8) !void {
|
||||||
const filename = std.fs.path.basename(sub_path);
|
const filename = std.fs.path.basename(sub_path);
|
||||||
if (!std.mem.startsWith(u8, filename, "extinst.")) {
|
if (!std.mem.startsWith(u8, filename, "extinst.")) {
|
||||||
return;
|
return;
|
||||||
@ -105,22 +132,22 @@ fn readExtRegistry(exts: *std.ArrayList(Extension), a: Allocator, dir: std.fs.Di
|
|||||||
|
|
||||||
std.debug.assert(std.mem.endsWith(u8, filename, ".grammar.json"));
|
std.debug.assert(std.mem.endsWith(u8, filename, ".grammar.json"));
|
||||||
const name = filename["extinst.".len .. filename.len - ".grammar.json".len];
|
const name = filename["extinst.".len .. filename.len - ".grammar.json".len];
|
||||||
const spec = try readRegistry(ExtensionRegistry, a, dir, sub_path);
|
const spec = try readRegistry(ExtensionRegistry, dir, sub_path);
|
||||||
|
|
||||||
std.sort.block(Instruction, spec.instructions, CmpInst{}, CmpInst.lt);
|
std.sort.block(Instruction, spec.instructions, CmpInst{}, CmpInst.lt);
|
||||||
|
|
||||||
try exts.append(.{ .name = set_names.get(name).?, .spec = spec });
|
try exts.append(.{ .name = set_names.get(name).?, .spec = spec });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readRegistry(comptime RegistryType: type, a: Allocator, dir: std.fs.Dir, path: []const u8) !RegistryType {
|
fn readRegistry(comptime RegistryType: type, dir: std.fs.Dir, path: []const u8) !RegistryType {
|
||||||
const spec = try dir.readFileAlloc(a, path, std.math.maxInt(usize));
|
const spec = try dir.readFileAlloc(allocator, path, std.math.maxInt(usize));
|
||||||
// Required for json parsing.
|
// Required for json parsing.
|
||||||
@setEvalBranchQuota(10000);
|
@setEvalBranchQuota(10000);
|
||||||
|
|
||||||
var scanner = std.json.Scanner.initCompleteInput(a, spec);
|
var scanner = std.json.Scanner.initCompleteInput(allocator, spec);
|
||||||
var diagnostics = std.json.Diagnostics{};
|
var diagnostics = std.json.Diagnostics{};
|
||||||
scanner.enableDiagnostics(&diagnostics);
|
scanner.enableDiagnostics(&diagnostics);
|
||||||
const parsed = std.json.parseFromTokenSource(RegistryType, a, &scanner, .{}) catch |err| {
|
const parsed = std.json.parseFromTokenSource(RegistryType, allocator, &scanner, .{}) catch |err| {
|
||||||
std.debug.print("{s}:{}:{}:\n", .{ path, diagnostics.getLine(), diagnostics.getColumn() });
|
std.debug.print("{s}:{}:{}:\n", .{ path, diagnostics.getLine(), diagnostics.getColumn() });
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
@ -129,11 +156,8 @@ fn readRegistry(comptime RegistryType: type, a: Allocator, dir: std.fs.Dir, path
|
|||||||
|
|
||||||
/// Returns a set with types that require an extra struct for the `Instruction` interface
|
/// Returns a set with types that require an extra struct for the `Instruction` interface
|
||||||
/// to the spir-v spec, or whether the original type can be used.
|
/// to the spir-v spec, or whether the original type can be used.
|
||||||
fn extendedStructs(
|
fn extendedStructs(kinds: []const OperandKind) !ExtendedStructSet {
|
||||||
a: Allocator,
|
var map = ExtendedStructSet.init(allocator);
|
||||||
kinds: []const OperandKind,
|
|
||||||
) !ExtendedStructSet {
|
|
||||||
var map = ExtendedStructSet.init(a);
|
|
||||||
try map.ensureTotalCapacity(@as(u32, @intCast(kinds.len)));
|
try map.ensureTotalCapacity(@as(u32, @intCast(kinds.len)));
|
||||||
|
|
||||||
for (kinds) |kind| {
|
for (kinds) |kind| {
|
||||||
@ -167,7 +191,7 @@ fn tagPriorityScore(tag: []const u8) usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(writer: *std.io.Writer, a: Allocator, registry: CoreRegistry, extensions: []const Extension) !void {
|
fn render(writer: *std.io.Writer, registry: CoreRegistry, extensions: []const Extension) !void {
|
||||||
try writer.writeAll(
|
try writer.writeAll(
|
||||||
\\//! This file is auto-generated by tools/gen_spirv_spec.zig.
|
\\//! This file is auto-generated by tools/gen_spirv_spec.zig.
|
||||||
\\
|
\\
|
||||||
@ -185,22 +209,17 @@ fn render(writer: *std.io.Writer, a: Allocator, registry: CoreRegistry, extensio
|
|||||||
\\};
|
\\};
|
||||||
\\
|
\\
|
||||||
\\pub const Word = u32;
|
\\pub const Word = u32;
|
||||||
\\pub const IdResult = enum(Word) {
|
\\pub const Id = enum(Word) {
|
||||||
\\ none,
|
\\ none,
|
||||||
\\ _,
|
\\ _,
|
||||||
\\
|
\\
|
||||||
\\ pub fn format(self: IdResult, writer: *std.io.Writer) std.io.Writer.Error!void {
|
\\ pub fn format(self: Id, writer: *std.io.Writer) std.io.Writer.Error!void {
|
||||||
\\ switch (self) {
|
\\ switch (self) {
|
||||||
\\ .none => try writer.writeAll("(none)"),
|
\\ .none => try writer.writeAll("(none)"),
|
||||||
\\ else => try writer.print("%{d}", .{@intFromEnum(self)}),
|
\\ else => try writer.print("%{d}", .{@intFromEnum(self)}),
|
||||||
\\ }
|
\\ }
|
||||||
\\ }
|
\\ }
|
||||||
\\};
|
\\};
|
||||||
\\pub const IdResultType = IdResult;
|
|
||||||
\\pub const IdRef = IdResult;
|
|
||||||
\\
|
|
||||||
\\pub const IdMemorySemantics = IdRef;
|
|
||||||
\\pub const IdScope = IdRef;
|
|
||||||
\\
|
\\
|
||||||
\\pub const LiteralInteger = Word;
|
\\pub const LiteralInteger = Word;
|
||||||
\\pub const LiteralFloat = Word;
|
\\pub const LiteralFloat = Word;
|
||||||
@ -215,9 +234,9 @@ fn render(writer: *std.io.Writer, a: Allocator, registry: CoreRegistry, extensio
|
|||||||
\\};
|
\\};
|
||||||
\\pub const LiteralExtInstInteger = struct{ inst: Word };
|
\\pub const LiteralExtInstInteger = struct{ inst: Word };
|
||||||
\\pub const LiteralSpecConstantOpInteger = struct { opcode: Opcode };
|
\\pub const LiteralSpecConstantOpInteger = struct { opcode: Opcode };
|
||||||
\\pub const PairLiteralIntegerIdRef = struct { value: LiteralInteger, label: IdRef };
|
\\pub const PairLiteralIntegerIdRef = struct { value: LiteralInteger, label: Id };
|
||||||
\\pub const PairIdRefLiteralInteger = struct { target: IdRef, member: LiteralInteger };
|
\\pub const PairIdRefLiteralInteger = struct { target: Id, member: LiteralInteger };
|
||||||
\\pub const PairIdRefIdRef = [2]IdRef;
|
\\pub const PairIdRefIdRef = [2]Id;
|
||||||
\\
|
\\
|
||||||
\\pub const Quantifier = enum {
|
\\pub const Quantifier = enum {
|
||||||
\\ required,
|
\\ required,
|
||||||
@ -255,7 +274,7 @@ fn render(writer: *std.io.Writer, a: Allocator, registry: CoreRegistry, extensio
|
|||||||
);
|
);
|
||||||
|
|
||||||
try writer.print(
|
try writer.print(
|
||||||
\\pub const version = Version{{ .major = {}, .minor = {}, .patch = {} }};
|
\\pub const version: Version = .{{ .major = {}, .minor = {}, .patch = {} }};
|
||||||
\\pub const magic_number: Word = {s};
|
\\pub const magic_number: Word = {s};
|
||||||
\\
|
\\
|
||||||
\\
|
\\
|
||||||
@ -266,7 +285,7 @@ fn render(writer: *std.io.Writer, a: Allocator, registry: CoreRegistry, extensio
|
|||||||
// Merge the operand kinds from all extensions together.
|
// Merge the operand kinds from all extensions together.
|
||||||
// var all_operand_kinds = std.ArrayList(OperandKind).init(a);
|
// var all_operand_kinds = std.ArrayList(OperandKind).init(a);
|
||||||
// try all_operand_kinds.appendSlice(registry.operand_kinds);
|
// try all_operand_kinds.appendSlice(registry.operand_kinds);
|
||||||
var all_operand_kinds = OperandKindMap.init(a);
|
var all_operand_kinds = OperandKindMap.init(allocator);
|
||||||
for (registry.operand_kinds) |kind| {
|
for (registry.operand_kinds) |kind| {
|
||||||
try all_operand_kinds.putNoClobber(.{ "core", kind.kind }, kind);
|
try all_operand_kinds.putNoClobber(.{ "core", kind.kind }, kind);
|
||||||
}
|
}
|
||||||
@ -279,35 +298,33 @@ fn render(writer: *std.io.Writer, a: Allocator, registry: CoreRegistry, extensio
|
|||||||
try all_operand_kinds.ensureUnusedCapacity(ext.spec.operand_kinds.len);
|
try all_operand_kinds.ensureUnusedCapacity(ext.spec.operand_kinds.len);
|
||||||
for (ext.spec.operand_kinds) |kind| {
|
for (ext.spec.operand_kinds) |kind| {
|
||||||
var new_kind = kind;
|
var new_kind = kind;
|
||||||
new_kind.kind = try std.mem.join(a, ".", &.{ ext.name, kind.kind });
|
new_kind.kind = try std.mem.join(allocator, ".", &.{ ext.name, kind.kind });
|
||||||
try all_operand_kinds.putNoClobber(.{ ext.name, kind.kind }, new_kind);
|
try all_operand_kinds.putNoClobber(.{ ext.name, kind.kind }, new_kind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const extended_structs = try extendedStructs(a, all_operand_kinds.values());
|
const extended_structs = try extendedStructs(all_operand_kinds.values());
|
||||||
// Note: extensions don't seem to have class.
|
// Note: extensions don't seem to have class.
|
||||||
try renderClass(writer, a, registry.instructions);
|
try renderClass(writer, registry.instructions);
|
||||||
try renderOperandKind(writer, all_operand_kinds.values());
|
try renderOperandKind(writer, all_operand_kinds.values());
|
||||||
try renderOpcodes(writer, a, registry.instructions, extended_structs);
|
try renderOpcodes(writer, registry.instructions, extended_structs);
|
||||||
try renderOperandKinds(writer, a, all_operand_kinds.values(), extended_structs);
|
try renderOperandKinds(writer, all_operand_kinds.values(), extended_structs);
|
||||||
try renderInstructionSet(writer, a, registry, extensions, all_operand_kinds);
|
try renderInstructionSet(writer, registry, extensions, all_operand_kinds);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderInstructionSet(
|
fn renderInstructionSet(
|
||||||
writer: anytype,
|
writer: anytype,
|
||||||
a: Allocator,
|
|
||||||
core: CoreRegistry,
|
core: CoreRegistry,
|
||||||
extensions: []const Extension,
|
extensions: []const Extension,
|
||||||
all_operand_kinds: OperandKindMap,
|
all_operand_kinds: OperandKindMap,
|
||||||
) !void {
|
) !void {
|
||||||
_ = a;
|
|
||||||
try writer.writeAll(
|
try writer.writeAll(
|
||||||
\\pub const InstructionSet = enum {
|
\\pub const InstructionSet = enum {
|
||||||
\\ core,
|
\\ core,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (extensions) |ext| {
|
for (extensions) |ext| {
|
||||||
try writer.print("{p},\n", .{std.zig.fmtId(ext.name)});
|
try writer.print("{f},\n", .{formatId(ext.name)});
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll(
|
try writer.writeAll(
|
||||||
@ -340,14 +357,14 @@ fn renderInstructionsCase(
|
|||||||
// but there aren't so many total aliases and that would add more overhead in total. We will
|
// but there aren't so many total aliases and that would add more overhead in total. We will
|
||||||
// just filter those out when needed.
|
// just filter those out when needed.
|
||||||
|
|
||||||
try writer.print(".{p_} => &[_]Instruction{{\n", .{std.zig.fmtId(set_name)});
|
try writer.print(".{f} => &.{{\n", .{formatId(set_name)});
|
||||||
|
|
||||||
for (instructions) |inst| {
|
for (instructions) |inst| {
|
||||||
try writer.print(
|
try writer.print(
|
||||||
\\.{{
|
\\.{{
|
||||||
\\ .name = "{s}",
|
\\ .name = "{s}",
|
||||||
\\ .opcode = {},
|
\\ .opcode = {},
|
||||||
\\ .operands = &[_]Operand{{
|
\\ .operands = &.{{
|
||||||
\\
|
\\
|
||||||
, .{ inst.opname, inst.opcode });
|
, .{ inst.opname, inst.opcode });
|
||||||
|
|
||||||
@ -362,7 +379,7 @@ fn renderInstructionsCase(
|
|||||||
|
|
||||||
const kind = all_operand_kinds.get(.{ set_name, operand.kind }) orelse
|
const kind = all_operand_kinds.get(.{ set_name, operand.kind }) orelse
|
||||||
all_operand_kinds.get(.{ "core", operand.kind }).?;
|
all_operand_kinds.get(.{ "core", operand.kind }).?;
|
||||||
try writer.print(".{{.kind = .{p_}, .quantifier = .{s}}},\n", .{ std.zig.fmtId(kind.kind), quantifier });
|
try writer.print(".{{.kind = .{f}, .quantifier = .{s}}},\n", .{ formatId(kind.kind), quantifier });
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll(
|
try writer.writeAll(
|
||||||
@ -378,54 +395,69 @@ fn renderInstructionsCase(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderClass(writer: anytype, a: Allocator, instructions: []const Instruction) !void {
|
fn renderClass(writer: anytype, instructions: []const Instruction) !void {
|
||||||
var class_map = std.StringArrayHashMap(void).init(a);
|
var class_map = std.StringArrayHashMap(void).init(allocator);
|
||||||
|
|
||||||
for (instructions) |inst| {
|
for (instructions) |inst| {
|
||||||
if (std.mem.eql(u8, inst.class.?, "@exclude")) {
|
if (std.mem.eql(u8, inst.class.?, "@exclude")) continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try class_map.put(inst.class.?, {});
|
try class_map.put(inst.class.?, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll("pub const Class = enum {\n");
|
try writer.writeAll("pub const Class = enum {\n");
|
||||||
for (class_map.keys()) |class| {
|
for (class_map.keys()) |class| {
|
||||||
try renderInstructionClass(writer, class);
|
try writer.print("{f},\n", .{formatId(class)});
|
||||||
try writer.writeAll(",\n");
|
|
||||||
}
|
}
|
||||||
try writer.writeAll("};\n\n");
|
try writer.writeAll("};\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderInstructionClass(writer: anytype, class: []const u8) !void {
|
const Formatter = struct {
|
||||||
// Just assume that these wont clobber zig builtin types.
|
data: []const u8,
|
||||||
var prev_was_sep = true;
|
|
||||||
for (class) |c| {
|
fn format(f: Formatter, writer: *std.io.Writer) std.io.Writer.Error!void {
|
||||||
switch (c) {
|
var id_buf: [128]u8 = undefined;
|
||||||
'-', '_' => prev_was_sep = true,
|
var fbs = std.io.fixedBufferStream(&id_buf);
|
||||||
else => if (prev_was_sep) {
|
const fw = fbs.writer();
|
||||||
try writer.writeByte(std.ascii.toUpper(c));
|
for (f.data, 0..) |c, i| {
|
||||||
prev_was_sep = false;
|
switch (c) {
|
||||||
} else {
|
'-', '_', '.', '~', ' ' => fw.writeByte('_') catch return error.WriteFailed,
|
||||||
try writer.writeByte(std.ascii.toLower(c));
|
'a'...'z', '0'...'9' => fw.writeByte(c) catch return error.WriteFailed,
|
||||||
},
|
'A'...'Z' => {
|
||||||
|
if ((i > 0 and std.ascii.isLower(f.data[i - 1])) or
|
||||||
|
(i > 0 and std.ascii.isUpper(f.data[i - 1]) and
|
||||||
|
i + 1 < f.data.len and std.ascii.isLower(f.data[i + 1])))
|
||||||
|
{
|
||||||
|
_ = fw.write(&.{ '_', std.ascii.toLower(c) }) catch return error.WriteFailed;
|
||||||
|
} else {
|
||||||
|
fw.writeByte(std.ascii.toLower(c)) catch return error.WriteFailed;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure that this won't clobber with zig keywords
|
||||||
|
try writer.print("{f}", .{std.zig.fmtId(fbs.getWritten())});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn formatId(identifier: []const u8) std.fmt.Alt(Formatter, Formatter.format) {
|
||||||
|
return .{ .data = .{ .data = identifier } };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderOperandKind(writer: anytype, operands: []const OperandKind) !void {
|
fn renderOperandKind(writer: anytype, operands: []const OperandKind) !void {
|
||||||
try writer.writeAll(
|
try writer.writeAll(
|
||||||
\\pub const OperandKind = enum {
|
\\pub const OperandKind = enum {
|
||||||
\\ Opcode,
|
\\ opcode,
|
||||||
\\
|
\\
|
||||||
);
|
);
|
||||||
for (operands) |operand| {
|
for (operands) |operand| {
|
||||||
try writer.print("{p},\n", .{std.zig.fmtId(operand.kind)});
|
try writer.print("{f},\n", .{formatId(operand.kind)});
|
||||||
}
|
}
|
||||||
try writer.writeAll(
|
try writer.writeAll(
|
||||||
\\
|
\\
|
||||||
\\pub fn category(self: OperandKind) OperandCategory {
|
\\pub fn category(self: OperandKind) OperandCategory {
|
||||||
\\ return switch (self) {
|
\\ return switch (self) {
|
||||||
\\ .Opcode => .literal,
|
\\ .opcode => .literal,
|
||||||
\\
|
\\
|
||||||
);
|
);
|
||||||
for (operands) |operand| {
|
for (operands) |operand| {
|
||||||
@ -436,26 +468,26 @@ fn renderOperandKind(writer: anytype, operands: []const OperandKind) !void {
|
|||||||
.Literal => "literal",
|
.Literal => "literal",
|
||||||
.Composite => "composite",
|
.Composite => "composite",
|
||||||
};
|
};
|
||||||
try writer.print(".{p_} => .{s},\n", .{ std.zig.fmtId(operand.kind), cat });
|
try writer.print(".{f} => .{s},\n", .{ formatId(operand.kind), cat });
|
||||||
}
|
}
|
||||||
try writer.writeAll(
|
try writer.writeAll(
|
||||||
\\ };
|
\\ };
|
||||||
\\}
|
\\}
|
||||||
\\pub fn enumerants(self: OperandKind) []const Enumerant {
|
\\pub fn enumerants(self: OperandKind) []const Enumerant {
|
||||||
\\ return switch (self) {
|
\\ return switch (self) {
|
||||||
\\ .Opcode => unreachable,
|
\\ .opcode => unreachable,
|
||||||
\\
|
\\
|
||||||
);
|
);
|
||||||
for (operands) |operand| {
|
for (operands) |operand| {
|
||||||
switch (operand.category) {
|
switch (operand.category) {
|
||||||
.BitEnum, .ValueEnum => {},
|
.BitEnum, .ValueEnum => {},
|
||||||
else => {
|
else => {
|
||||||
try writer.print(".{p_} => unreachable,\n", .{std.zig.fmtId(operand.kind)});
|
try writer.print(".{f} => unreachable,\n", .{formatId(operand.kind)});
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.print(".{p_} => &[_]Enumerant{{", .{std.zig.fmtId(operand.kind)});
|
try writer.print(".{f} => &.{{", .{formatId(operand.kind)});
|
||||||
for (operand.enumerants.?) |enumerant| {
|
for (operand.enumerants.?) |enumerant| {
|
||||||
if (enumerant.value == .bitflag and std.mem.eql(u8, enumerant.enumerant, "None")) {
|
if (enumerant.value == .bitflag and std.mem.eql(u8, enumerant.enumerant, "None")) {
|
||||||
continue;
|
continue;
|
||||||
@ -474,32 +506,30 @@ fn renderEnumerant(writer: anytype, enumerant: Enumerant) !void {
|
|||||||
.bitflag => |flag| try writer.writeAll(flag),
|
.bitflag => |flag| try writer.writeAll(flag),
|
||||||
.int => |int| try writer.print("{}", .{int}),
|
.int => |int| try writer.print("{}", .{int}),
|
||||||
}
|
}
|
||||||
try writer.writeAll(", .parameters = &[_]OperandKind{");
|
try writer.writeAll(", .parameters = &.{");
|
||||||
for (enumerant.parameters, 0..) |param, i| {
|
for (enumerant.parameters, 0..) |param, i| {
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
try writer.writeAll(", ");
|
try writer.writeAll(", ");
|
||||||
// Note, param.quantifier will always be one.
|
// Note, param.quantifier will always be one.
|
||||||
try writer.print(".{p_}", .{std.zig.fmtId(param.kind)});
|
try writer.print(".{f}", .{formatId(param.kind)});
|
||||||
}
|
}
|
||||||
try writer.writeAll("}}");
|
try writer.writeAll("}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderOpcodes(
|
fn renderOpcodes(
|
||||||
writer: anytype,
|
writer: anytype,
|
||||||
a: Allocator,
|
|
||||||
instructions: []const Instruction,
|
instructions: []const Instruction,
|
||||||
extended_structs: ExtendedStructSet,
|
extended_structs: ExtendedStructSet,
|
||||||
) !void {
|
) !void {
|
||||||
var inst_map = std.AutoArrayHashMap(u32, usize).init(a);
|
var inst_map = std.AutoArrayHashMap(u32, usize).init(allocator);
|
||||||
try inst_map.ensureTotalCapacity(instructions.len);
|
try inst_map.ensureTotalCapacity(instructions.len);
|
||||||
|
|
||||||
var aliases = std.ArrayList(struct { inst: usize, alias: usize }).init(a);
|
var aliases = std.ArrayList(struct { inst: usize, alias: usize }).init(allocator);
|
||||||
try aliases.ensureTotalCapacity(instructions.len);
|
try aliases.ensureTotalCapacity(instructions.len);
|
||||||
|
|
||||||
for (instructions, 0..) |inst, i| {
|
for (instructions, 0..) |inst, i| {
|
||||||
if (std.mem.eql(u8, inst.class.?, "@exclude")) {
|
if (std.mem.eql(u8, inst.class.?, "@exclude")) continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const result = inst_map.getOrPutAssumeCapacity(inst.opcode);
|
const result = inst_map.getOrPutAssumeCapacity(inst.opcode);
|
||||||
if (!result.found_existing) {
|
if (!result.found_existing) {
|
||||||
result.value_ptr.* = i;
|
result.value_ptr.* = i;
|
||||||
@ -525,7 +555,7 @@ fn renderOpcodes(
|
|||||||
try writer.writeAll("pub const Opcode = enum(u16) {\n");
|
try writer.writeAll("pub const Opcode = enum(u16) {\n");
|
||||||
for (instructions_indices) |i| {
|
for (instructions_indices) |i| {
|
||||||
const inst = instructions[i];
|
const inst = instructions[i];
|
||||||
try writer.print("{p} = {},\n", .{ std.zig.fmtId(inst.opname), inst.opcode });
|
try writer.print("{f} = {},\n", .{ std.zig.fmtId(inst.opname), inst.opcode });
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll(
|
try writer.writeAll(
|
||||||
@ -533,9 +563,9 @@ fn renderOpcodes(
|
|||||||
);
|
);
|
||||||
|
|
||||||
for (aliases.items) |alias| {
|
for (aliases.items) |alias| {
|
||||||
try writer.print("pub const {} = Opcode.{p_};\n", .{
|
try writer.print("pub const {f} = Opcode.{f};\n", .{
|
||||||
std.zig.fmtId(instructions[alias.inst].opname),
|
formatId(instructions[alias.inst].opname),
|
||||||
std.zig.fmtId(instructions[alias.alias].opname),
|
formatId(instructions[alias.alias].opname),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,7 +578,7 @@ fn renderOpcodes(
|
|||||||
|
|
||||||
for (instructions_indices) |i| {
|
for (instructions_indices) |i| {
|
||||||
const inst = instructions[i];
|
const inst = instructions[i];
|
||||||
try renderOperand(writer, .instruction, inst.opname, inst.operands, extended_structs);
|
try renderOperand(writer, .instruction, inst.opname, inst.operands, extended_structs, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll(
|
try writer.writeAll(
|
||||||
@ -561,9 +591,7 @@ fn renderOpcodes(
|
|||||||
|
|
||||||
for (instructions_indices) |i| {
|
for (instructions_indices) |i| {
|
||||||
const inst = instructions[i];
|
const inst = instructions[i];
|
||||||
try writer.print(".{p_} => .", .{std.zig.fmtId(inst.opname)});
|
try writer.print(".{f} => .{f},\n", .{ std.zig.fmtId(inst.opname), formatId(inst.class.?) });
|
||||||
try renderInstructionClass(writer, inst.class.?);
|
|
||||||
try writer.writeAll(",\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll(
|
try writer.writeAll(
|
||||||
@ -576,14 +604,13 @@ fn renderOpcodes(
|
|||||||
|
|
||||||
fn renderOperandKinds(
|
fn renderOperandKinds(
|
||||||
writer: anytype,
|
writer: anytype,
|
||||||
a: Allocator,
|
|
||||||
kinds: []const OperandKind,
|
kinds: []const OperandKind,
|
||||||
extended_structs: ExtendedStructSet,
|
extended_structs: ExtendedStructSet,
|
||||||
) !void {
|
) !void {
|
||||||
for (kinds) |kind| {
|
for (kinds) |kind| {
|
||||||
switch (kind.category) {
|
switch (kind.category) {
|
||||||
.ValueEnum => try renderValueEnum(writer, a, kind, extended_structs),
|
.ValueEnum => try renderValueEnum(writer, kind, extended_structs),
|
||||||
.BitEnum => try renderBitEnum(writer, a, kind, extended_structs),
|
.BitEnum => try renderBitEnum(writer, kind, extended_structs),
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -591,20 +618,18 @@ fn renderOperandKinds(
|
|||||||
|
|
||||||
fn renderValueEnum(
|
fn renderValueEnum(
|
||||||
writer: anytype,
|
writer: anytype,
|
||||||
a: Allocator,
|
|
||||||
enumeration: OperandKind,
|
enumeration: OperandKind,
|
||||||
extended_structs: ExtendedStructSet,
|
extended_structs: ExtendedStructSet,
|
||||||
) !void {
|
) !void {
|
||||||
const enumerants = enumeration.enumerants orelse return error.InvalidRegistry;
|
const enumerants = enumeration.enumerants orelse return error.InvalidRegistry;
|
||||||
|
|
||||||
var enum_map = std.AutoArrayHashMap(u32, usize).init(a);
|
var enum_map = std.AutoArrayHashMap(u32, usize).init(allocator);
|
||||||
try enum_map.ensureTotalCapacity(enumerants.len);
|
try enum_map.ensureTotalCapacity(enumerants.len);
|
||||||
|
|
||||||
var aliases = std.ArrayList(struct { enumerant: usize, alias: usize }).init(a);
|
var aliases = std.ArrayList(struct { enumerant: usize, alias: usize }).init(allocator);
|
||||||
try aliases.ensureTotalCapacity(enumerants.len);
|
try aliases.ensureTotalCapacity(enumerants.len);
|
||||||
|
|
||||||
for (enumerants, 0..) |enumerant, i| {
|
for (enumerants, 0..) |enumerant, i| {
|
||||||
try writer.context.flush();
|
|
||||||
const value: u31 = switch (enumerant.value) {
|
const value: u31 = switch (enumerant.value) {
|
||||||
.int => |value| value,
|
.int => |value| value,
|
||||||
// Some extensions declare ints as string
|
// Some extensions declare ints as string
|
||||||
@ -632,25 +657,25 @@ fn renderValueEnum(
|
|||||||
|
|
||||||
const enum_indices = enum_map.values();
|
const enum_indices = enum_map.values();
|
||||||
|
|
||||||
try writer.print("pub const {} = enum(u32) {{\n", .{std.zig.fmtId(enumeration.kind)});
|
try writer.print("pub const {f} = enum(u32) {{\n", .{std.zig.fmtId(enumeration.kind)});
|
||||||
|
|
||||||
for (enum_indices) |i| {
|
for (enum_indices) |i| {
|
||||||
const enumerant = enumerants[i];
|
const enumerant = enumerants[i];
|
||||||
// if (enumerant.value != .int) return error.InvalidRegistry;
|
// if (enumerant.value != .int) return error.InvalidRegistry;
|
||||||
|
|
||||||
switch (enumerant.value) {
|
switch (enumerant.value) {
|
||||||
.int => |value| try writer.print("{p} = {},\n", .{ std.zig.fmtId(enumerant.enumerant), value }),
|
.int => |value| try writer.print("{f} = {},\n", .{ formatId(enumerant.enumerant), value }),
|
||||||
.bitflag => |value| try writer.print("{p} = {s},\n", .{ std.zig.fmtId(enumerant.enumerant), value }),
|
.bitflag => |value| try writer.print("{f} = {s},\n", .{ formatId(enumerant.enumerant), value }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeByte('\n');
|
try writer.writeByte('\n');
|
||||||
|
|
||||||
for (aliases.items) |alias| {
|
for (aliases.items) |alias| {
|
||||||
try writer.print("pub const {} = {}.{p_};\n", .{
|
try writer.print("pub const {f} = {f}.{f};\n", .{
|
||||||
std.zig.fmtId(enumerants[alias.enumerant].enumerant),
|
formatId(enumerants[alias.enumerant].enumerant),
|
||||||
std.zig.fmtId(enumeration.kind),
|
std.zig.fmtId(enumeration.kind),
|
||||||
std.zig.fmtId(enumerants[alias.alias].enumerant),
|
formatId(enumerants[alias.alias].enumerant),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,11 +684,11 @@ fn renderValueEnum(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.print("\npub const Extended = union({}) {{\n", .{std.zig.fmtId(enumeration.kind)});
|
try writer.print("\npub const Extended = union({f}) {{\n", .{std.zig.fmtId(enumeration.kind)});
|
||||||
|
|
||||||
for (enum_indices) |i| {
|
for (enum_indices) |i| {
|
||||||
const enumerant = enumerants[i];
|
const enumerant = enumerants[i];
|
||||||
try renderOperand(writer, .@"union", enumerant.enumerant, enumerant.parameters, extended_structs);
|
try renderOperand(writer, .@"union", enumerant.enumerant, enumerant.parameters, extended_structs, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll("};\n};\n");
|
try writer.writeAll("};\n};\n");
|
||||||
@ -671,16 +696,15 @@ fn renderValueEnum(
|
|||||||
|
|
||||||
fn renderBitEnum(
|
fn renderBitEnum(
|
||||||
writer: anytype,
|
writer: anytype,
|
||||||
a: Allocator,
|
|
||||||
enumeration: OperandKind,
|
enumeration: OperandKind,
|
||||||
extended_structs: ExtendedStructSet,
|
extended_structs: ExtendedStructSet,
|
||||||
) !void {
|
) !void {
|
||||||
try writer.print("pub const {} = packed struct {{\n", .{std.zig.fmtId(enumeration.kind)});
|
try writer.print("pub const {f} = packed struct {{\n", .{std.zig.fmtId(enumeration.kind)});
|
||||||
|
|
||||||
var flags_by_bitpos = [_]?usize{null} ** 32;
|
var flags_by_bitpos = [_]?usize{null} ** 32;
|
||||||
const enumerants = enumeration.enumerants orelse return error.InvalidRegistry;
|
const enumerants = enumeration.enumerants orelse return error.InvalidRegistry;
|
||||||
|
|
||||||
var aliases = std.ArrayList(struct { flag: usize, alias: u5 }).init(a);
|
var aliases = std.ArrayList(struct { flag: usize, alias: u5 }).init(allocator);
|
||||||
try aliases.ensureTotalCapacity(enumerants.len);
|
try aliases.ensureTotalCapacity(enumerants.len);
|
||||||
|
|
||||||
for (enumerants, 0..) |enumerant, i| {
|
for (enumerants, 0..) |enumerant, i| {
|
||||||
@ -715,7 +739,7 @@ fn renderBitEnum(
|
|||||||
|
|
||||||
for (flags_by_bitpos, 0..) |maybe_flag_index, bitpos| {
|
for (flags_by_bitpos, 0..) |maybe_flag_index, bitpos| {
|
||||||
if (maybe_flag_index) |flag_index| {
|
if (maybe_flag_index) |flag_index| {
|
||||||
try writer.print("{p_}", .{std.zig.fmtId(enumerants[flag_index].enumerant)});
|
try writer.print("{f}", .{formatId(enumerants[flag_index].enumerant)});
|
||||||
} else {
|
} else {
|
||||||
try writer.print("_reserved_bit_{}", .{bitpos});
|
try writer.print("_reserved_bit_{}", .{bitpos});
|
||||||
}
|
}
|
||||||
@ -726,10 +750,10 @@ fn renderBitEnum(
|
|||||||
try writer.writeByte('\n');
|
try writer.writeByte('\n');
|
||||||
|
|
||||||
for (aliases.items) |alias| {
|
for (aliases.items) |alias| {
|
||||||
try writer.print("pub const {}: {} = .{{.{p_} = true}};\n", .{
|
try writer.print("pub const {f}: {f} = .{{.{f} = true}};\n", .{
|
||||||
std.zig.fmtId(enumerants[alias.flag].enumerant),
|
formatId(enumerants[alias.flag].enumerant),
|
||||||
std.zig.fmtId(enumeration.kind),
|
std.zig.fmtId(enumeration.kind),
|
||||||
std.zig.fmtId(enumerants[flags_by_bitpos[alias.alias].?].enumerant),
|
formatId(enumerants[flags_by_bitpos[alias.alias].?].enumerant),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,7 +771,7 @@ fn renderBitEnum(
|
|||||||
};
|
};
|
||||||
const enumerant = enumerants[flag_index];
|
const enumerant = enumerants[flag_index];
|
||||||
|
|
||||||
try renderOperand(writer, .mask, enumerant.enumerant, enumerant.parameters, extended_structs);
|
try renderOperand(writer, .mask, enumerant.enumerant, enumerant.parameters, extended_structs, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll("};\n};\n");
|
try writer.writeAll("};\n};\n");
|
||||||
@ -763,11 +787,18 @@ fn renderOperand(
|
|||||||
field_name: []const u8,
|
field_name: []const u8,
|
||||||
parameters: []const Operand,
|
parameters: []const Operand,
|
||||||
extended_structs: ExtendedStructSet,
|
extended_structs: ExtendedStructSet,
|
||||||
|
snake_case: bool,
|
||||||
) !void {
|
) !void {
|
||||||
if (kind == .instruction) {
|
if (kind == .instruction) {
|
||||||
try writer.writeByte('.');
|
try writer.writeByte('.');
|
||||||
}
|
}
|
||||||
try writer.print("{}", .{std.zig.fmtId(field_name)});
|
|
||||||
|
if (snake_case) {
|
||||||
|
try writer.print("{f}", .{formatId(field_name)});
|
||||||
|
} else {
|
||||||
|
try writer.print("{f}", .{std.zig.fmtId(field_name)});
|
||||||
|
}
|
||||||
|
|
||||||
if (parameters.len == 0) {
|
if (parameters.len == 0) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
.@"union" => try writer.writeAll(",\n"),
|
.@"union" => try writer.writeAll(",\n"),
|
||||||
@ -787,7 +818,7 @@ fn renderOperand(
|
|||||||
try writer.writeByte('?');
|
try writer.writeByte('?');
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll("struct{");
|
try writer.writeAll("struct {");
|
||||||
|
|
||||||
for (parameters, 0..) |param, j| {
|
for (parameters, 0..) |param, j| {
|
||||||
if (j != 0) {
|
if (j != 0) {
|
||||||
@ -804,7 +835,11 @@ fn renderOperand(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.print("{}", .{std.zig.fmtId(param.kind)});
|
if (std.mem.startsWith(u8, param.kind, "Id")) {
|
||||||
|
_ = try writer.write("Id");
|
||||||
|
} else {
|
||||||
|
try writer.print("{f}", .{std.zig.fmtId(param.kind)});
|
||||||
|
}
|
||||||
|
|
||||||
if (extended_structs.contains(param.kind)) {
|
if (extended_structs.contains(param.kind)) {
|
||||||
try writer.writeAll(".Extended");
|
try writer.writeAll(".Extended");
|
||||||
@ -830,49 +865,24 @@ fn renderOperand(
|
|||||||
fn renderFieldName(writer: anytype, operands: []const Operand, field_index: usize) !void {
|
fn renderFieldName(writer: anytype, operands: []const Operand, field_index: usize) !void {
|
||||||
const operand = operands[field_index];
|
const operand = operands[field_index];
|
||||||
|
|
||||||
// Should be enough for all names - adjust as needed.
|
|
||||||
var name_backing_buffer: [64]u8 = undefined;
|
|
||||||
var name_buffer = std.ArrayListUnmanaged(u8).initBuffer(&name_backing_buffer);
|
|
||||||
|
|
||||||
derive_from_kind: {
|
derive_from_kind: {
|
||||||
// Operand names are often in the json encoded as "'Name'" (with two sets of quotes).
|
// Operand names are often in the json encoded as "'Name'" (with two sets of quotes).
|
||||||
// Additionally, some operands have ~ in them at the end (D~ref~).
|
// Additionally, some operands have ~ in them at the end (D~ref~).
|
||||||
const name = std.mem.trim(u8, operand.name, "'~");
|
const name = std.mem.trim(u8, operand.name, "'~");
|
||||||
if (name.len == 0) {
|
if (name.len == 0) break :derive_from_kind;
|
||||||
break :derive_from_kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some names have weird characters in them (like newlines) - skip any such ones.
|
|
||||||
// Use the same loop to transform to snake-case.
|
|
||||||
for (name) |c| {
|
for (name) |c| {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
'a'...'z', '0'...'9' => name_buffer.appendAssumeCapacity(c),
|
'a'...'z', '0'...'9', 'A'...'Z', ' ', '~' => continue,
|
||||||
'A'...'Z' => name_buffer.appendAssumeCapacity(std.ascii.toLower(c)),
|
|
||||||
' ', '~' => name_buffer.appendAssumeCapacity('_'),
|
|
||||||
else => break :derive_from_kind,
|
else => break :derive_from_kind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assume there are no duplicate 'name' fields.
|
try writer.print("{f}", .{formatId(name)});
|
||||||
try writer.print("{p_}", .{std.zig.fmtId(name_buffer.items)});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translate to snake case.
|
try writer.print("{f}", .{formatId(operand.kind)});
|
||||||
name_buffer.items.len = 0;
|
|
||||||
for (operand.kind, 0..) |c, i| {
|
|
||||||
switch (c) {
|
|
||||||
'a'...'z', '0'...'9' => name_buffer.appendAssumeCapacity(c),
|
|
||||||
'A'...'Z' => if (i > 0 and std.ascii.isLower(operand.kind[i - 1])) {
|
|
||||||
name_buffer.appendSliceAssumeCapacity(&[_]u8{ '_', std.ascii.toLower(c) });
|
|
||||||
} else {
|
|
||||||
name_buffer.appendAssumeCapacity(std.ascii.toLower(c));
|
|
||||||
},
|
|
||||||
else => unreachable, // Assume that the name is valid C-syntax (and contains no underscores).
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try writer.print("{p_}", .{std.zig.fmtId(name_buffer.items)});
|
|
||||||
|
|
||||||
// For fields derived from type name, there could be any amount.
|
// For fields derived from type name, there could be any amount.
|
||||||
// Simply check against all other fields, and if another similar one exists, add a number.
|
// Simply check against all other fields, and if another similar one exists, add a number.
|
||||||
|
|||||||
@ -37,9 +37,11 @@ pub const InstructionPrintingClass = struct {
|
|||||||
pub const Instruction = struct {
|
pub const Instruction = struct {
|
||||||
opname: []const u8,
|
opname: []const u8,
|
||||||
class: ?[]const u8 = null, // Note: Only available in the core registry.
|
class: ?[]const u8 = null, // Note: Only available in the core registry.
|
||||||
|
aliases: [][]const u8 = &[_][]const u8{},
|
||||||
opcode: u32,
|
opcode: u32,
|
||||||
operands: []Operand = &[_]Operand{},
|
operands: []Operand = &[_]Operand{},
|
||||||
capabilities: [][]const u8 = &[_][]const u8{},
|
capabilities: [][]const u8 = &[_][]const u8{},
|
||||||
|
provisional: bool = false,
|
||||||
// DebugModuleINTEL has this...
|
// DebugModuleINTEL has this...
|
||||||
capability: ?[]const u8 = null,
|
capability: ?[]const u8 = null,
|
||||||
extensions: [][]const u8 = &[_][]const u8{},
|
extensions: [][]const u8 = &[_][]const u8{},
|
||||||
@ -81,6 +83,7 @@ pub const OperandKind = struct {
|
|||||||
|
|
||||||
pub const Enumerant = struct {
|
pub const Enumerant = struct {
|
||||||
enumerant: []const u8,
|
enumerant: []const u8,
|
||||||
|
aliases: [][]const u8 = &[_][]const u8{},
|
||||||
value: union(enum) {
|
value: union(enum) {
|
||||||
bitflag: []const u8, // Hexadecimal representation of the value
|
bitflag: []const u8, // Hexadecimal representation of the value
|
||||||
int: u31,
|
int: u31,
|
||||||
@ -100,6 +103,7 @@ pub const Enumerant = struct {
|
|||||||
pub const jsonStringify = @compileError("not supported");
|
pub const jsonStringify = @compileError("not supported");
|
||||||
},
|
},
|
||||||
capabilities: [][]const u8 = &[_][]const u8{},
|
capabilities: [][]const u8 = &[_][]const u8{},
|
||||||
|
provisional: bool = false,
|
||||||
/// Valid for .ValueEnum and .BitEnum
|
/// Valid for .ValueEnum and .BitEnum
|
||||||
extensions: [][]const u8 = &[_][]const u8{},
|
extensions: [][]const u8 = &[_][]const u8{},
|
||||||
/// `quantifier` will always be `null`.
|
/// `quantifier` will always be `null`.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user