working on results
This commit is contained in:
@@ -10,6 +10,9 @@ pub fn build(b: *std.Build) void {
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const pretty = b.dependency("pretty", .{ .target = target, .optimize = optimize });
|
||||
mod.addImport("pretty", pretty.module("pretty"));
|
||||
|
||||
const lib = b.addLibrary(.{
|
||||
.name = "spirv_interpreter",
|
||||
.root_module = mod,
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
.{
|
||||
.name = .SPIRV_Interpreter,
|
||||
.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",
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
|
||||
@@ -4,18 +4,21 @@ const lib = @import("lib.zig");
|
||||
const spv = @import("spv.zig");
|
||||
const op = @import("opcodes.zig");
|
||||
|
||||
const pretty = @import("pretty");
|
||||
|
||||
const SpvVoid = spv.SpvVoid;
|
||||
const SpvByte = spv.SpvByte;
|
||||
const SpvWord = spv.SpvWord;
|
||||
const SpvBool = spv.SpvBool;
|
||||
|
||||
const SpvMember = spv.SpvMember;
|
||||
const SpvBinding = spv.SpvBinding;
|
||||
|
||||
const Result = @import("Result.zig");
|
||||
const Runtime = @import("Runtime.zig");
|
||||
const WordIterator = @import("WordIterator.zig");
|
||||
|
||||
const SpvValue = Result.SpvValue;
|
||||
|
||||
const Self = @This();
|
||||
|
||||
const SpvEntryPoint = struct {
|
||||
@@ -71,10 +74,10 @@ geometry_output_count: SpvWord,
|
||||
geometry_input: SpvWord,
|
||||
geometry_output: SpvWord,
|
||||
|
||||
input_locations: std.AutoHashMap(SpvWord, *SpvMember),
|
||||
output_locations: std.AutoHashMap(SpvWord, *SpvMember),
|
||||
bindings: std.AutoHashMap(SpvBinding, *SpvMember),
|
||||
push_constants: []SpvMember,
|
||||
input_locations: std.AutoHashMap(SpvWord, *SpvValue),
|
||||
output_locations: std.AutoHashMap(SpvWord, *SpvValue),
|
||||
bindings: std.AutoHashMap(SpvBinding, *SpvValue),
|
||||
push_constants: []SpvValue,
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, source: []const SpvWord) ModuleError!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_y = 1,
|
||||
.local_size_z = 1,
|
||||
.input_locations = std.AutoHashMap(SpvWord, *SpvMember).init(allocator),
|
||||
.output_locations = std.AutoHashMap(SpvWord, *SpvMember).init(allocator),
|
||||
.bindings = std.AutoHashMap(SpvBinding, *SpvMember).init(allocator),
|
||||
.input_locations = std.AutoHashMap(SpvWord, *SpvValue).init(allocator),
|
||||
.output_locations = std.AutoHashMap(SpvWord, *SpvValue).init(allocator),
|
||||
.bindings = std.AutoHashMap(SpvBinding, *SpvValue).init(allocator),
|
||||
});
|
||||
errdefer self.deinit(allocator);
|
||||
|
||||
@@ -162,6 +165,8 @@ pub fn init(allocator: std.mem.Allocator, source: []const SpvWord) ModuleError!S
|
||||
capabilities,
|
||||
entry_points,
|
||||
});
|
||||
|
||||
pretty.print(allocator, self.results, .{ .tab_size = 4, .max_depth = 0 }) catch return ModuleError.OutOfMemory;
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
154
src/Result.zig
154
src/Result.zig
@@ -6,11 +6,9 @@ const SpvByte = spv.SpvByte;
|
||||
const SpvWord = spv.SpvWord;
|
||||
const SpvBool = spv.SpvBool;
|
||||
|
||||
const Type = enum {
|
||||
None,
|
||||
pub const Variant = enum {
|
||||
String,
|
||||
Extension,
|
||||
FunctionType,
|
||||
Type,
|
||||
Variable,
|
||||
Constant,
|
||||
@@ -20,7 +18,7 @@ const Type = enum {
|
||||
Label,
|
||||
};
|
||||
|
||||
const ValueType = enum {
|
||||
pub const Type = enum {
|
||||
Void,
|
||||
Bool,
|
||||
Int,
|
||||
@@ -30,6 +28,7 @@ const ValueType = enum {
|
||||
Array,
|
||||
RuntimeArray,
|
||||
Structure,
|
||||
Function,
|
||||
Image,
|
||||
Sampler,
|
||||
SampledImage,
|
||||
@@ -53,6 +52,36 @@ const Decoration = struct {
|
||||
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();
|
||||
|
||||
name: ?[]const u8,
|
||||
@@ -60,55 +89,55 @@ name: ?[]const u8,
|
||||
parent: ?*const Self,
|
||||
|
||||
member_names: std.ArrayList([]const u8),
|
||||
members: std.ArrayList(spv.SpvMember),
|
||||
|
||||
decorations: std.ArrayList(Decoration),
|
||||
|
||||
res_type: Type,
|
||||
type_data: union(Type) {
|
||||
None: struct {},
|
||||
variant: ?union(Variant) {
|
||||
String: []const u8,
|
||||
Extension: struct {},
|
||||
FunctionType: struct {
|
||||
return_type: SpvWord,
|
||||
},
|
||||
Type: struct {
|
||||
value_type: ValueType,
|
||||
data: union(ValueType) {
|
||||
Void: struct {},
|
||||
Bool: struct {},
|
||||
Int: struct {
|
||||
bit_length: SpvWord,
|
||||
is_signed: bool,
|
||||
},
|
||||
Float: struct {
|
||||
bit_length: SpvWord,
|
||||
},
|
||||
Vector: struct {
|
||||
components_type: ValueType,
|
||||
},
|
||||
Matrix: struct {
|
||||
column_type: ValueType,
|
||||
},
|
||||
Array: struct {},
|
||||
RuntimeArray: struct {},
|
||||
Structure: struct {},
|
||||
Image: struct {},
|
||||
Sampler: struct {},
|
||||
SampledImage: struct {},
|
||||
Pointer: struct {
|
||||
storage_class: spv.SpvStorageClass,
|
||||
},
|
||||
Type: union(Type) {
|
||||
Void: struct {},
|
||||
Bool: struct {},
|
||||
Int: struct {
|
||||
bit_length: SpvWord,
|
||||
is_signed: bool,
|
||||
},
|
||||
Float: struct {
|
||||
bit_length: SpvWord,
|
||||
},
|
||||
Vector: struct {
|
||||
components_type: Type,
|
||||
member_count: SpvWord,
|
||||
},
|
||||
Matrix: struct {
|
||||
column_type: Type,
|
||||
member_count: SpvWord,
|
||||
},
|
||||
Array: struct {},
|
||||
RuntimeArray: struct {},
|
||||
Structure: struct {
|
||||
/// Allocated array
|
||||
members: []const SpvWord,
|
||||
},
|
||||
Function: struct {
|
||||
return_type: SpvWord,
|
||||
/// Allocated array
|
||||
params: []const SpvWord,
|
||||
},
|
||||
Image: struct {},
|
||||
Sampler: struct {},
|
||||
SampledImage: struct {},
|
||||
Pointer: struct {
|
||||
storage_class: spv.SpvStorageClass,
|
||||
target: SpvWord,
|
||||
},
|
||||
member_count: SpvWord = 0,
|
||||
id: SpvWord = 0,
|
||||
},
|
||||
Variable: struct {},
|
||||
Constant: struct {},
|
||||
Function: struct {
|
||||
/// Allocated array
|
||||
params: []SpvWord,
|
||||
Variable: struct {
|
||||
storage_class: spv.SpvStorageClass,
|
||||
value: SpvValue,
|
||||
},
|
||||
Constant: SpvValue,
|
||||
Function: struct {},
|
||||
AccessChain: struct {},
|
||||
FunctionParameter: struct {},
|
||||
Label: struct {},
|
||||
@@ -119,10 +148,8 @@ pub fn init() Self {
|
||||
.name = null,
|
||||
.parent = null,
|
||||
.member_names = .empty,
|
||||
.members = .empty,
|
||||
.decorations = .empty,
|
||||
.res_type = .None,
|
||||
.type_data = undefined,
|
||||
.variant = null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -133,12 +160,31 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
||||
for (self.member_names.items) |name| {
|
||||
allocator.free(name);
|
||||
}
|
||||
// FIXME
|
||||
//switch (self.type_data) {
|
||||
// .Function => |data| allocator.free(data.params),
|
||||
// else => {},
|
||||
//}
|
||||
if (self.variant) |variant| {
|
||||
switch (variant) {
|
||||
.Type => |t| {
|
||||
switch (t) {
|
||||
.Function => |data| allocator.free(data.params),
|
||||
.Structure => |data| allocator.free(data.members),
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
self.member_names.deinit(allocator);
|
||||
self.members.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;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ const Self = @This();
|
||||
|
||||
pub const RuntimeError = error{
|
||||
InvalidSpirV,
|
||||
UnsupportedSpirV,
|
||||
OutOfMemory,
|
||||
Unreachable,
|
||||
Killed,
|
||||
|
||||
193
src/opcodes.zig
193
src/opcodes.zig
@@ -14,9 +14,6 @@ const SpvWord = spv.SpvWord;
|
||||
const SpvBool = spv.SpvBool;
|
||||
|
||||
// DUMB INDEV OPCODES TODO :
|
||||
// OpTypeFunction X
|
||||
// OpTypeStruct X
|
||||
// OpConstant X
|
||||
// OpVariable X
|
||||
// OpFunction X
|
||||
// OpLabel X
|
||||
@@ -34,6 +31,7 @@ pub const SetupDispatcher = block: {
|
||||
@setEvalBranchQuota(65535);
|
||||
break :block std.EnumMap(spv.SpvOp, OpCodeFunc).init(.{
|
||||
.Capability = opCapability,
|
||||
.Constant = opConstant,
|
||||
.Decorate = opDecorate,
|
||||
.EntryPoint = opEntryPoint,
|
||||
.ExecutionMode = opExecutionMode,
|
||||
@@ -43,13 +41,16 @@ pub const SetupDispatcher = block: {
|
||||
.Name = opName,
|
||||
.Source = opSource,
|
||||
.SourceExtension = opSourceExtension,
|
||||
.TypeVoid = opTypeVoid,
|
||||
.TypeBool = opTypeBool,
|
||||
.TypeInt = opTypeInt,
|
||||
.TypeFloat = opTypeFloat,
|
||||
.TypeVector = opTypeVector,
|
||||
.TypeFunction = opTypeFunction,
|
||||
.TypeInt = opTypeInt,
|
||||
.TypeMatrix = opTypeMatrix,
|
||||
.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 {
|
||||
const id = try rt.it.next();
|
||||
rt.mod.results.items[id].res_type = .Type;
|
||||
rt.mod.results.items[id].type_data = .{
|
||||
rt.mod.results.items[id].variant = .{
|
||||
.Type = .{
|
||||
.value_type = .Void,
|
||||
.data = .{
|
||||
.Void = .{},
|
||||
},
|
||||
.Void = .{},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn opTypeBool(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||
const id = try rt.it.next();
|
||||
rt.mod.results.items[id].res_type = .Type;
|
||||
rt.mod.results.items[id].type_data = .{
|
||||
rt.mod.results.items[id].variant = .{
|
||||
.Type = .{
|
||||
.value_type = .Bool,
|
||||
.data = .{
|
||||
.Bool = .{},
|
||||
},
|
||||
.member_count = 1,
|
||||
.Bool = .{},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn opTypeInt(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||
const id = try rt.it.next();
|
||||
rt.mod.results.items[id].res_type = .Type;
|
||||
rt.mod.results.items[id].type_data = .{
|
||||
rt.mod.results.items[id].variant = .{
|
||||
.Type = .{
|
||||
.value_type = .Int,
|
||||
.data = .{
|
||||
.Int = .{
|
||||
.bit_length = try rt.it.next(),
|
||||
.is_signed = if (try rt.it.next() != 0) true else false,
|
||||
},
|
||||
.Int = .{
|
||||
.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 {
|
||||
const id = try rt.it.next();
|
||||
rt.mod.results.items[id].res_type = .Type;
|
||||
rt.mod.results.items[id].type_data = .{
|
||||
rt.mod.results.items[id].variant = .{
|
||||
.Type = .{
|
||||
.value_type = .Float,
|
||||
.data = .{
|
||||
.Float = .{
|
||||
.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 {
|
||||
const id = try rt.it.next();
|
||||
rt.mod.results.items[id].res_type = .Type;
|
||||
rt.mod.results.items[id].type_data = .{
|
||||
rt.mod.results.items[id].variant = .{
|
||||
.Type = .{
|
||||
.value_type = .Vector,
|
||||
.data = .{
|
||||
.Vector = .{
|
||||
.components_type = switch (rt.mod.results.items[try rt.it.next()].type_data) {
|
||||
.Type => |data| data.value_type,
|
||||
else => return RuntimeError.InvalidSpirV,
|
||||
},
|
||||
.Vector = .{
|
||||
.components_type = switch (rt.mod.results.items[try rt.it.next()].variant.?) {
|
||||
.Type => |t| @as(Result.Type, t),
|
||||
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 {
|
||||
const id = try rt.it.next();
|
||||
rt.mod.results.items[id].res_type = .Type;
|
||||
rt.mod.results.items[id].type_data = .{
|
||||
rt.mod.results.items[id].variant = .{
|
||||
.Type = .{
|
||||
.value_type = .Matrix,
|
||||
.data = .{
|
||||
.Matrix = .{
|
||||
.column_type = switch (rt.mod.results.items[try rt.it.next()].type_data) {
|
||||
.Type => |data| data.value_type,
|
||||
else => return RuntimeError.InvalidSpirV,
|
||||
},
|
||||
.Matrix = .{
|
||||
.column_type = switch (rt.mod.results.items[try rt.it.next()].variant.?) {
|
||||
.Type => |t| @as(Result.Type, t),
|
||||
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 {
|
||||
const id = try rt.it.next();
|
||||
rt.mod.results.items[id].res_type = .Type;
|
||||
rt.mod.results.items[id].type_data = .{
|
||||
rt.mod.results.items[id].variant = .{
|
||||
.Type = .{
|
||||
.value_type = .Pointer,
|
||||
.data = .{
|
||||
.Pointer = .{
|
||||
.storage_class = try rt.it.nextAs(spv.SpvStorageClass),
|
||||
.Pointer = .{
|
||||
.storage_class = try rt.it.nextAs(spv.SpvStorageClass),
|
||||
.target = try rt.it.next(),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
14
src/spv.zig
14
src/spv.zig
@@ -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 {
|
||||
set: SpvWord,
|
||||
binding: SpvWord,
|
||||
|
||||
Reference in New Issue
Block a user