Files
SPIRV-Interpreter/src/Result.zig
Kbz-8 7dd86b021d
All checks were successful
Build / build (push) Successful in 2m17s
Test / build (push) Successful in 9m19s
fixing tests failure
2026-03-11 12:37:08 +01:00

926 lines
33 KiB
Zig

const std = @import("std");
const spv = @import("spv.zig");
const op = @import("opcodes.zig");
const Runtime = @import("Runtime.zig");
const RuntimeError = Runtime.RuntimeError;
const SpvVoid = spv.SpvVoid;
const SpvByte = spv.SpvByte;
const SpvWord = spv.SpvWord;
const SpvBool = spv.SpvBool;
pub const Vec4f32 = @Vector(4, f32);
pub const Vec3f32 = @Vector(3, f32);
pub const Vec2f32 = @Vector(2, f32);
pub const Vec4i32 = @Vector(4, i32);
pub const Vec3i32 = @Vector(3, i32);
pub const Vec2i32 = @Vector(2, i32);
pub const Vec4u32 = @Vector(4, u32);
pub const Vec3u32 = @Vector(3, u32);
pub const Vec2u32 = @Vector(2, u32);
pub const Variant = enum {
String,
Extension,
Type,
Variable,
Constant,
Function,
AccessChain,
FunctionParameter,
Label,
};
pub const Type = enum {
Void,
Bool,
Int,
Float,
Vector,
Vector4f32,
Vector3f32,
Vector2f32,
Vector4i32,
Vector3i32,
Vector2i32,
Vector4u32,
Vector3u32,
Vector2u32,
Matrix,
Array,
RuntimeArray,
Structure,
Function,
Image,
Sampler,
SampledImage,
Pointer,
};
const ImageInfo = struct {
dim: spv.SpvDim,
depth: SpvByte,
arrayed: SpvByte,
ms: SpvByte,
sampled: SpvByte,
format: spv.SpvImageFormat,
access: spv.SpvAccessQualifier,
};
const Decoration = struct {
rtype: spv.SpvDecoration,
literal_1: SpvWord,
literal_2: ?SpvWord,
index: SpvWord,
};
pub const Value = union(Type) {
Void: struct {},
Bool: bool,
Int: struct {
bit_count: usize,
value: extern union {
sint8: i8,
sint16: i16,
sint32: i32,
sint64: i64,
uint8: u8,
uint16: u16,
uint32: u32,
uint64: u64,
},
},
Float: struct {
bit_count: usize,
value: extern union {
float16: f16,
float32: f32,
float64: f64,
},
},
Vector: []Value,
Vector4f32: Vec4f32,
Vector3f32: Vec3f32,
Vector2f32: Vec2f32,
Vector4i32: Vec4i32,
Vector3i32: Vec3i32,
Vector2i32: Vec2i32,
Vector4u32: Vec4u32,
Vector3u32: Vec3u32,
Vector2u32: Vec2u32,
Matrix: []Value,
Array: []Value,
RuntimeArray: struct {
type_word: SpvWord,
data: []u8,
},
Structure: []Value,
Function: noreturn,
Image: struct {},
Sampler: struct {},
SampledImage: struct {},
Pointer: struct {
ptr: union(enum) {
common: *Value,
f32_ptr: *f32,
i32_ptr: *i32, //< For vector specializations
u32_ptr: *u32,
},
runtime_array_window: ?[]u8 = null,
},
pub inline fn getCompositeDataOrNull(self: *const Value) ?[]Value {
return switch (self.*) {
.Vector, .Matrix, .Array, .Structure => |v| v,
else => null,
};
}
pub fn init(allocator: std.mem.Allocator, results: []const Self, target: SpvWord) RuntimeError!Value {
const resolved = results[target].resolveType(results);
const member_count = resolved.getMemberCounts();
return switch (resolved.variant.?) {
.Type => |t| switch (t) {
.Bool => .{ .Bool = false },
.Int => |i| .{ .Int = .{
.bit_count = i.bit_length,
.value = .{ .uint64 = 0 },
} },
.Float => |f| .{ .Float = .{
.bit_count = f.bit_length,
.value = .{ .float64 = 0 },
} },
.Vector => |v| blk: {
var self: Value = .{ .Vector = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory };
errdefer self.deinit(allocator);
for (self.Vector) |*value| {
value.* = try Value.init(allocator, results, v.components_type_word);
}
break :blk self;
},
.Vector4f32 => .{ .Vector4f32 = Vec4f32{ 0.0, 0.0, 0.0, 0.0 } },
.Vector3f32 => .{ .Vector3f32 = Vec3f32{ 0.0, 0.0, 0.0 } },
.Vector2f32 => .{ .Vector2f32 = Vec2f32{ 0.0, 0.0 } },
.Vector4i32 => .{ .Vector4i32 = Vec4i32{ 0, 0, 0, 0 } },
.Vector3i32 => .{ .Vector3i32 = Vec3i32{ 0, 0, 0 } },
.Vector2i32 => .{ .Vector2i32 = Vec2i32{ 0, 0 } },
.Vector4u32 => .{ .Vector4u32 = Vec4u32{ 0, 0, 0, 0 } },
.Vector3u32 => .{ .Vector3u32 = Vec3u32{ 0, 0, 0 } },
.Vector2u32 => .{ .Vector2u32 = Vec2u32{ 0, 0 } },
.Matrix => |m| blk: {
var self: Value = .{ .Matrix = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory };
errdefer self.deinit(allocator);
for (self.Matrix) |*value| {
value.* = try Value.init(allocator, results, m.column_type_word);
}
break :blk self;
},
.Array => |a| blk: {
var self: Value = .{ .Array = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory };
errdefer self.deinit(allocator);
for (self.Array) |*value| {
value.* = try Value.init(allocator, results, a.components_type_word);
}
break :blk self;
},
.Structure => |s| blk: {
var self: Value = .{ .Structure = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory };
errdefer self.deinit(allocator);
for (self.Structure, s.members_type_word) |*value, member_type_word| {
value.* = try Value.init(allocator, results, member_type_word);
}
break :blk self;
},
.RuntimeArray => |a| .{
.RuntimeArray = .{
.type_word = a.components_type_word,
.data = &.{},
},
},
else => unreachable,
},
else => unreachable,
};
}
/// Performs a deep copy
pub fn dupe(self: *const Value, allocator: std.mem.Allocator) RuntimeError!Value {
return switch (self.*) {
.Vector => |v| .{
.Vector = blk: {
const values = allocator.dupe(Value, v) catch return RuntimeError.OutOfMemory;
for (values, v) |*new_value, value| new_value.* = try value.dupe(allocator);
break :blk values;
},
},
.Matrix => |m| .{
.Matrix = blk: {
const values = allocator.dupe(Value, m) catch return RuntimeError.OutOfMemory;
for (values, m) |*new_value, value| new_value.* = try value.dupe(allocator);
break :blk values;
},
},
.Array => |a| .{
.Array = blk: {
const values = allocator.dupe(Value, a) catch return RuntimeError.OutOfMemory;
for (values, a) |*new_value, value| new_value.* = try value.dupe(allocator);
break :blk values;
},
},
.Structure => |s| .{
.Structure = blk: {
const values = allocator.dupe(Value, s) catch return RuntimeError.OutOfMemory;
for (values, s) |*new_value, value| new_value.* = try value.dupe(allocator);
break :blk values;
},
},
else => self.*,
};
}
pub fn read(self: *const Value, output: []u8) RuntimeError!usize {
switch (self.*) {
.Bool => |b| {
output[0] = if (b == true) 1 else 0;
return 1;
},
.Int => |i| {
switch (i.bit_count) {
8 => output[0] = @bitCast(i.value.uint8),
16 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&i.value.uint16)),
32 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&i.value.uint32)),
64 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&i.value.uint64)),
else => return RuntimeError.InvalidValueType,
}
return @divExact(i.bit_count, 8);
},
.Float => |f| {
switch (f.bit_count) {
16 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&f.value.float16)),
32 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&f.value.float32)),
64 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&f.value.float64)),
else => return RuntimeError.InvalidValueType,
}
return @divExact(f.bit_count, 8);
},
.Vector4f32 => |vec| {
inline for (0..4) |i| {
std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i]));
}
return 4 * 4;
},
.Vector3f32 => |vec| {
inline for (0..3) |i| {
std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i]));
}
return 3 * 4;
},
.Vector2f32 => |vec| {
inline for (0..2) |i| {
std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i]));
}
return 2 * 4;
},
.Vector4i32 => |vec| {
inline for (0..4) |i| {
std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i]));
}
return 4 * 4;
},
.Vector3i32 => |vec| {
inline for (0..3) |i| {
std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i]));
}
return 3 * 4;
},
.Vector2i32 => |vec| {
inline for (0..2) |i| {
std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i]));
}
return 2 * 4;
},
.Vector4u32 => |vec| {
inline for (0..4) |i| {
std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i]));
}
return 4 * 4;
},
.Vector3u32 => |vec| {
inline for (0..3) |i| {
std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i]));
}
return 3 * 4;
},
.Vector2u32 => |vec| {
inline for (0..2) |i| {
std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i]));
}
return 2 * 4;
},
.Vector,
.Matrix,
.Array,
.Structure,
=> |values| {
var offset: usize = 0;
for (values) |v| {
offset += try v.read(output[offset..]);
}
return offset;
},
else => return RuntimeError.InvalidValueType,
}
return 0;
}
pub fn writeConst(self: *Value, input: []const u8) RuntimeError!usize {
return self.write(@constCast(input));
}
pub fn write(self: *Value, input: []u8) RuntimeError!usize {
switch (self.*) {
.Bool => |*b| {
b.* = if (input[0] != 0) true else false;
return 1;
},
.Int => |*i| {
switch (i.bit_count) {
8 => i.value.uint8 = @bitCast(input[0]),
16 => std.mem.copyForwards(u8, std.mem.asBytes(&i.value.uint16), input[0..2]),
32 => std.mem.copyForwards(u8, std.mem.asBytes(&i.value.uint32), input[0..4]),
64 => std.mem.copyForwards(u8, std.mem.asBytes(&i.value.uint64), input[0..8]),
else => return RuntimeError.InvalidValueType,
}
return @divExact(i.bit_count, 8);
},
.Float => |*f| {
switch (f.bit_count) {
16 => std.mem.copyForwards(u8, std.mem.asBytes(&f.value.float16), input[0..2]),
32 => std.mem.copyForwards(u8, std.mem.asBytes(&f.value.float32), input[0..4]),
64 => std.mem.copyForwards(u8, std.mem.asBytes(&f.value.float64), input[0..8]),
else => return RuntimeError.InvalidValueType,
}
return @divExact(f.bit_count, 8);
},
.Vector4f32 => |*vec| {
inline for (0..4) |i| {
const start = i * 4;
const end = (i + 1) * 4;
if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds;
std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]);
}
return 4 * 4;
},
.Vector3f32 => |*vec| {
inline for (0..3) |i| {
const start = i * 4;
const end = (i + 1) * 4;
if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds;
std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]);
}
return 3 * 4;
},
.Vector2f32 => |*vec| {
inline for (0..2) |i| {
const start = i * 4;
const end = (i + 1) * 4;
if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds;
std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]);
}
return 2 * 4;
},
.Vector4i32 => |*vec| {
inline for (0..4) |i| {
const start = i * 4;
const end = (i + 1) * 4;
if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds;
std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]);
}
return 4 * 4;
},
.Vector3i32 => |*vec| {
inline for (0..3) |i| {
const start = i * 4;
const end = (i + 1) * 4;
if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds;
std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]);
}
return 3 * 4;
},
.Vector2i32 => |*vec| {
inline for (0..2) |i| {
const start = i * 4;
const end = (i + 1) * 4;
if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds;
std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]);
}
return 2 * 4;
},
.Vector4u32 => |*vec| {
inline for (0..4) |i| {
const start = i * 4;
const end = (i + 1) * 4;
if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds;
std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]);
}
return 4 * 4;
},
.Vector3u32 => |*vec| {
inline for (0..3) |i| {
const start = i * 4;
const end = (i + 1) * 4;
if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds;
std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]);
}
return 3 * 4;
},
.Vector2u32 => |*vec| {
inline for (0..2) |i| {
const start = i * 4;
const end = (i + 1) * 4;
if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds;
std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]);
}
return 2 * 4;
},
.Vector,
.Matrix,
.Array,
.Structure,
=> |*values| {
var offset: usize = 0;
for (values.*) |*v| {
offset += try v.write(input[offset..]);
}
return offset;
},
.RuntimeArray => |*arr| arr.data = input[0..],
else => return RuntimeError.InvalidValueType,
}
return 0;
}
pub fn flushPtr(self: *Value, allocator: std.mem.Allocator) RuntimeError!void {
switch (self.*) {
.Pointer => |*p| {
if (p.runtime_array_window) |window| {
switch (p.ptr) {
.common => |ptr| {
_ = try ptr.read(window);
ptr.deinit(allocator);
allocator.destroy(ptr);
},
else => {},
}
}
p.runtime_array_window = null;
},
else => {},
}
}
fn deinit(self: *Value, allocator: std.mem.Allocator) void {
switch (self.*) {
.Vector, .Matrix, .Array, .Structure => |values| {
for (values) |*value| value.deinit(allocator);
allocator.free(values);
},
else => {},
}
}
};
pub const TypeData = union(Type) {
Void: struct {},
Bool: struct {},
Int: struct {
bit_length: SpvWord,
is_signed: bool,
},
Float: struct {
bit_length: SpvWord,
},
Vector: struct {
components_type_word: SpvWord,
components_type: Type,
member_count: SpvWord,
},
Vector4f32: struct {},
Vector3f32: struct {},
Vector2f32: struct {},
Vector4i32: struct {},
Vector3i32: struct {},
Vector2i32: struct {},
Vector4u32: struct {},
Vector3u32: struct {},
Vector2u32: struct {},
Matrix: struct {
column_type_word: SpvWord,
column_type: Type,
member_count: SpvWord,
},
Array: struct {
components_type_word: SpvWord,
components_type: Type,
member_count: SpvWord,
},
RuntimeArray: struct {
components_type_word: SpvWord,
components_type: Type,
},
Structure: struct {
members_type_word: []const SpvWord,
member_names: std.ArrayList([]const u8),
},
Function: struct {
source_location: usize,
return_type: SpvWord,
params: []const SpvWord,
},
Image: struct {},
Sampler: struct {},
SampledImage: struct {},
Pointer: struct {
storage_class: spv.SpvStorageClass,
target: SpvWord,
},
pub fn getSize(self: *const TypeData, results: []const Self) usize {
return switch (self.*) {
.Bool => 1,
.Int => |i| @divExact(i.bit_length, 8),
.Float => |f| @divExact(f.bit_length, 8),
.Vector => |v| results[v.components_type_word].variant.?.Type.getSize(results),
.Array => |a| results[a.components_type_word].variant.?.Type.getSize(results),
.Matrix => |m| results[m.column_type_word].variant.?.Type.getSize(results),
.RuntimeArray => |a| results[a.components_type_word].variant.?.Type.getSize(results),
.Structure => |s| blk: {
var total: usize = 0;
for (s.members_type_word) |type_word| {
total += results[type_word].variant.?.Type.getSize(results);
}
break :blk total;
},
.Vector4f32, .Vector4i32, .Vector4u32 => 4 * 4,
.Vector3f32, .Vector3i32, .Vector3u32 => 3 * 4,
.Vector2f32, .Vector2i32, .Vector2u32 => 2 * 4,
else => 0,
};
}
};
pub const VariantData = union(Variant) {
String: []const u8,
Extension: struct {
/// Should not be allocated but rather a pointer to a static array
dispatcher: []?op.OpCodeExtFunc,
},
Type: TypeData,
Variable: struct {
storage_class: spv.SpvStorageClass,
type_word: SpvWord,
type: Type,
value: Value,
},
Constant: struct {
type_word: SpvWord,
type: Type,
value: Value,
},
Function: struct {
source_location: usize,
return_type: SpvWord,
function_type: SpvWord,
params: []SpvWord,
},
AccessChain: struct {
target: SpvWord,
value: Value,
},
FunctionParameter: struct {
type_word: SpvWord,
type: Type,
value_ptr: ?*Value,
},
Label: struct {
source_location: usize,
},
};
const Self = @This();
name: ?[]const u8,
decorations: std.ArrayList(Decoration),
variant: ?VariantData,
pub fn init() Self {
return .{
.name = null,
.decorations = .empty,
.variant = null,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
if (self.name) |name| {
allocator.free(name);
}
if (self.variant) |*variant| {
switch (variant.*) {
.Type => |*t| switch (t.*) {
.Function => |data| allocator.free(data.params),
.Structure => |*data| {
allocator.free(data.members_type_word);
for (data.member_names.items) |name| {
allocator.free(name);
}
data.member_names.deinit(allocator);
},
else => {},
},
.Constant => |*c| c.value.deinit(allocator),
.Variable => |*v| v.value.deinit(allocator),
.AccessChain => |*a| a.value.deinit(allocator),
.Function => |f| allocator.free(f.params),
else => {},
}
}
self.decorations.deinit(allocator);
}
pub inline fn getValueTypeWord(self: *Self) RuntimeError!SpvWord {
return switch ((try self.getVariant()).*) {
.Variable => |v| v.type_word,
.Constant => |c| c.type_word,
.AccessChain => |a| a.target,
.FunctionParameter => |p| p.type_word,
else => RuntimeError.InvalidSpirV,
};
}
pub inline fn getValueType(self: *Self) RuntimeError!Type {
return switch ((try self.getVariant()).*) {
.Variable => |v| v.type,
.Constant => |c| c.type,
.FunctionParameter => |p| p.type,
else => RuntimeError.InvalidSpirV,
};
}
pub inline fn getValue(self: *Self) RuntimeError!*Value {
return switch ((try self.getVariant()).*) {
.Variable => |*v| &v.value,
.Constant => |*c| &c.value,
.AccessChain => |*a| &a.value,
.FunctionParameter => |*p| p.value_ptr orelse return RuntimeError.InvalidSpirV,
else => RuntimeError.InvalidSpirV,
};
}
pub inline fn getConstValue(self: *Self) RuntimeError!*const Value {
return switch ((try self.getVariant()).*) {
.Variable => |v| &v.value,
.Constant => |c| &c.value,
.AccessChain => |a| &a.value,
.FunctionParameter => |p| p.value_ptr orelse return RuntimeError.InvalidSpirV,
else => RuntimeError.InvalidSpirV,
};
}
pub inline fn getVariant(self: *Self) RuntimeError!*VariantData {
return &(self.variant orelse return RuntimeError.InvalidSpirV);
}
pub inline fn getConstVariant(self: *const Self) RuntimeError!*const VariantData {
return &(self.variant orelse return RuntimeError.InvalidSpirV);
}
/// 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,
.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,
.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 => break :blk .{ .Type = t },
},
.Variable => |v| break :blk .{
.Variable = .{
.storage_class = v.storage_class,
.type_word = v.type_word,
.type = v.type,
.value = try v.value.dupe(allocator),
},
},
.Constant => |c| break :blk .{
.Constant = .{
.type_word = c.type_word,
.type = c.type,
.value = try c.value.dupe(allocator),
},
},
.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 resolveLaneBitWidth(target_type: TypeData, rt: *const Runtime) RuntimeError!SpvWord {
return sw: switch (target_type) {
.Bool => 8,
.Float => |f| f.bit_length,
.Int => |i| i.bit_length,
.Vector => |v| continue :sw (try rt.results[v.components_type_word].getVariant()).Type,
.Vector4f32,
.Vector3f32,
.Vector2f32,
.Vector4i32,
.Vector3i32,
.Vector2i32,
.Vector4u32,
.Vector3u32,
.Vector2u32,
=> return 32,
else => return RuntimeError.InvalidSpirV,
};
}
pub fn resolveSign(target_type: TypeData, rt: *const Runtime) RuntimeError!enum { signed, unsigned } {
return sw: switch (target_type) {
.Int => |i| if (i.is_signed) .signed else .unsigned,
.Vector => |v| continue :sw (try rt.results[v.components_type_word].getVariant()).Type,
.Vector4i32 => .signed,
.Vector3i32 => .signed,
.Vector2i32 => .signed,
.Vector4u32 => .unsigned,
.Vector3u32 => .unsigned,
.Vector2u32 => .unsigned,
else => .unsigned,
};
}
pub inline fn resolveType(self: *const Self, results: []const Self) *const Self {
return if (self.resolveTypeWordOrNull()) |word| &results[word] else self;
}
pub fn resolveTypeWordOrNull(self: *const Self) ?SpvWord {
return if (self.variant) |variant|
switch (variant) {
.Type => |t| switch (t) {
.Pointer => |ptr| ptr.target,
else => null,
},
else => null,
}
else
null;
}
pub fn getMemberCounts(self: *const Self) usize {
if (self.variant) |variant| {
switch (variant) {
.Type => |t| switch (t) {
.Bool, .Int, .Float, .Image, .Sampler => return 1,
.Vector => |v| return v.member_count,
.Vector4f32, .Vector4i32, .Vector4u32 => return 4,
.Vector3f32, .Vector3i32, .Vector3u32 => return 3,
.Vector2f32, .Vector2i32, .Vector2u32 => return 2,
.Matrix => |m| return m.member_count,
.Array => |a| return a.member_count,
.SampledImage => return 2,
.Structure => |s| return s.members_type_word.len,
.Function => |f| return f.params.len,
else => {},
},
else => {},
}
}
return 0;
}
pub fn initValue(allocator: std.mem.Allocator, member_count: usize, results: []const Self, resolved: *const Self) RuntimeError!Value {
return switch (resolved.variant.?) {
.Type => |t| switch (t) {
.Void => .{ .Void = .{} },
.Bool => .{ .Bool = false },
.Int => |i| .{ .Int = .{
.bit_count = i.bit_length,
.value = .{ .uint64 = 0 },
} },
.Float => |f| .{ .Float = .{
.bit_count = f.bit_length,
.value = .{ .float64 = 0 },
} },
.Vector => |v| blk: {
const value: Value = .{ .Vector = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory };
errdefer allocator.free(value.Vector);
for (value.Vector) |*val| {
val.* = try Value.init(allocator, results, v.components_type_word);
}
break :blk value;
},
.Vector4f32 => .{ .Vector4f32 = Vec4f32{ 0.0, 0.0, 0.0, 0.0 } },
.Vector3f32 => .{ .Vector3f32 = Vec3f32{ 0.0, 0.0, 0.0 } },
.Vector2f32 => .{ .Vector2f32 = Vec2f32{ 0.0, 0.0 } },
.Vector4i32 => .{ .Vector4i32 = Vec4i32{ 0, 0, 0, 0 } },
.Vector3i32 => .{ .Vector3i32 = Vec3i32{ 0, 0, 0 } },
.Vector2i32 => .{ .Vector2i32 = Vec2i32{ 0, 0 } },
.Vector4u32 => .{ .Vector4u32 = Vec4u32{ 0, 0, 0, 0 } },
.Vector3u32 => .{ .Vector3u32 = Vec3u32{ 0, 0, 0 } },
.Vector2u32 => .{ .Vector2u32 = Vec2u32{ 0, 0 } },
.Matrix => |m| blk: {
const value: Value = .{ .Matrix = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory };
errdefer allocator.free(value.Matrix);
for (value.Matrix) |*v| {
v.* = try Value.init(allocator, results, m.column_type_word);
}
break :blk value;
},
.Array => |a| blk: {
const value: Value = .{ .Array = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory };
errdefer allocator.free(value.Array);
for (value.Array) |*val| {
val.* = try Value.init(allocator, results, a.components_type_word);
}
break :blk value;
},
.RuntimeArray => |a| .{
.RuntimeArray = .{
.type_word = a.components_type_word,
.data = &.{},
},
},
.Structure => |s| blk: {
const value: Value = .{ .Structure = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory };
errdefer allocator.free(value.Structure);
for (value.Structure, s.members_type_word) |*v, member_type_word| {
v.* = try Value.init(allocator, results, member_type_word);
}
break :blk value;
},
.Image => RuntimeError.ToDo,
.Sampler => RuntimeError.ToDo,
.SampledImage => RuntimeError.ToDo,
else => RuntimeError.InvalidSpirV,
},
else => RuntimeError.InvalidSpirV,
};
}
pub fn flushPtr(self: *Self, allocator: std.mem.Allocator) RuntimeError!void {
if (self.variant) |*variant| {
switch (variant.*) {
.Constant => |*c| try c.value.flushPtr(allocator),
.Variable => |*v| try v.value.flushPtr(allocator),
.AccessChain => |*a| try a.value.flushPtr(allocator),
else => {},
}
}
}