working on results

This commit is contained in:
2026-01-04 00:35:40 +01:00
parent c228d86e91
commit 02b8c69838
7 changed files with 253 additions and 140 deletions

View File

@@ -10,6 +10,9 @@ pub fn build(b: *std.Build) void {
.optimize = optimize, .optimize = optimize,
}); });
const pretty = b.dependency("pretty", .{ .target = target, .optimize = optimize });
mod.addImport("pretty", pretty.module("pretty"));
const lib = b.addLibrary(.{ const lib = b.addLibrary(.{
.name = "spirv_interpreter", .name = "spirv_interpreter",
.root_module = mod, .root_module = mod,

View File

@@ -1,7 +1,12 @@
.{ .{
.name = .SPIRV_Interpreter, .name = .SPIRV_Interpreter,
.version = "0.0.1", .version = "0.0.1",
.dependencies = .{}, .dependencies = .{
.pretty = .{
.url = "https://github.com/timfayz/pretty/archive/refs/heads/main.tar.gz",
.hash = "pretty-0.10.6-Tm65r6lPAQCBxgwzehYPeqsCXQDT9kt2ktJuO-2tRfE6",
},
},
.minimum_zig_version = "0.15.2", .minimum_zig_version = "0.15.2",
.paths = .{ .paths = .{
"build.zig", "build.zig",

View File

@@ -4,18 +4,21 @@ const lib = @import("lib.zig");
const spv = @import("spv.zig"); const spv = @import("spv.zig");
const op = @import("opcodes.zig"); const op = @import("opcodes.zig");
const pretty = @import("pretty");
const SpvVoid = spv.SpvVoid; const SpvVoid = spv.SpvVoid;
const SpvByte = spv.SpvByte; const SpvByte = spv.SpvByte;
const SpvWord = spv.SpvWord; const SpvWord = spv.SpvWord;
const SpvBool = spv.SpvBool; const SpvBool = spv.SpvBool;
const SpvMember = spv.SpvMember;
const SpvBinding = spv.SpvBinding; const SpvBinding = spv.SpvBinding;
const Result = @import("Result.zig"); const Result = @import("Result.zig");
const Runtime = @import("Runtime.zig"); const Runtime = @import("Runtime.zig");
const WordIterator = @import("WordIterator.zig"); const WordIterator = @import("WordIterator.zig");
const SpvValue = Result.SpvValue;
const Self = @This(); const Self = @This();
const SpvEntryPoint = struct { const SpvEntryPoint = struct {
@@ -71,10 +74,10 @@ geometry_output_count: SpvWord,
geometry_input: SpvWord, geometry_input: SpvWord,
geometry_output: SpvWord, geometry_output: SpvWord,
input_locations: std.AutoHashMap(SpvWord, *SpvMember), input_locations: std.AutoHashMap(SpvWord, *SpvValue),
output_locations: std.AutoHashMap(SpvWord, *SpvMember), output_locations: std.AutoHashMap(SpvWord, *SpvValue),
bindings: std.AutoHashMap(SpvBinding, *SpvMember), bindings: std.AutoHashMap(SpvBinding, *SpvValue),
push_constants: []SpvMember, push_constants: []SpvValue,
pub fn init(allocator: std.mem.Allocator, source: []const SpvWord) ModuleError!Self { pub fn init(allocator: std.mem.Allocator, source: []const SpvWord) ModuleError!Self {
var self: Self = std.mem.zeroInit(Self, .{ var self: Self = std.mem.zeroInit(Self, .{
@@ -87,9 +90,9 @@ pub fn init(allocator: std.mem.Allocator, source: []const SpvWord) ModuleError!S
.local_size_x = 1, .local_size_x = 1,
.local_size_y = 1, .local_size_y = 1,
.local_size_z = 1, .local_size_z = 1,
.input_locations = std.AutoHashMap(SpvWord, *SpvMember).init(allocator), .input_locations = std.AutoHashMap(SpvWord, *SpvValue).init(allocator),
.output_locations = std.AutoHashMap(SpvWord, *SpvMember).init(allocator), .output_locations = std.AutoHashMap(SpvWord, *SpvValue).init(allocator),
.bindings = std.AutoHashMap(SpvBinding, *SpvMember).init(allocator), .bindings = std.AutoHashMap(SpvBinding, *SpvValue).init(allocator),
}); });
errdefer self.deinit(allocator); errdefer self.deinit(allocator);
@@ -162,6 +165,8 @@ pub fn init(allocator: std.mem.Allocator, source: []const SpvWord) ModuleError!S
capabilities, capabilities,
entry_points, entry_points,
}); });
pretty.print(allocator, self.results, .{ .tab_size = 4, .max_depth = 0 }) catch return ModuleError.OutOfMemory;
} }
return self; return self;

View File

@@ -6,11 +6,9 @@ const SpvByte = spv.SpvByte;
const SpvWord = spv.SpvWord; const SpvWord = spv.SpvWord;
const SpvBool = spv.SpvBool; const SpvBool = spv.SpvBool;
const Type = enum { pub const Variant = enum {
None,
String, String,
Extension, Extension,
FunctionType,
Type, Type,
Variable, Variable,
Constant, Constant,
@@ -20,7 +18,7 @@ const Type = enum {
Label, Label,
}; };
const ValueType = enum { pub const Type = enum {
Void, Void,
Bool, Bool,
Int, Int,
@@ -30,6 +28,7 @@ const ValueType = enum {
Array, Array,
RuntimeArray, RuntimeArray,
Structure, Structure,
Function,
Image, Image,
Sampler, Sampler,
SampledImage, SampledImage,
@@ -53,6 +52,36 @@ const Decoration = struct {
index: SpvWord, index: SpvWord,
}; };
pub const SpvValue = union(Type) {
Void: noreturn,
Bool: bool,
Int: union {
sint8: i8,
sint16: i16,
sint32: i32,
sint64: i64,
uint8: u8,
uint16: u16,
uint32: u32,
uint64: u64,
},
Float: union {
float16: f16,
float32: f32,
float64: f64,
},
Vector: noreturn,
Matrix: noreturn,
Array: struct {},
RuntimeArray: struct {},
Structure: struct {},
Function: noreturn,
Image: struct {},
Sampler: struct {},
SampledImage: struct {},
Pointer: noreturn,
};
const Self = @This(); const Self = @This();
name: ?[]const u8, name: ?[]const u8,
@@ -60,55 +89,55 @@ name: ?[]const u8,
parent: ?*const Self, parent: ?*const Self,
member_names: std.ArrayList([]const u8), member_names: std.ArrayList([]const u8),
members: std.ArrayList(spv.SpvMember),
decorations: std.ArrayList(Decoration), decorations: std.ArrayList(Decoration),
res_type: Type, variant: ?union(Variant) {
type_data: union(Type) {
None: struct {},
String: []const u8, String: []const u8,
Extension: struct {}, Extension: struct {},
FunctionType: struct { Type: union(Type) {
return_type: SpvWord, Void: struct {},
}, Bool: struct {},
Type: struct { Int: struct {
value_type: ValueType, bit_length: SpvWord,
data: union(ValueType) { is_signed: bool,
Void: struct {}, },
Bool: struct {}, Float: struct {
Int: struct { bit_length: SpvWord,
bit_length: SpvWord, },
is_signed: bool, Vector: struct {
}, components_type: Type,
Float: struct { member_count: SpvWord,
bit_length: SpvWord, },
}, Matrix: struct {
Vector: struct { column_type: Type,
components_type: ValueType, member_count: SpvWord,
}, },
Matrix: struct { Array: struct {},
column_type: ValueType, RuntimeArray: struct {},
}, Structure: struct {
Array: struct {}, /// Allocated array
RuntimeArray: struct {}, members: []const SpvWord,
Structure: struct {}, },
Image: struct {}, Function: struct {
Sampler: struct {}, return_type: SpvWord,
SampledImage: struct {}, /// Allocated array
Pointer: struct { params: []const SpvWord,
storage_class: spv.SpvStorageClass, },
}, Image: struct {},
Sampler: struct {},
SampledImage: struct {},
Pointer: struct {
storage_class: spv.SpvStorageClass,
target: SpvWord,
}, },
member_count: SpvWord = 0,
id: SpvWord = 0,
}, },
Variable: struct {}, Variable: struct {
Constant: struct {}, storage_class: spv.SpvStorageClass,
Function: struct { value: SpvValue,
/// Allocated array
params: []SpvWord,
}, },
Constant: SpvValue,
Function: struct {},
AccessChain: struct {}, AccessChain: struct {},
FunctionParameter: struct {}, FunctionParameter: struct {},
Label: struct {}, Label: struct {},
@@ -119,10 +148,8 @@ pub fn init() Self {
.name = null, .name = null,
.parent = null, .parent = null,
.member_names = .empty, .member_names = .empty,
.members = .empty,
.decorations = .empty, .decorations = .empty,
.res_type = .None, .variant = null,
.type_data = undefined,
}; };
} }
@@ -133,12 +160,31 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
for (self.member_names.items) |name| { for (self.member_names.items) |name| {
allocator.free(name); allocator.free(name);
} }
// FIXME if (self.variant) |variant| {
//switch (self.type_data) { switch (variant) {
// .Function => |data| allocator.free(data.params), .Type => |t| {
// else => {}, switch (t) {
//} .Function => |data| allocator.free(data.params),
.Structure => |data| allocator.free(data.members),
else => {},
}
},
else => {},
}
}
self.member_names.deinit(allocator); self.member_names.deinit(allocator);
self.members.deinit(allocator);
self.decorations.deinit(allocator); self.decorations.deinit(allocator);
} }
pub fn resolveType(self: *const Self, results: []const Self) *const Self {
return if (self.variant) |variant|
switch (variant) {
.Type => |t| switch (t) {
.Pointer => |ptr| &results[ptr.target],
else => self,
},
else => self,
}
else
self;
}

View File

@@ -15,6 +15,7 @@ const Self = @This();
pub const RuntimeError = error{ pub const RuntimeError = error{
InvalidSpirV, InvalidSpirV,
UnsupportedSpirV,
OutOfMemory, OutOfMemory,
Unreachable, Unreachable,
Killed, Killed,

View File

@@ -14,9 +14,6 @@ const SpvWord = spv.SpvWord;
const SpvBool = spv.SpvBool; const SpvBool = spv.SpvBool;
// DUMB INDEV OPCODES TODO : // DUMB INDEV OPCODES TODO :
// OpTypeFunction X
// OpTypeStruct X
// OpConstant X
// OpVariable X // OpVariable X
// OpFunction X // OpFunction X
// OpLabel X // OpLabel X
@@ -34,6 +31,7 @@ pub const SetupDispatcher = block: {
@setEvalBranchQuota(65535); @setEvalBranchQuota(65535);
break :block std.EnumMap(spv.SpvOp, OpCodeFunc).init(.{ break :block std.EnumMap(spv.SpvOp, OpCodeFunc).init(.{
.Capability = opCapability, .Capability = opCapability,
.Constant = opConstant,
.Decorate = opDecorate, .Decorate = opDecorate,
.EntryPoint = opEntryPoint, .EntryPoint = opEntryPoint,
.ExecutionMode = opExecutionMode, .ExecutionMode = opExecutionMode,
@@ -43,13 +41,16 @@ pub const SetupDispatcher = block: {
.Name = opName, .Name = opName,
.Source = opSource, .Source = opSource,
.SourceExtension = opSourceExtension, .SourceExtension = opSourceExtension,
.TypeVoid = opTypeVoid,
.TypeBool = opTypeBool, .TypeBool = opTypeBool,
.TypeInt = opTypeInt,
.TypeFloat = opTypeFloat, .TypeFloat = opTypeFloat,
.TypeVector = opTypeVector, .TypeFunction = opTypeFunction,
.TypeInt = opTypeInt,
.TypeMatrix = opTypeMatrix, .TypeMatrix = opTypeMatrix,
.TypePointer = opTypePointer, .TypePointer = opTypePointer,
.TypeStruct = opTypeStruct,
.TypeVector = opTypeVector,
.TypeVoid = opTypeVoid,
.Variable = opVariable,
}); });
}; };
@@ -203,114 +204,180 @@ fn opSourceExtension(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Run
fn opTypeVoid(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { fn opTypeVoid(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
const id = try rt.it.next(); const id = try rt.it.next();
rt.mod.results.items[id].res_type = .Type; rt.mod.results.items[id].variant = .{
rt.mod.results.items[id].type_data = .{
.Type = .{ .Type = .{
.value_type = .Void, .Void = .{},
.data = .{
.Void = .{},
},
}, },
}; };
} }
fn opTypeBool(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { fn opTypeBool(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
const id = try rt.it.next(); const id = try rt.it.next();
rt.mod.results.items[id].res_type = .Type; rt.mod.results.items[id].variant = .{
rt.mod.results.items[id].type_data = .{
.Type = .{ .Type = .{
.value_type = .Bool, .Bool = .{},
.data = .{
.Bool = .{},
},
.member_count = 1,
}, },
}; };
} }
fn opTypeInt(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { fn opTypeInt(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
const id = try rt.it.next(); const id = try rt.it.next();
rt.mod.results.items[id].res_type = .Type; rt.mod.results.items[id].variant = .{
rt.mod.results.items[id].type_data = .{
.Type = .{ .Type = .{
.value_type = .Int, .Int = .{
.data = .{ .bit_length = try rt.it.next(),
.Int = .{ .is_signed = if (try rt.it.next() != 0) true else false,
.bit_length = try rt.it.next(),
.is_signed = if (try rt.it.next() != 0) true else false,
},
}, },
.member_count = 1,
}, },
}; };
} }
fn opTypeFloat(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { fn opTypeFloat(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
const id = try rt.it.next(); const id = try rt.it.next();
rt.mod.results.items[id].res_type = .Type; rt.mod.results.items[id].variant = .{
rt.mod.results.items[id].type_data = .{
.Type = .{ .Type = .{
.value_type = .Float, .Float = .{
.data = .{ .bit_length = try rt.it.next(),
.Float = .{
.bit_length = try rt.it.next(),
},
}, },
.member_count = 1,
}, },
}; };
} }
fn opTypeVector(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { fn opTypeVector(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
const id = try rt.it.next(); const id = try rt.it.next();
rt.mod.results.items[id].res_type = .Type; rt.mod.results.items[id].variant = .{
rt.mod.results.items[id].type_data = .{
.Type = .{ .Type = .{
.value_type = .Vector, .Vector = .{
.data = .{ .components_type = switch (rt.mod.results.items[try rt.it.next()].variant.?) {
.Vector = .{ .Type => |t| @as(Result.Type, t),
.components_type = switch (rt.mod.results.items[try rt.it.next()].type_data) { else => return RuntimeError.InvalidSpirV,
.Type => |data| data.value_type,
else => return RuntimeError.InvalidSpirV,
},
}, },
.member_count = try rt.it.next(),
}, },
.member_count = try rt.it.next(),
}, },
}; };
} }
fn opTypeMatrix(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { fn opTypeMatrix(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
const id = try rt.it.next(); const id = try rt.it.next();
rt.mod.results.items[id].res_type = .Type; rt.mod.results.items[id].variant = .{
rt.mod.results.items[id].type_data = .{
.Type = .{ .Type = .{
.value_type = .Matrix, .Matrix = .{
.data = .{ .column_type = switch (rt.mod.results.items[try rt.it.next()].variant.?) {
.Matrix = .{ .Type => |t| @as(Result.Type, t),
.column_type = switch (rt.mod.results.items[try rt.it.next()].type_data) { else => return RuntimeError.InvalidSpirV,
.Type => |data| data.value_type,
else => return RuntimeError.InvalidSpirV,
},
}, },
.member_count = try rt.it.next(),
}, },
.member_count = try rt.it.next(),
}, },
}; };
} }
fn opTypePointer(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { fn opTypePointer(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
const id = try rt.it.next(); const id = try rt.it.next();
rt.mod.results.items[id].res_type = .Type; rt.mod.results.items[id].variant = .{
rt.mod.results.items[id].type_data = .{
.Type = .{ .Type = .{
.value_type = .Pointer, .Pointer = .{
.data = .{ .storage_class = try rt.it.nextAs(spv.SpvStorageClass),
.Pointer = .{ .target = try rt.it.next(),
.storage_class = try rt.it.nextAs(spv.SpvStorageClass), },
},
};
}
fn opTypeStruct(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
const id = try rt.it.next();
rt.mod.results.items[id].variant = .{
.Type = .{
.Structure = .{
.members = blk: {
const members = allocator.alloc(SpvWord, word_count - 1) catch return RuntimeError.OutOfMemory;
errdefer allocator.free(members);
for (members) |*member| {
member.* = try rt.it.next();
}
break :blk members;
}, },
}, },
.id = try rt.it.next(), },
};
}
fn opTypeFunction(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
const id = try rt.it.next();
rt.mod.results.items[id].variant = .{
.Type = .{
.Function = .{
.return_type = try rt.it.next(),
.params = blk: {
const params = allocator.alloc(SpvWord, word_count - 2) catch return RuntimeError.OutOfMemory;
errdefer allocator.free(params);
for (params) |*param| {
param.* = try rt.it.next();
}
break :blk params;
},
},
},
};
}
fn opConstant(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
const var_type = try rt.it.next();
const id = try rt.it.next();
rt.mod.results.items[id].variant = .{
.Constant = value: {
const resolved = rt.mod.results.items[var_type].resolveType(rt.mod.results.items);
if (resolved.variant) |variant| {
switch (variant) {
.Type => |t| switch (t) {
.Int => {
break :value if (word_count - 2 != 1) .{
.Int = .{
.uint64 = try rt.it.next() | (@as(u64, try rt.it.next()) >> 32),
},
} else .{
.Int = .{
.uint32 = try rt.it.next(),
},
};
},
.Float => {
break :value if (word_count - 2 != 1) .{
.Float = .{
.float64 = @bitCast(@as(u64, try rt.it.next()) | (@as(u64, try rt.it.next()) >> 32)),
},
} else .{
.Float = .{
.float32 = @bitCast(try rt.it.next()),
},
};
},
else => {}, // Will fallback on error,
},
else => {}, // Will fallback on error
}
}
return RuntimeError.InvalidSpirV;
},
};
}
fn opVariable(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
const var_type = try rt.it.next();
const id = try rt.it.next();
const storage_class = try rt.it.nextAs(spv.SpvStorageClass);
const initializer: ?SpvWord = if (word_count >= 4) try rt.it.next() else null;
_ = initializer;
rt.mod.results.items[id].variant = .{
.Variable = .{
.storage_class = storage_class,
.value = value: {
const resolved = rt.mod.results.items[var_type].resolveType(rt.mod.results.items);
_ = resolved;
break :value undefined;
},
}, },
}; };
} }

View File

@@ -68,20 +68,6 @@ pub fn vendorName(id: u32) []const u8 {
}; };
} }
pub const SpvMember = struct {
type: SpvWord,
value: union {
boolean: bool,
int32: i32,
uint32: u32,
uint64: u64,
float32: f32,
float64: f64,
// TODO: sampler, image, sampledimage
},
members: []SpvMember,
};
pub const SpvBinding = struct { pub const SpvBinding = struct {
set: SpvWord, set: SpvWord,
binding: SpvWord, binding: SpvWord,