adding real runtime
This commit is contained in:
@@ -13,10 +13,13 @@ pub fn main() !void {
|
|||||||
var module = try spv.Module.init(allocator, @ptrCast(@alignCast(shader_source)));
|
var module = try spv.Module.init(allocator, @ptrCast(@alignCast(shader_source)));
|
||||||
defer module.deinit(allocator);
|
defer module.deinit(allocator);
|
||||||
|
|
||||||
var rt = spv.Runtime.init(&module);
|
var rt = try spv.Runtime.init(allocator, &module);
|
||||||
defer rt.deinit();
|
defer rt.deinit(allocator);
|
||||||
|
|
||||||
try rt.callEntryPoint(0);
|
try rt.callEntryPoint(allocator, try rt.getEntryPointByName("main"));
|
||||||
|
var output: [4]f32 = undefined;
|
||||||
|
try rt.readOutput(f32, output[0..output.len], try rt.getResultByName("color"));
|
||||||
|
std.log.info("Result: Vec4[{d}, {d}, {d}, {d}]", .{ output[0], output[1], output[2], output[3] });
|
||||||
}
|
}
|
||||||
std.log.info("Successfully executed", .{});
|
std.log.info("Successfully executed", .{});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ 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;
|
||||||
@@ -60,7 +58,7 @@ memory_model: spv.SpvMemoryModel,
|
|||||||
files: std.ArrayList(SpvSource),
|
files: std.ArrayList(SpvSource),
|
||||||
extensions: std.ArrayList([]const u8),
|
extensions: std.ArrayList([]const u8),
|
||||||
|
|
||||||
results: std.ArrayList(Result),
|
results: []Result,
|
||||||
|
|
||||||
entry_points: std.ArrayList(SpvEntryPoint),
|
entry_points: std.ArrayList(SpvEntryPoint),
|
||||||
capabilities: std.EnumSet(spv.SpvCapability),
|
capabilities: std.EnumSet(spv.SpvCapability),
|
||||||
@@ -74,9 +72,9 @@ geometry_output_count: SpvWord,
|
|||||||
geometry_input: SpvWord,
|
geometry_input: SpvWord,
|
||||||
geometry_output: SpvWord,
|
geometry_output: SpvWord,
|
||||||
|
|
||||||
input_locations: std.AutoHashMap(SpvWord, *Value),
|
input_locations: std.AutoHashMap(SpvWord, []Value),
|
||||||
output_locations: std.AutoHashMap(SpvWord, *Value),
|
output_locations: std.AutoHashMap(SpvWord, []Value),
|
||||||
bindings: std.AutoHashMap(SpvBinding, *Value),
|
bindings: std.AutoHashMap(SpvBinding, []Value),
|
||||||
push_constants: []Value,
|
push_constants: []Value,
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, source: []const SpvWord) ModuleError!Self {
|
pub fn init(allocator: std.mem.Allocator, source: []const SpvWord) ModuleError!Self {
|
||||||
@@ -84,15 +82,14 @@ pub fn init(allocator: std.mem.Allocator, source: []const SpvWord) ModuleError!S
|
|||||||
.code = allocator.dupe(SpvWord, source) catch return ModuleError.OutOfMemory,
|
.code = allocator.dupe(SpvWord, source) catch return ModuleError.OutOfMemory,
|
||||||
.files = std.ArrayList(SpvSource).empty,
|
.files = std.ArrayList(SpvSource).empty,
|
||||||
.extensions = std.ArrayList([]const u8).empty,
|
.extensions = std.ArrayList([]const u8).empty,
|
||||||
.results = std.ArrayList(Result).empty,
|
|
||||||
.entry_points = std.ArrayList(SpvEntryPoint).empty,
|
.entry_points = std.ArrayList(SpvEntryPoint).empty,
|
||||||
.capabilities = std.EnumSet(spv.SpvCapability).initEmpty(),
|
.capabilities = std.EnumSet(spv.SpvCapability).initEmpty(),
|
||||||
.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, *Value).init(allocator),
|
.input_locations = std.AutoHashMap(SpvWord, []Value).init(allocator),
|
||||||
.output_locations = std.AutoHashMap(SpvWord, *Value).init(allocator),
|
.output_locations = std.AutoHashMap(SpvWord, []Value).init(allocator),
|
||||||
.bindings = std.AutoHashMap(SpvBinding, *Value).init(allocator),
|
.bindings = std.AutoHashMap(SpvBinding, []Value).init(allocator),
|
||||||
});
|
});
|
||||||
errdefer self.deinit(allocator);
|
errdefer self.deinit(allocator);
|
||||||
|
|
||||||
@@ -115,18 +112,15 @@ pub fn init(allocator: std.mem.Allocator, source: []const SpvWord) ModuleError!S
|
|||||||
self.generator_version = @intCast(generator & 0x0000FFFF);
|
self.generator_version = @intCast(generator & 0x0000FFFF);
|
||||||
|
|
||||||
self.bound = self.it.next() catch return ModuleError.InvalidSpirV;
|
self.bound = self.it.next() catch return ModuleError.InvalidSpirV;
|
||||||
self.results.resize(allocator, self.bound) catch return ModuleError.OutOfMemory;
|
self.results = allocator.alloc(Result, self.bound) catch return ModuleError.OutOfMemory;
|
||||||
for (self.results.items) |*result| {
|
for (self.results) |*result| {
|
||||||
result.* = Result.init();
|
result.* = Result.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = self.it.skip(); // Skip schema
|
_ = self.it.skip(); // Skip schema
|
||||||
|
|
||||||
const prepassOps = std.EnumSet(spv.SpvOp).initMany(&[_]spv.SpvOp{
|
try self.pass(allocator); // Setup pass
|
||||||
spv.SpvOp.Name,
|
try self.populateMaps();
|
||||||
});
|
|
||||||
try self.pass(allocator, prepassOps); // Pre-pass
|
|
||||||
try self.pass(allocator, prepassOps.complement()); // Setup pass
|
|
||||||
|
|
||||||
if (std.process.hasEnvVarConstant("SPIRV_INTERPRETER_DEBUG_LOGS")) {
|
if (std.process.hasEnvVarConstant("SPIRV_INTERPRETER_DEBUG_LOGS")) {
|
||||||
var capability_set_names: std.ArrayList([]const u8) = .empty;
|
var capability_set_names: std.ArrayList([]const u8) = .empty;
|
||||||
@@ -166,7 +160,7 @@ pub fn init(allocator: std.mem.Allocator, source: []const SpvWord) ModuleError!S
|
|||||||
entry_points,
|
entry_points,
|
||||||
});
|
});
|
||||||
|
|
||||||
pretty.print(allocator, self.results, .{ .tab_size = 4, .max_depth = 0 }) catch return ModuleError.OutOfMemory;
|
//@import("pretty").print(allocator, self.results, .{ .tab_size = 4, .max_depth = 0 }) catch return ModuleError.OutOfMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -183,19 +177,18 @@ fn checkEndiannessFromSpvMagic(magic: SpvWord) bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pass(self: *Self, allocator: std.mem.Allocator, opcodes: std.EnumSet(spv.SpvOp)) ModuleError!void {
|
fn pass(self: *Self, allocator: std.mem.Allocator) ModuleError!void {
|
||||||
var rt = Runtime.init(self);
|
var rt = Runtime.init(allocator, self) catch return ModuleError.OutOfMemory;
|
||||||
defer rt.deinit();
|
defer rt.deinit(allocator);
|
||||||
|
|
||||||
while (rt.it.nextOrNull()) |opcode_data| {
|
while (rt.it.nextOrNull()) |opcode_data| {
|
||||||
const word_count = ((opcode_data & (~spv.SpvOpCodeMask)) >> spv.SpvWordCountShift) - 1;
|
const word_count = ((opcode_data & (~spv.SpvOpCodeMask)) >> spv.SpvWordCountShift) - 1;
|
||||||
const opcode = (opcode_data & spv.SpvOpCodeMask);
|
const opcode = (opcode_data & spv.SpvOpCodeMask);
|
||||||
|
|
||||||
var it_tmp = rt.it; // Save because operations may iter on this iterator
|
var it_tmp = rt.it; // Save because operations may iter on this iterator
|
||||||
if (std.enums.fromInt(spv.SpvOp, opcode)) |spv_op| {
|
if (std.enums.fromInt(spv.SpvOp, opcode)) |spv_op| {
|
||||||
if (opcodes.contains(spv_op)) {
|
if (op.SetupDispatcher.get(spv_op)) |pfn| {
|
||||||
if (op.SetupDispatcher.get(spv_op)) |pfn| {
|
pfn(allocator, word_count, &rt) catch return ModuleError.InvalidSpirV;
|
||||||
pfn(allocator, word_count, &rt) catch return ModuleError.InvalidSpirV;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = it_tmp.skipN(word_count);
|
_ = it_tmp.skipN(word_count);
|
||||||
@@ -203,6 +196,20 @@ fn pass(self: *Self, allocator: std.mem.Allocator, opcodes: std.EnumSet(spv.SpvO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn populateMaps(self: *Self) ModuleError!void {
|
||||||
|
for (self.results, 0..) |result, id| {
|
||||||
|
if (result.variant == null or std.meta.activeTag(result.variant.?) != .Variable) continue;
|
||||||
|
const variable = result.variant.?.Variable;
|
||||||
|
switch (variable.storage_class) {
|
||||||
|
.Output => for (result.decorations.items) |decoration| switch (decoration.rtype) {
|
||||||
|
.Location => self.output_locations.put(@intCast(id), variable.values) catch return ModuleError.OutOfMemory,
|
||||||
|
else => {},
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
||||||
allocator.free(self.code);
|
allocator.free(self.code);
|
||||||
self.input_locations.deinit();
|
self.input_locations.deinit();
|
||||||
@@ -220,8 +227,8 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|||||||
}
|
}
|
||||||
self.extensions.deinit(allocator);
|
self.extensions.deinit(allocator);
|
||||||
|
|
||||||
for (self.results.items) |*result| {
|
for (self.results) |*result| {
|
||||||
result.deinit(allocator);
|
result.deinit(allocator);
|
||||||
}
|
}
|
||||||
self.results.deinit(allocator);
|
allocator.free(self.results);
|
||||||
}
|
}
|
||||||
|
|||||||
220
src/Result.zig
220
src/Result.zig
@@ -55,7 +55,7 @@ const Decoration = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const Value = union(Type) {
|
pub const Value = union(Type) {
|
||||||
Void,
|
Void: struct {},
|
||||||
Bool: bool,
|
Bool: bool,
|
||||||
Int: extern union {
|
Int: extern union {
|
||||||
sint8: i8,
|
sint8: i8,
|
||||||
@@ -77,11 +77,11 @@ pub const Value = union(Type) {
|
|||||||
Array: struct {},
|
Array: struct {},
|
||||||
RuntimeArray: struct {},
|
RuntimeArray: struct {},
|
||||||
Structure: []Value,
|
Structure: []Value,
|
||||||
Function,
|
Function: struct {},
|
||||||
Image: struct {},
|
Image: struct {},
|
||||||
Sampler: struct {},
|
Sampler: struct {},
|
||||||
SampledImage: struct {},
|
SampledImage: struct {},
|
||||||
Pointer,
|
Pointer: struct {},
|
||||||
|
|
||||||
fn initMembers(self: *Value, allocator: std.mem.Allocator, results: []const Self, target: SpvWord) RuntimeError!void {
|
fn initMembers(self: *Value, allocator: std.mem.Allocator, results: []const Self, target: SpvWord) RuntimeError!void {
|
||||||
const resolved = results[target].resolveType(results);
|
const resolved = results[target].resolveType(results);
|
||||||
@@ -91,16 +91,19 @@ pub const Value = union(Type) {
|
|||||||
.Type => |t| switch (t) {
|
.Type => |t| switch (t) {
|
||||||
.Bool, .Int, .Float => std.debug.assert(member_count == 1),
|
.Bool, .Int, .Float => std.debug.assert(member_count == 1),
|
||||||
.Structure => |s| {
|
.Structure => |s| {
|
||||||
_ = s;
|
self.* = .{
|
||||||
//self.Structure = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory;
|
.Structure = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory,
|
||||||
//for (self.Structure, s.members) |*value, member_id| {
|
};
|
||||||
// value.* = switch (results[member_id].variant.?.Type) { // wtf ?
|
for (self.Structure, s.members) |*value, member| {
|
||||||
// inline else => |tag| @unionInit(Value, @tagName(tag), undefined),
|
value.* = switch (member) {
|
||||||
// };
|
inline else => |tag| @unionInit(Value, @tagName(tag), undefined),
|
||||||
//}
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.Matrix => |m| {
|
.Matrix => |m| {
|
||||||
self.Matrix = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory;
|
self.* = .{
|
||||||
|
.Matrix = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory,
|
||||||
|
};
|
||||||
for (self.Matrix) |*value| {
|
for (self.Matrix) |*value| {
|
||||||
value.* = switch (m.column_type) {
|
value.* = switch (m.column_type) {
|
||||||
inline else => |tag| @unionInit(Value, @tagName(tag), undefined),
|
inline else => |tag| @unionInit(Value, @tagName(tag), undefined),
|
||||||
@@ -111,7 +114,9 @@ pub const Value = union(Type) {
|
|||||||
_ = a;
|
_ = a;
|
||||||
},
|
},
|
||||||
.Vector => |v| {
|
.Vector => |v| {
|
||||||
self.Vector = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory;
|
self.* = .{
|
||||||
|
.Vector = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory,
|
||||||
|
};
|
||||||
for (self.Vector) |*value| {
|
for (self.Vector) |*value| {
|
||||||
value.* = switch (v.components_type) {
|
value.* = switch (v.components_type) {
|
||||||
inline else => |tag| @unionInit(Value, @tagName(tag), undefined),
|
inline else => |tag| @unionInit(Value, @tagName(tag), undefined),
|
||||||
@@ -123,47 +128,32 @@ pub const Value = union(Type) {
|
|||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
//void spvm_member_allocate_typed_value(spvm_member_t val, spvm_result* results, spvm_word type)
|
/// Performs a deep copy
|
||||||
//{
|
fn dupe(self: *const Value, allocator: std.mem.Allocator) RuntimeError!Value {
|
||||||
// spvm_result_t type_info = spvm_state_get_type_info(results, &results[type]);
|
return switch (self.*) {
|
||||||
// assert(type != 0);
|
.Vector => |v| .{
|
||||||
//
|
.Vector = allocator.dupe(Value, v) catch return RuntimeError.OutOfMemory,
|
||||||
// if (type_info->value_type == spvm_value_type_void ||
|
},
|
||||||
// type_info->value_type == spvm_value_type_int ||
|
.Matrix => |m| .{
|
||||||
// type_info->value_type == spvm_value_type_float ||
|
.Matrix = allocator.dupe(Value, m) catch return RuntimeError.OutOfMemory,
|
||||||
// type_info->value_type == spvm_value_type_bool) {
|
},
|
||||||
// assert(type_info->member_count == 1u);
|
.Structure => |s| .{
|
||||||
// } else {
|
.Structure = allocator.dupe(Value, s) catch return RuntimeError.OutOfMemory,
|
||||||
// spvm_member_allocate_value(val, type_info->member_count);
|
},
|
||||||
// }
|
else => self.*,
|
||||||
//
|
};
|
||||||
// val->type = type;
|
}
|
||||||
//
|
|
||||||
// if (type_info->value_type == spvm_value_type_struct) {
|
fn deinit(self: *Value, allocator: std.mem.Allocator) void {
|
||||||
// for (spvm_word i = 0; i < val->member_count; i++) {
|
switch (self.*) {
|
||||||
// spvm_member_allocate_typed_value(&val->members[i], results, type_info->params[i]);
|
.Structure => |values| allocator.free(values),
|
||||||
// }
|
.Matrix => |values| allocator.free(values),
|
||||||
// }
|
.Vector => |values| allocator.free(values),
|
||||||
// else if (type_info->value_type == spvm_value_type_matrix) {
|
else => {},
|
||||||
// for (spvm_word i = 0; i < val->member_count; i++)
|
}
|
||||||
// spvm_member_allocate_typed_value(&val->members[i], results, type_info->pointer);
|
}
|
||||||
// }
|
};
|
||||||
// else if (type_info->value_type == spvm_value_type_array) {
|
|
||||||
// if (results[type_info->pointer].member_count > 0)
|
|
||||||
// for (spvm_word i = 0; i < val->member_count; i++)
|
|
||||||
// spvm_member_allocate_typed_value(&val->members[i], results, type_info->pointer);
|
|
||||||
// } else if (type_info->value_type == spvm_value_type_vector) {
|
|
||||||
// for (spvm_word i = 0; i < val->member_count; ++i)
|
|
||||||
// val->members[i].type = type_info->pointer;
|
|
||||||
// } else {
|
|
||||||
// // having nested images/samplers is not supported
|
|
||||||
// assert(type_info->value_type != spvm_value_type_sampled_image);
|
|
||||||
// assert(type_info->value_type != spvm_value_type_image);
|
|
||||||
// assert(type_info->value_type != spvm_value_type_sampler);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
@@ -187,6 +177,7 @@ variant: ?union(Variant) {
|
|||||||
bit_length: SpvWord,
|
bit_length: SpvWord,
|
||||||
},
|
},
|
||||||
Vector: struct {
|
Vector: struct {
|
||||||
|
components_type_word: SpvWord,
|
||||||
components_type: Type,
|
components_type: Type,
|
||||||
member_count: SpvWord,
|
member_count: SpvWord,
|
||||||
},
|
},
|
||||||
@@ -198,10 +189,12 @@ variant: ?union(Variant) {
|
|||||||
Array: struct {},
|
Array: struct {},
|
||||||
RuntimeArray: struct {},
|
RuntimeArray: struct {},
|
||||||
Structure: struct {
|
Structure: struct {
|
||||||
members: []const SpvWord,
|
members_type_word: []const SpvWord,
|
||||||
|
members: []Type,
|
||||||
member_names: std.ArrayList([]const u8),
|
member_names: std.ArrayList([]const u8),
|
||||||
},
|
},
|
||||||
Function: struct {
|
Function: struct {
|
||||||
|
source_location: usize,
|
||||||
return_type: SpvWord,
|
return_type: SpvWord,
|
||||||
params: []const SpvWord,
|
params: []const SpvWord,
|
||||||
},
|
},
|
||||||
@@ -219,13 +212,19 @@ variant: ?union(Variant) {
|
|||||||
},
|
},
|
||||||
Constant: []Value,
|
Constant: []Value,
|
||||||
Function: struct {
|
Function: struct {
|
||||||
|
source_location: usize,
|
||||||
return_type: SpvWord,
|
return_type: SpvWord,
|
||||||
function_type: SpvWord,
|
function_type: SpvWord,
|
||||||
params: []const SpvWord,
|
params: []const SpvWord,
|
||||||
},
|
},
|
||||||
AccessChain: struct {},
|
AccessChain: struct {
|
||||||
|
target: SpvWord,
|
||||||
|
values: []Value,
|
||||||
|
},
|
||||||
FunctionParameter: struct {},
|
FunctionParameter: struct {},
|
||||||
Label: struct {},
|
Label: struct {
|
||||||
|
source_location: usize,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
pub fn init() Self {
|
pub fn init() Self {
|
||||||
@@ -246,6 +245,7 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|||||||
.Type => |*t| switch (t.*) {
|
.Type => |*t| switch (t.*) {
|
||||||
.Function => |data| allocator.free(data.params),
|
.Function => |data| allocator.free(data.params),
|
||||||
.Structure => |*data| {
|
.Structure => |*data| {
|
||||||
|
allocator.free(data.members_type_word);
|
||||||
allocator.free(data.members);
|
allocator.free(data.members);
|
||||||
for (data.member_names.items) |name| {
|
for (data.member_names.items) |name| {
|
||||||
allocator.free(name);
|
allocator.free(name);
|
||||||
@@ -254,13 +254,97 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
.Constant => |values| allocator.free(values),
|
.Constant => |values| {
|
||||||
|
for (values) |*value| value.deinit(allocator);
|
||||||
|
allocator.free(values);
|
||||||
|
},
|
||||||
|
.Variable => |v| {
|
||||||
|
for (v.values) |*value| value.deinit(allocator);
|
||||||
|
allocator.free(v.values);
|
||||||
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.decorations.deinit(allocator);
|
self.decorations.deinit(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs a deep copy
|
||||||
|
pub fn dupe(self: *const Self, allocator: std.mem.Allocator) RuntimeError!Self {
|
||||||
|
return .{
|
||||||
|
.name = if (self.name) |name| allocator.dupe(u8, name) catch return RuntimeError.OutOfMemory else null,
|
||||||
|
.decorations = self.decorations.clone(allocator) catch return RuntimeError.OutOfMemory,
|
||||||
|
.parent = self.parent,
|
||||||
|
.variant = blk: {
|
||||||
|
if (self.variant) |variant| {
|
||||||
|
switch (variant) {
|
||||||
|
.String => |s| break :blk .{
|
||||||
|
.String = allocator.dupe(u8, s) catch return RuntimeError.OutOfMemory,
|
||||||
|
},
|
||||||
|
.Type => |t| switch (t) {
|
||||||
|
.Structure => |s| break :blk .{
|
||||||
|
.Type = .{
|
||||||
|
.Structure = .{
|
||||||
|
.members_type_word = allocator.dupe(SpvWord, s.members_type_word) catch return RuntimeError.OutOfMemory,
|
||||||
|
.members = allocator.dupe(Type, s.members) catch return RuntimeError.OutOfMemory,
|
||||||
|
.member_names = blk2: {
|
||||||
|
const member_names = s.member_names.clone(allocator) catch return RuntimeError.OutOfMemory;
|
||||||
|
for (member_names.items, s.member_names.items) |*new_name, name| {
|
||||||
|
new_name.* = allocator.dupe(u8, name) catch return RuntimeError.OutOfMemory;
|
||||||
|
}
|
||||||
|
break :blk2 member_names;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.Function => |f| break :blk .{
|
||||||
|
.Type = .{
|
||||||
|
.Function = .{
|
||||||
|
.source_location = f.source_location,
|
||||||
|
.return_type = f.return_type,
|
||||||
|
.params = allocator.dupe(SpvWord, f.params) catch return RuntimeError.OutOfMemory,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
},
|
||||||
|
.Variable => |v| break :blk .{
|
||||||
|
.Variable = .{
|
||||||
|
.storage_class = v.storage_class,
|
||||||
|
.values = blk2: {
|
||||||
|
const values = allocator.dupe(Value, v.values) catch return RuntimeError.OutOfMemory;
|
||||||
|
for (values, v.values) |*new_value, value| {
|
||||||
|
new_value.* = try value.dupe(allocator);
|
||||||
|
}
|
||||||
|
break :blk2 values;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.Constant => |c| break :blk .{
|
||||||
|
.Constant = blk2: {
|
||||||
|
const values = allocator.dupe(Value, c) catch return RuntimeError.OutOfMemory;
|
||||||
|
for (values, c) |*new_value, value| {
|
||||||
|
new_value.* = try value.dupe(allocator);
|
||||||
|
}
|
||||||
|
break :blk2 values;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.Function => |f| break :blk .{
|
||||||
|
.Function = .{
|
||||||
|
.source_location = f.source_location,
|
||||||
|
.return_type = f.return_type,
|
||||||
|
.function_type = f.function_type,
|
||||||
|
.params = allocator.dupe(SpvWord, f.params) catch return RuntimeError.OutOfMemory,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
break :blk variant;
|
||||||
|
}
|
||||||
|
break :blk null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resolveType(self: *const Self, results: []const Self) *const Self {
|
pub fn resolveType(self: *const Self, results: []const Self) *const Self {
|
||||||
return if (self.variant) |variant|
|
return if (self.variant) |variant|
|
||||||
switch (variant) {
|
switch (variant) {
|
||||||
@@ -292,19 +376,7 @@ pub fn getMemberCounts(self: *const Self) usize {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initConstantValue(self: *Self, allocator: std.mem.Allocator, results: []const Self, target: SpvWord) RuntimeError!void {
|
pub fn initValues(allocator: std.mem.Allocator, values: []Value, results: []const Self, resolved: *const Self) RuntimeError!void {
|
||||||
const resolved = results[target].resolveType(results);
|
|
||||||
const member_count = resolved.getMemberCounts();
|
|
||||||
|
|
||||||
if (member_count == 0) return;
|
|
||||||
|
|
||||||
self.variant = .{ .Constant = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory };
|
|
||||||
errdefer switch (self.variant.?) {
|
|
||||||
.Constant => |c| allocator.free(c),
|
|
||||||
else => unreachable,
|
|
||||||
};
|
|
||||||
const values = self.variant.?.Constant;
|
|
||||||
|
|
||||||
switch (resolved.variant.?) {
|
switch (resolved.variant.?) {
|
||||||
.Type => |t| switch (t) {
|
.Type => |t| switch (t) {
|
||||||
.Bool => values[0] = .{ .Bool = undefined },
|
.Bool => values[0] = .{ .Bool = undefined },
|
||||||
@@ -322,17 +394,17 @@ pub fn initConstantValue(self: *Self, allocator: std.mem.Allocator, results: []c
|
|||||||
try value.initMembers(allocator, results, m.column_type_word);
|
try value.initMembers(allocator, results, m.column_type_word);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Array => |a| {
|
.Array => |a| { // TODO
|
||||||
_ = a;
|
_ = a;
|
||||||
},
|
},
|
||||||
.Structure => |s| {
|
.Structure => |s| {
|
||||||
for (values, s.members) |*value, member_type| {
|
for (values, s.members_type_word) |*value, member_type_word| {
|
||||||
try value.initMembers(allocator, results, member_type);
|
try value.initMembers(allocator, results, member_type_word);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Image => {},
|
.Image => {}, // TODO
|
||||||
.Sampler => {}, // No op
|
.Sampler => {}, // No op
|
||||||
.SampledImage => {},
|
.SampledImage => {}, // TODO
|
||||||
else => return RuntimeError.InvalidSpirV,
|
else => return RuntimeError.InvalidSpirV,
|
||||||
},
|
},
|
||||||
else => return RuntimeError.InvalidSpirV,
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
|||||||
149
src/Runtime.zig
149
src/Runtime.zig
@@ -19,26 +19,157 @@ pub const RuntimeError = error{
|
|||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
Unreachable,
|
Unreachable,
|
||||||
Killed,
|
Killed,
|
||||||
|
InvalidEntryPoint,
|
||||||
|
ToDo,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Function = struct {
|
||||||
|
source_location: usize,
|
||||||
|
result: *Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod: *Module,
|
mod: *Module,
|
||||||
it: WordIterator,
|
it: WordIterator,
|
||||||
|
|
||||||
current_function: ?*Result,
|
/// Local deep copy of module's results to be able to run multiple runtimes concurrently
|
||||||
|
results: []Result,
|
||||||
|
|
||||||
pub fn init(module: *Module) Self {
|
current_function: ?*Result,
|
||||||
return std.mem.zeroInit(Self, .{
|
function_stack: std.ArrayList(Function),
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator, module: *Module) RuntimeError!Self {
|
||||||
|
return .{
|
||||||
.mod = module,
|
.mod = module,
|
||||||
.it = module.it,
|
.it = module.it,
|
||||||
|
.results = blk: {
|
||||||
|
const results = allocator.dupe(Result, module.results) catch return RuntimeError.OutOfMemory;
|
||||||
|
for (results, module.results) |*new_result, result| {
|
||||||
|
new_result.* = result.dupe(allocator) catch return RuntimeError.OutOfMemory;
|
||||||
|
}
|
||||||
|
break :blk results;
|
||||||
|
},
|
||||||
.current_function = null,
|
.current_function = null,
|
||||||
});
|
.function_stack = .empty,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *const Self) void {
|
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
||||||
_ = self;
|
for (self.results) |*result| {
|
||||||
|
result.deinit(allocator);
|
||||||
|
}
|
||||||
|
allocator.free(self.results);
|
||||||
|
self.function_stack.deinit(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn callEntryPoint(self: *Self, entry: SpvWord) RuntimeError!void {
|
pub fn getEntryPointByName(self: *const Self, name: []const u8) error{NotFound}!SpvWord {
|
||||||
_ = self;
|
for (self.mod.entry_points.items, 0..) |entry_point, i| {
|
||||||
_ = entry;
|
if (blk: {
|
||||||
|
// Not using std.mem.eql as entry point names may have longer size than their content
|
||||||
|
for (0..@min(name.len, entry_point.name.len)) |j| {
|
||||||
|
if (name[j] != entry_point.name[j]) break :blk false;
|
||||||
|
}
|
||||||
|
break :blk true;
|
||||||
|
}) return @intCast(i);
|
||||||
|
}
|
||||||
|
return error.NotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getResultByName(self: *const Self, name: []const u8) error{NotFound}!SpvWord {
|
||||||
|
for (self.results, 0..) |result, i| {
|
||||||
|
if (result.name) |result_name| {
|
||||||
|
if (blk: {
|
||||||
|
// Same as entry points
|
||||||
|
for (0..@min(name.len, result_name.len)) |j| {
|
||||||
|
if (name[j] != result_name[j]) break :blk false;
|
||||||
|
}
|
||||||
|
break :blk true;
|
||||||
|
}) return @intCast(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return error.NotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calls an entry point, `entry_point_index` being the index of the entry point ordered by declaration in the bytecode
|
||||||
|
pub fn callEntryPoint(self: *Self, allocator: std.mem.Allocator, entry_point_index: SpvWord) RuntimeError!void {
|
||||||
|
self.reset();
|
||||||
|
|
||||||
|
if (entry_point_index > self.mod.entry_points.items.len) return RuntimeError.InvalidEntryPoint;
|
||||||
|
|
||||||
|
{
|
||||||
|
const entry_point_desc = &self.mod.entry_points.items[entry_point_index];
|
||||||
|
const entry_point_result = &self.mod.results[entry_point_desc.id];
|
||||||
|
if (entry_point_result.variant) |variant| {
|
||||||
|
switch (variant) {
|
||||||
|
.Function => |f| {
|
||||||
|
if (!self.it.jumpToSourceLocation(f.source_location)) return RuntimeError.InvalidEntryPoint;
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidEntryPoint,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return RuntimeError.InvalidEntryPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (self.it.nextOrNull()) |opcode_data| {
|
||||||
|
const word_count = ((opcode_data & (~spv.SpvOpCodeMask)) >> spv.SpvWordCountShift) - 1;
|
||||||
|
const opcode = (opcode_data & spv.SpvOpCodeMask);
|
||||||
|
|
||||||
|
var it_tmp = self.it; // Save because operations may iter on this iterator
|
||||||
|
if (std.enums.fromInt(spv.SpvOp, opcode)) |spv_op| {
|
||||||
|
if (op.RuntimeDispatcher.get(spv_op)) |pfn| {
|
||||||
|
try pfn(allocator, word_count, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = it_tmp.skipN(word_count);
|
||||||
|
self.it = it_tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn readOutput(self: *const Self, comptime T: type, output: []T, result: SpvWord) error{NotFound}!void {
|
||||||
|
if (self.mod.output_locations.get(result)) |out| {
|
||||||
|
self.readValue(T, output, &out[0]);
|
||||||
|
} else {
|
||||||
|
return error.NotFound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(self: *Self) void {
|
||||||
|
self.function_stack.clearRetainingCapacity();
|
||||||
|
self.current_function = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readValue(self: *const Self, comptime T: type, output: []T, value: *const Result.Value) void {
|
||||||
|
switch (value.*) {
|
||||||
|
.Bool => |b| {
|
||||||
|
if (T == bool) {
|
||||||
|
output[0] = b;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.Int => |i| {
|
||||||
|
switch (T) {
|
||||||
|
i8 => output[0] = i.sint8,
|
||||||
|
i16 => output[0] = i.sint16,
|
||||||
|
i32 => output[0] = i.sint32,
|
||||||
|
i64 => output[0] = i.sint64,
|
||||||
|
u8 => output[0] = i.uint8,
|
||||||
|
u16 => output[0] = i.uint16,
|
||||||
|
u32 => output[0] = i.uint32,
|
||||||
|
u64 => output[0] = i.uint64,
|
||||||
|
inline else => unreachable,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.Float => |f| {
|
||||||
|
switch (T) {
|
||||||
|
f16 => output[0] = f.float16,
|
||||||
|
f32 => output[0] = f.float32,
|
||||||
|
f64 => output[0] = f.float64,
|
||||||
|
inline else => unreachable,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.Vector => |values| for (values, 0..) |v, i| self.readValue(T, output[i..], &v),
|
||||||
|
.Matrix => |values| for (values, 0..) |v, i| self.readValue(T, output[i..], &v),
|
||||||
|
.Array => unreachable, // TODO
|
||||||
|
.Structure => |values| for (values, 0..) |v, i| self.readValue(T, output[i..], &v),
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,3 +54,17 @@ pub fn skipN(self: *Self, count: usize) bool {
|
|||||||
self.index += count;
|
self.index += count;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn skipToEnd(self: *Self) void {
|
||||||
|
self.index = self.buffer.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn emitSourceLocation(self: *const Self) usize {
|
||||||
|
return self.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn jumpToSourceLocation(self: *Self, source_location: usize) bool {
|
||||||
|
if (source_location > self.buffer.len) return false;
|
||||||
|
self.index = source_location;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
314
src/opcodes.zig
314
src/opcodes.zig
@@ -13,25 +13,22 @@ const SpvByte = spv.SpvByte;
|
|||||||
const SpvWord = spv.SpvWord;
|
const SpvWord = spv.SpvWord;
|
||||||
const SpvBool = spv.SpvBool;
|
const SpvBool = spv.SpvBool;
|
||||||
|
|
||||||
// DUMB INDEV OPCODES TODO :
|
|
||||||
// OpVariable X
|
|
||||||
// OpAccessChain X
|
|
||||||
// OpStore X
|
|
||||||
// OpLoad X
|
|
||||||
// OpCompositeExtract X
|
|
||||||
// OpReturn X
|
|
||||||
// OpFunctionEnd X
|
|
||||||
|
|
||||||
pub const OpCodeFunc = *const fn (std.mem.Allocator, SpvWord, *Runtime) RuntimeError!void;
|
pub const OpCodeFunc = *const fn (std.mem.Allocator, SpvWord, *Runtime) RuntimeError!void;
|
||||||
|
|
||||||
pub const SetupDispatcher = block: {
|
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,
|
||||||
|
.CompositeConstruct = opCompositeConstruct,
|
||||||
|
.CompositeExtract = opCompositeExtract,
|
||||||
.Constant = opConstant,
|
.Constant = opConstant,
|
||||||
.Decorate = opDecorate,
|
.Decorate = opDecorate,
|
||||||
.EntryPoint = opEntryPoint,
|
.EntryPoint = opEntryPoint,
|
||||||
.ExecutionMode = opExecutionMode,
|
.ExecutionMode = opExecutionMode,
|
||||||
|
.Function = opFunction,
|
||||||
|
.FunctionEnd = opFunctionEnd,
|
||||||
|
.Label = opLabel,
|
||||||
|
.Load = opLoadSetup,
|
||||||
.MemberDecorate = opDecorateMember,
|
.MemberDecorate = opDecorateMember,
|
||||||
.MemberName = opMemberName,
|
.MemberName = opMemberName,
|
||||||
.MemoryModel = opMemoryModel,
|
.MemoryModel = opMemoryModel,
|
||||||
@@ -48,9 +45,16 @@ pub const SetupDispatcher = block: {
|
|||||||
.TypeVector = opTypeVector,
|
.TypeVector = opTypeVector,
|
||||||
.TypeVoid = opTypeVoid,
|
.TypeVoid = opTypeVoid,
|
||||||
.Variable = opVariable,
|
.Variable = opVariable,
|
||||||
.Function = opFunction,
|
});
|
||||||
.Label = opLabel,
|
};
|
||||||
.CompositeConstruct = opCompositeConstruct,
|
|
||||||
|
pub const RuntimeDispatcher = block: {
|
||||||
|
@setEvalBranchQuota(65535);
|
||||||
|
break :block std.EnumMap(spv.SpvOp, OpCodeFunc).init(.{
|
||||||
|
.AccessChain = opAccessChain,
|
||||||
|
.Load = opLoad,
|
||||||
|
.Return = opReturn,
|
||||||
|
.Store = opStore,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -59,7 +63,7 @@ fn opCapability(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!voi
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn addDecoration(allocator: std.mem.Allocator, rt: *Runtime, target: SpvWord, decoration_type: spv.SpvDecoration, member: ?SpvWord) RuntimeError!void {
|
fn addDecoration(allocator: std.mem.Allocator, rt: *Runtime, target: SpvWord, decoration_type: spv.SpvDecoration, member: ?SpvWord) RuntimeError!void {
|
||||||
var decoration = rt.mod.results.items[target].decorations.addOne(allocator) catch return RuntimeError.OutOfMemory;
|
var decoration = rt.mod.results[target].decorations.addOne(allocator) catch return RuntimeError.OutOfMemory;
|
||||||
decoration.rtype = decoration_type;
|
decoration.rtype = decoration_type;
|
||||||
decoration.index = if (member) |memb| memb else 0;
|
decoration.index = if (member) |memb| memb else 0;
|
||||||
|
|
||||||
@@ -155,12 +159,13 @@ fn opMemberName(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime)
|
|||||||
const id = try rt.it.next();
|
const id = try rt.it.next();
|
||||||
const memb = try rt.it.next();
|
const memb = try rt.it.next();
|
||||||
|
|
||||||
var result = &rt.mod.results.items[id];
|
var result = &rt.mod.results[id];
|
||||||
|
|
||||||
if (result.variant == null) {
|
if (result.variant == null) {
|
||||||
result.variant = .{
|
result.variant = .{
|
||||||
.Type = .{
|
.Type = .{
|
||||||
.Structure = .{
|
.Structure = .{
|
||||||
|
.members_type_word = undefined,
|
||||||
.members = undefined,
|
.members = undefined,
|
||||||
.member_names = .empty,
|
.member_names = .empty,
|
||||||
},
|
},
|
||||||
@@ -190,8 +195,8 @@ fn opMemoryModel(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!vo
|
|||||||
|
|
||||||
fn opName(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
fn opName(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
const id = try rt.it.next();
|
const id = try rt.it.next();
|
||||||
if (id >= rt.mod.results.items.len) return RuntimeError.InvalidSpirV;
|
if (id >= rt.mod.results.len) return RuntimeError.InvalidSpirV;
|
||||||
var result = &rt.mod.results.items[id];
|
var result = &rt.mod.results[id];
|
||||||
result.* = Result.init();
|
result.* = Result.init();
|
||||||
result.name = try readStringN(allocator, &rt.it, word_count - 1);
|
result.name = try readStringN(allocator, &rt.it, word_count - 1);
|
||||||
}
|
}
|
||||||
@@ -202,15 +207,15 @@ fn opSource(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) Run
|
|||||||
file.lang_version = try rt.it.next();
|
file.lang_version = try rt.it.next();
|
||||||
if (word_count > 2) {
|
if (word_count > 2) {
|
||||||
const id = try rt.it.next();
|
const id = try rt.it.next();
|
||||||
if (id >= rt.mod.results.items.len) return RuntimeError.InvalidSpirV;
|
if (id >= rt.mod.results.len) return RuntimeError.InvalidSpirV;
|
||||||
if (rt.mod.results.items[id].name) |name| {
|
if (rt.mod.results[id].name) |name| {
|
||||||
file.file_name = name;
|
file.file_name = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (word_count > 3) {
|
if (word_count > 3) {
|
||||||
const id = try rt.it.next();
|
const id = try rt.it.next();
|
||||||
if (id >= rt.mod.results.items.len) return RuntimeError.InvalidSpirV;
|
if (id >= rt.mod.results.len) return RuntimeError.InvalidSpirV;
|
||||||
if (rt.mod.results.items[id].name) |name| {
|
if (rt.mod.results[id].name) |name| {
|
||||||
file.source = name;
|
file.source = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,7 +227,7 @@ 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].variant = .{
|
rt.mod.results[id].variant = .{
|
||||||
.Type = .{
|
.Type = .{
|
||||||
.Void = .{},
|
.Void = .{},
|
||||||
},
|
},
|
||||||
@@ -231,7 +236,7 @@ fn opTypeVoid(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!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].variant = .{
|
rt.mod.results[id].variant = .{
|
||||||
.Type = .{
|
.Type = .{
|
||||||
.Bool = .{},
|
.Bool = .{},
|
||||||
},
|
},
|
||||||
@@ -240,7 +245,7 @@ fn opTypeBool(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void
|
|||||||
|
|
||||||
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].variant = .{
|
rt.mod.results[id].variant = .{
|
||||||
.Type = .{
|
.Type = .{
|
||||||
.Int = .{
|
.Int = .{
|
||||||
.bit_length = try rt.it.next(),
|
.bit_length = try rt.it.next(),
|
||||||
@@ -252,7 +257,7 @@ fn opTypeInt(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
|||||||
|
|
||||||
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].variant = .{
|
rt.mod.results[id].variant = .{
|
||||||
.Type = .{
|
.Type = .{
|
||||||
.Float = .{
|
.Float = .{
|
||||||
.bit_length = try rt.it.next(),
|
.bit_length = try rt.it.next(),
|
||||||
@@ -263,10 +268,12 @@ fn opTypeFloat(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void
|
|||||||
|
|
||||||
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].variant = .{
|
const components_type_word = try rt.it.next();
|
||||||
|
rt.mod.results[id].variant = .{
|
||||||
.Type = .{
|
.Type = .{
|
||||||
.Vector = .{
|
.Vector = .{
|
||||||
.components_type = switch (rt.mod.results.items[try rt.it.next()].variant.?) {
|
.components_type_word = components_type_word,
|
||||||
|
.components_type = switch (rt.mod.results[components_type_word].variant.?) {
|
||||||
.Type => |t| @as(Result.Type, t),
|
.Type => |t| @as(Result.Type, t),
|
||||||
else => return RuntimeError.InvalidSpirV,
|
else => return RuntimeError.InvalidSpirV,
|
||||||
},
|
},
|
||||||
@@ -279,11 +286,11 @@ fn opTypeVector(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!voi
|
|||||||
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();
|
||||||
const column_type_word = try rt.it.next();
|
const column_type_word = try rt.it.next();
|
||||||
rt.mod.results.items[id].variant = .{
|
rt.mod.results[id].variant = .{
|
||||||
.Type = .{
|
.Type = .{
|
||||||
.Matrix = .{
|
.Matrix = .{
|
||||||
.column_type_word = column_type_word,
|
.column_type_word = column_type_word,
|
||||||
.column_type = switch (rt.mod.results.items[column_type_word].variant.?) {
|
.column_type = switch (rt.mod.results[column_type_word].variant.?) {
|
||||||
.Type => |t| @as(Result.Type, t),
|
.Type => |t| @as(Result.Type, t),
|
||||||
else => return RuntimeError.InvalidSpirV,
|
else => return RuntimeError.InvalidSpirV,
|
||||||
},
|
},
|
||||||
@@ -295,7 +302,7 @@ fn opTypeMatrix(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!voi
|
|||||||
|
|
||||||
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].variant = .{
|
rt.mod.results[id].variant = .{
|
||||||
.Type = .{
|
.Type = .{
|
||||||
.Pointer = .{
|
.Pointer = .{
|
||||||
.storage_class = try rt.it.nextAs(spv.SpvStorageClass),
|
.storage_class = try rt.it.nextAs(spv.SpvStorageClass),
|
||||||
@@ -307,27 +314,36 @@ fn opTypePointer(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!vo
|
|||||||
|
|
||||||
fn opTypeStruct(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
fn opTypeStruct(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
const id = try rt.it.next();
|
const id = try rt.it.next();
|
||||||
const members = blk: {
|
const members_type_word, const members = blk: {
|
||||||
const members = allocator.alloc(SpvWord, word_count - 1) catch return RuntimeError.OutOfMemory;
|
const members_type_word = allocator.alloc(SpvWord, word_count - 1) catch return RuntimeError.OutOfMemory;
|
||||||
|
errdefer allocator.free(members_type_word);
|
||||||
|
|
||||||
|
const members = allocator.alloc(Result.Type, word_count - 1) catch return RuntimeError.OutOfMemory;
|
||||||
errdefer allocator.free(members);
|
errdefer allocator.free(members);
|
||||||
for (members) |*member| {
|
|
||||||
member.* = try rt.it.next();
|
for (members_type_word, members) |*member_type_word, *member| {
|
||||||
|
member_type_word.* = try rt.it.next();
|
||||||
|
member.* = rt.mod.results[member_type_word.*].variant.?.Type;
|
||||||
}
|
}
|
||||||
break :blk members;
|
break :blk .{ members_type_word, members };
|
||||||
};
|
};
|
||||||
|
|
||||||
if (rt.mod.results.items[id].variant) |*variant| {
|
if (rt.mod.results[id].variant) |*variant| {
|
||||||
switch (variant.*) {
|
switch (variant.*) {
|
||||||
.Type => |*t| switch (t.*) {
|
.Type => |*t| switch (t.*) {
|
||||||
.Structure => |*s| s.members = members,
|
.Structure => |*s| {
|
||||||
|
s.members_type_word = members_type_word;
|
||||||
|
s.members = members;
|
||||||
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rt.mod.results.items[id].variant = .{
|
rt.mod.results[id].variant = .{
|
||||||
.Type = .{
|
.Type = .{
|
||||||
.Structure = .{
|
.Structure = .{
|
||||||
|
.members_type_word = members_type_word,
|
||||||
.members = members,
|
.members = members,
|
||||||
.member_names = .empty,
|
.member_names = .empty,
|
||||||
},
|
},
|
||||||
@@ -338,9 +354,10 @@ fn opTypeStruct(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime)
|
|||||||
|
|
||||||
fn opTypeFunction(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
fn opTypeFunction(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
const id = try rt.it.next();
|
const id = try rt.it.next();
|
||||||
rt.mod.results.items[id].variant = .{
|
rt.mod.results[id].variant = .{
|
||||||
.Type = .{
|
.Type = .{
|
||||||
.Function = .{
|
.Function = .{
|
||||||
|
.source_location = 0,
|
||||||
.return_type = try rt.it.next(),
|
.return_type = try rt.it.next(),
|
||||||
.params = blk: {
|
.params = blk: {
|
||||||
const params = allocator.alloc(SpvWord, word_count - 2) catch return RuntimeError.OutOfMemory;
|
const params = allocator.alloc(SpvWord, word_count - 2) catch return RuntimeError.OutOfMemory;
|
||||||
@@ -356,12 +373,7 @@ fn opTypeFunction(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtim
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn opConstant(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
fn opConstant(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
const var_type = try rt.it.next();
|
const target = try setupConstant(allocator, rt);
|
||||||
const id = try rt.it.next();
|
|
||||||
|
|
||||||
const target = &rt.mod.results.items[id];
|
|
||||||
try target.initConstantValue(allocator, rt.mod.results.items, var_type);
|
|
||||||
|
|
||||||
// No check on null and sizes, absolute trust in this shit
|
// No check on null and sizes, absolute trust in this shit
|
||||||
switch (target.variant.?.Constant[0]) {
|
switch (target.variant.?.Constant[0]) {
|
||||||
.Int => |*i| {
|
.Int => |*i| {
|
||||||
@@ -382,26 +394,29 @@ fn opConstant(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) R
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opVariable(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
fn opVariable(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
const var_type = try rt.it.next();
|
const var_type = try rt.it.next();
|
||||||
const id = try rt.it.next();
|
const id = try rt.it.next();
|
||||||
const storage_class = try rt.it.nextAs(spv.SpvStorageClass);
|
const storage_class = try rt.it.nextAs(spv.SpvStorageClass);
|
||||||
const initializer: ?SpvWord = if (word_count >= 4) try rt.it.next() else null;
|
const initializer: ?SpvWord = if (word_count >= 4) try rt.it.next() else null;
|
||||||
_ = var_type;
|
|
||||||
_ = id;
|
|
||||||
_ = storage_class;
|
|
||||||
_ = initializer;
|
|
||||||
|
|
||||||
//rt.mod.results.items[id].variant = .{
|
const target = &rt.mod.results[id];
|
||||||
// .Variable = .{
|
|
||||||
// .storage_class = storage_class,
|
const resolved = rt.mod.results[var_type].resolveType(rt.mod.results);
|
||||||
// .value = value: {
|
const member_count = resolved.getMemberCounts();
|
||||||
// const resolved = rt.mod.results.items[var_type].resolveType(rt.mod.results.items);
|
if (member_count == 0) {
|
||||||
// _ = resolved;
|
return RuntimeError.InvalidSpirV;
|
||||||
// break :value undefined;
|
}
|
||||||
// },
|
target.variant = .{
|
||||||
// },
|
.Variable = .{
|
||||||
//};
|
.storage_class = storage_class,
|
||||||
|
.values = allocator.alloc(Result.Value, member_count) catch return RuntimeError.OutOfMemory,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
errdefer allocator.free(target.variant.?.Variable.values);
|
||||||
|
try Result.initValues(allocator, target.variant.?.Variable.values, rt.mod.results, resolved);
|
||||||
|
|
||||||
|
_ = initializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opFunction(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
fn opFunction(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
@@ -410,12 +425,15 @@ fn opFunction(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeErr
|
|||||||
_ = rt.it.skip(); // Skip function control
|
_ = rt.it.skip(); // Skip function control
|
||||||
const function_type_id = try rt.it.next();
|
const function_type_id = try rt.it.next();
|
||||||
|
|
||||||
rt.mod.results.items[id].variant = .{
|
const source_location = rt.it.emitSourceLocation();
|
||||||
|
|
||||||
|
rt.mod.results[id].variant = .{
|
||||||
.Function = .{
|
.Function = .{
|
||||||
|
.source_location = source_location,
|
||||||
.return_type = return_type,
|
.return_type = return_type,
|
||||||
.function_type = function_type_id,
|
.function_type = function_type_id,
|
||||||
.params = params: {
|
.params = params: {
|
||||||
if (rt.mod.results.items[function_type_id].variant) |variant| {
|
if (rt.mod.results[function_type_id].variant) |variant| {
|
||||||
const params_count = switch (variant) {
|
const params_count = switch (variant) {
|
||||||
.Type => |t| switch (t) {
|
.Type => |t| switch (t) {
|
||||||
.Function => |f| f.params.len,
|
.Function => |f| f.params.len,
|
||||||
@@ -430,30 +448,167 @@ fn opFunction(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeErr
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
rt.current_function = &rt.mod.results.items[id];
|
rt.mod.results[function_type_id].variant.?.Type.Function.source_location = source_location;
|
||||||
|
|
||||||
|
rt.current_function = &rt.mod.results[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opLabel(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
fn opLabel(_: 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].variant = .{
|
rt.mod.results[id].variant = .{
|
||||||
.Label = .{},
|
.Label = .{
|
||||||
|
.source_location = rt.it.emitSourceLocation() - 2, // Original label location
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opCompositeConstruct(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
fn opCompositeConstruct(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
_ = rt;
|
_ = try setupConstant(allocator, rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opCompositeExtract(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
_ = try setupConstant(allocator, rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opFunctionEnd(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
rt.current_function = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opAccessChain(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
const var_type = try rt.it.next();
|
||||||
|
const id = try rt.it.next();
|
||||||
|
const base_id = try rt.it.next();
|
||||||
|
|
||||||
|
const target = &rt.results[id];
|
||||||
|
|
||||||
|
target.variant = .{
|
||||||
|
.AccessChain = .{
|
||||||
|
.target = var_type,
|
||||||
|
.values = undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const base = &rt.results[base_id];
|
||||||
|
const values = blk: {
|
||||||
|
if (base.variant) |variant| {
|
||||||
|
switch (variant) {
|
||||||
|
.Variable => |v| break :blk v.values,
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RuntimeError.InvalidSpirV;
|
||||||
|
};
|
||||||
|
var value_ptr = &values[0];
|
||||||
|
|
||||||
|
const index_count = word_count - 4;
|
||||||
|
for (0..index_count) |_| {
|
||||||
|
const member = &rt.results[try rt.it.next()];
|
||||||
|
const member_value = switch (member.variant orelse return RuntimeError.InvalidSpirV) {
|
||||||
|
.Constant => |c| &c[0],
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
switch (member_value.*) {
|
||||||
|
.Int => |i| {
|
||||||
|
if (i.uint32 > values.len) return RuntimeError.InvalidSpirV;
|
||||||
|
value_ptr = switch (value_ptr.*) {
|
||||||
|
.Vector => |v| &v[i.uint32],
|
||||||
|
.Matrix => |m| &m[i.uint32],
|
||||||
|
.Array => |_| return RuntimeError.ToDo,
|
||||||
|
.Structure => |s| &s[i.uint32],
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
target.variant.?.AccessChain.values = switch (value_ptr.*) {
|
||||||
|
.Vector => |v| v,
|
||||||
|
.Matrix => |m| m,
|
||||||
|
.Array => |_| return RuntimeError.ToDo,
|
||||||
|
.Structure => |s| s,
|
||||||
|
else => @as([*]Result.Value, @ptrCast(value_ptr))[0..1],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opStore(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
const ptr_id = try rt.it.next();
|
||||||
|
const val_id = try rt.it.next();
|
||||||
|
copyValues(
|
||||||
|
switch (rt.results[ptr_id].variant orelse return RuntimeError.InvalidSpirV) {
|
||||||
|
.Variable => |v| v.values,
|
||||||
|
.Constant => |c| c,
|
||||||
|
.AccessChain => |a| a.values,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
},
|
||||||
|
switch (rt.results[val_id].variant orelse return RuntimeError.InvalidSpirV) {
|
||||||
|
.Variable => |v| v.values,
|
||||||
|
.Constant => |c| c,
|
||||||
|
.AccessChain => |a| a.values,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opLoadSetup(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
_ = try setupConstant(allocator, rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opLoad(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
_ = rt.it.skip();
|
||||||
|
const id = try rt.it.next();
|
||||||
|
const ptr_id = try rt.it.next();
|
||||||
|
copyValues(
|
||||||
|
switch (rt.results[id].variant orelse return RuntimeError.InvalidSpirV) {
|
||||||
|
.Variable => |v| v.values,
|
||||||
|
.Constant => |c| c,
|
||||||
|
.AccessChain => |a| a.values,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
},
|
||||||
|
switch (rt.results[ptr_id].variant orelse return RuntimeError.InvalidSpirV) {
|
||||||
|
.Variable => |v| v.values,
|
||||||
|
.Constant => |c| c,
|
||||||
|
.AccessChain => |a| a.values,
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opReturn(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
_ = rt.function_stack.pop();
|
||||||
|
if (rt.function_stack.getLastOrNull()) |function| {
|
||||||
|
_ = rt.it.jumpToSourceLocation(function.source_location);
|
||||||
|
rt.current_function = function.result;
|
||||||
|
} else {
|
||||||
|
rt.current_function = null;
|
||||||
|
rt.it.skipToEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn setupConstant(allocator: std.mem.Allocator, rt: *Runtime) RuntimeError!*Result {
|
||||||
|
const res_type = try rt.it.next();
|
||||||
|
const id = try rt.it.next();
|
||||||
|
const target = &rt.mod.results[id];
|
||||||
|
|
||||||
|
const resolved = rt.mod.results[res_type].resolveType(rt.mod.results);
|
||||||
|
const member_count = resolved.getMemberCounts();
|
||||||
|
if (member_count == 0) {
|
||||||
|
return RuntimeError.InvalidSpirV;
|
||||||
|
}
|
||||||
|
target.variant = .{ .Constant = allocator.alloc(Result.Value, member_count) catch return RuntimeError.OutOfMemory };
|
||||||
|
errdefer allocator.free(target.variant.?.Constant);
|
||||||
|
try Result.initValues(allocator, target.variant.?.Constant, rt.mod.results, resolved);
|
||||||
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readString(allocator: std.mem.Allocator, it: *WordIterator) RuntimeError![]const u8 {
|
fn readString(allocator: std.mem.Allocator, it: *WordIterator) RuntimeError![]const u8 {
|
||||||
var str: std.ArrayList(u8) = .empty;
|
var str: std.ArrayList(u8) = .empty;
|
||||||
while (it.nextOrNull()) |word| {
|
while (it.nextOrNull()) |word| {
|
||||||
|
if (word == 0) break;
|
||||||
(str.addOne(allocator) catch return RuntimeError.OutOfMemory).* = @truncate(word & 0x000000FF);
|
(str.addOne(allocator) catch return RuntimeError.OutOfMemory).* = @truncate(word & 0x000000FF);
|
||||||
(str.addOne(allocator) catch return RuntimeError.OutOfMemory).* = @truncate((word & 0x0000FF00) >> 8);
|
(str.addOne(allocator) catch return RuntimeError.OutOfMemory).* = @truncate((word & 0x0000FF00) >> 8);
|
||||||
(str.addOne(allocator) catch return RuntimeError.OutOfMemory).* = @truncate((word & 0x00FF0000) >> 16);
|
(str.addOne(allocator) catch return RuntimeError.OutOfMemory).* = @truncate((word & 0x00FF0000) >> 16);
|
||||||
(str.addOne(allocator) catch return RuntimeError.OutOfMemory).* = @truncate((word & 0xFF000000) >> 24);
|
(str.addOne(allocator) catch return RuntimeError.OutOfMemory).* = @truncate((word & 0xFF000000) >> 24);
|
||||||
if (str.getLast() == 0) {
|
if (str.getLast() == 0) break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return str.toOwnedSlice(allocator);
|
return str.toOwnedSlice(allocator);
|
||||||
}
|
}
|
||||||
@@ -462,14 +617,29 @@ fn readStringN(allocator: std.mem.Allocator, it: *WordIterator, n: usize) Runtim
|
|||||||
var str = std.ArrayList(u8).initCapacity(allocator, n * 4) catch return RuntimeError.OutOfMemory;
|
var str = std.ArrayList(u8).initCapacity(allocator, n * 4) catch return RuntimeError.OutOfMemory;
|
||||||
for (0..n) |_| {
|
for (0..n) |_| {
|
||||||
if (it.nextOrNull()) |word| {
|
if (it.nextOrNull()) |word| {
|
||||||
|
if (word == 0) break;
|
||||||
str.addOneAssumeCapacity().* = @truncate(word & 0x000000FF);
|
str.addOneAssumeCapacity().* = @truncate(word & 0x000000FF);
|
||||||
str.addOneAssumeCapacity().* = @truncate((word & 0x0000FF00) >> 8);
|
str.addOneAssumeCapacity().* = @truncate((word & 0x0000FF00) >> 8);
|
||||||
str.addOneAssumeCapacity().* = @truncate((word & 0x00FF0000) >> 16);
|
str.addOneAssumeCapacity().* = @truncate((word & 0x00FF0000) >> 16);
|
||||||
str.addOneAssumeCapacity().* = @truncate((word & 0xFF000000) >> 24);
|
str.addOneAssumeCapacity().* = @truncate((word & 0xFF000000) >> 24);
|
||||||
if (str.getLast() == 0) {
|
if (str.getLast() == 0) break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return str.toOwnedSlice(allocator);
|
return str.toOwnedSlice(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copyValue(dst: *Result.Value, src: *const Result.Value) void {
|
||||||
|
switch (src.*) {
|
||||||
|
.Vector => |v| copyValues(dst.Vector, v),
|
||||||
|
.Matrix => |m| copyValues(dst.Matrix, m),
|
||||||
|
.Array => |_| unreachable,
|
||||||
|
.Structure => |s| copyValues(dst.Structure, s),
|
||||||
|
else => dst.* = src.*,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn copyValues(dst: []Result.Value, src: []const Result.Value) void {
|
||||||
|
for (dst, src) |*d, *s| {
|
||||||
|
copyValue(d, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user