adding bitsize to primitive values
All checks were successful
Build / build (push) Successful in 1m43s
Test / build (push) Successful in 4m37s

This commit is contained in:
2026-02-15 02:06:15 +01:00
parent ac4f41ddd4
commit 2ea707ea57
5 changed files with 320 additions and 208 deletions

View File

@@ -31,12 +31,12 @@ pub fn main() !void {
var input: Input = .{}; var input: Input = .{};
var output: Output = .{}; var output: Output = .{};
try rt.writeDescriptorSet(Input, allocator, &input, 0, 0); try rt.writeDescriptorSet(allocator, std.mem.asBytes(&input), 0, 0);
try rt.writeDescriptorSet(Output, allocator, &output, 0, 1); try rt.writeDescriptorSet(allocator, std.mem.asBytes(&output), 0, 1);
try rt.callEntryPoint(allocator, entry); try rt.callEntryPoint(allocator, entry);
try rt.readDescriptorSet(Output, allocator, &output, 0, 1); try rt.readDescriptorSet(std.mem.asBytes(&output), 0, 1);
std.log.info("Output: {any}", .{output}); std.log.info("Output: {any}", .{output});

View File

@@ -80,7 +80,9 @@ const Decoration = struct {
pub const Value = union(Type) { pub const Value = union(Type) {
Void: struct {}, Void: struct {},
Bool: bool, Bool: bool,
Int: extern union { Int: struct {
bit_count: usize,
value: extern union {
sint8: i8, sint8: i8,
sint16: i16, sint16: i16,
sint32: i32, sint32: i32,
@@ -90,11 +92,15 @@ pub const Value = union(Type) {
uint32: u32, uint32: u32,
uint64: u64, uint64: u64,
}, },
Float: extern union { },
Float: struct {
bit_count: usize,
value: extern union {
float16: f16, float16: f16,
float32: f32, float32: f32,
float64: f64, float64: f64,
}, },
},
Vector: []Value, Vector: []Value,
Vector4f32: Vec4f32, Vector4f32: Vec4f32,
Vector3f32: Vec3f32, Vector3f32: Vec3f32,
@@ -116,7 +122,7 @@ pub const Value = union(Type) {
Pointer: union(enum) { Pointer: union(enum) {
common: *Value, common: *Value,
f32_ptr: *f32, f32_ptr: *f32,
i32_ptr: *i32, //< For vectors specializations i32_ptr: *i32, //< For vector specializations
u32_ptr: *u32, u32_ptr: *u32,
}, },
@@ -135,8 +141,14 @@ pub const Value = union(Type) {
return switch (resolved.variant.?) { return switch (resolved.variant.?) {
.Type => |t| switch (t) { .Type => |t| switch (t) {
.Bool => .{ .Bool = false }, .Bool => .{ .Bool = false },
.Int => .{ .Int = .{ .uint64 = 0 } }, .Int => |i| .{ .Int = .{
.Float => .{ .Float = .{ .float64 = 0.0 } }, .bit_count = i.bit_length,
.value = .{ .uint64 = 0 },
} },
.Float => |f| .{ .Float = .{
.bit_count = f.bit_length,
.value = .{ .float64 = 0 },
} },
.Vector => |v| blk: { .Vector => |v| blk: {
var self: Value = .{ .Vector = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory }; var self: Value = .{ .Vector = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory };
errdefer self.deinit(allocator); errdefer self.deinit(allocator);
@@ -529,7 +541,7 @@ pub fn resolveSign(target_type: TypeData, rt: *const Runtime) RuntimeError!enum
.Vector4u32 => .unsigned, .Vector4u32 => .unsigned,
.Vector3u32 => .unsigned, .Vector3u32 => .unsigned,
.Vector2u32 => .unsigned, .Vector2u32 => .unsigned,
else => .unsinged, else => .unsigned,
}; };
} }
@@ -573,8 +585,14 @@ pub fn initValue(allocator: std.mem.Allocator, member_count: usize, results: []c
.Type => |t| switch (t) { .Type => |t| switch (t) {
.Void => .{ .Void = .{} }, .Void => .{ .Void = .{} },
.Bool => .{ .Bool = false }, .Bool => .{ .Bool = false },
.Int => .{ .Int = .{ .uint64 = 0 } }, .Int => |i| .{ .Int = .{
.Float => .{ .Float = .{ .float64 = 0.0 } }, .bit_count = i.bit_length,
.value = .{ .uint64 = 0 },
} },
.Float => |f| .{ .Float = .{
.bit_count = f.bit_length,
.value = .{ .float64 = 0 },
} },
.Vector => |v| blk: { .Vector => |v| blk: {
const value: Value = .{ .Vector = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory }; const value: Value = .{ .Vector = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory };
errdefer allocator.free(value.Vector); errdefer allocator.free(value.Vector);
@@ -609,7 +627,6 @@ pub fn initValue(allocator: std.mem.Allocator, member_count: usize, results: []c
break :blk value; break :blk value;
}, },
.RuntimeArray => |a| blk: { .RuntimeArray => |a| blk: {
std.debug.print("test {d}\n", .{member_count});
if (member_count == 0) { if (member_count == 0) {
break :blk Value{ .RuntimeArray = null }; break :blk Value{ .RuntimeArray = null };
} }

View File

@@ -150,43 +150,58 @@ pub fn callEntryPoint(self: *Self, allocator: std.mem.Allocator, entry_point_ind
//}) catch return RuntimeError.OutOfMemory; //}) catch return RuntimeError.OutOfMemory;
} }
pub fn readDescriptorSet(self: *const Self, comptime T: type, output: *T, set: SpvWord, binding: SpvWord) RuntimeError!void { pub fn readDescriptorSet(self: *const Self, output: []u8, set: SpvWord, binding: SpvWord) RuntimeError!void {
if (set < lib.SPIRV_MAX_SET and binding < lib.SPIRV_MAX_SET_BINDINGS) { if (set < lib.SPIRV_MAX_SET and binding < lib.SPIRV_MAX_SET_BINDINGS) {
try self.readValue(T, output, &self.results[self.mod.bindings[set][binding]].variant.?.Variable.value); _ = try self.readValue(output, &self.results[self.mod.bindings[set][binding]].variant.?.Variable.value);
} else { } else {
return RuntimeError.NotFound; return RuntimeError.NotFound;
} }
} }
pub fn writeDescriptorSet(self: *const Self, comptime T: type, allocator: std.mem.Allocator, input: *const T, set: SpvWord, binding: SpvWord) RuntimeError!void { pub fn writeDescriptorSet(self: *const Self, allocator: std.mem.Allocator, input: []const u8, set: SpvWord, binding: SpvWord) RuntimeError!void {
if (set < lib.SPIRV_MAX_SET and binding < lib.SPIRV_MAX_SET_BINDINGS) { if (set < lib.SPIRV_MAX_SET and binding < lib.SPIRV_MAX_SET_BINDINGS) {
const variable = &self.results[self.mod.bindings[set][binding]].variant.?.Variable; const variable = &self.results[self.mod.bindings[set][binding]].variant.?.Variable;
switch (variable.value) {
const helper = struct {
fn init(allocator2: std.mem.Allocator, len: usize, value: *Result.Value, type_word: SpvWord, results: []Result) RuntimeError!void {
const resolved = results[type_word].resolveType(results);
switch (value.*) {
.RuntimeArray => { .RuntimeArray => {
const resolved = self.results[variable.type_word].resolveType(self.results); value.* = try Result.initValue(allocator2, len, results, resolved);
variable.value = try Result.initValue(allocator, input.len, self.results, resolved);
}, },
.Vector, .Matrix, .Array, .Structure => |v| { .Structure => |*s| for (s.*, 0..) |*elem, i| {
_ = v; try @This().init(allocator2, len, elem, resolved.variant.?.Type.Structure.members_type_word[i], results);
}, },
else => {},
} }
try self.writeValue(T, input, &variable.value); }
};
try helper.init(allocator, input.len, &variable.value, variable.type_word, self.results);
@import("pretty").print(allocator, variable, .{
.tab_size = 4,
.max_depth = 0,
.struct_max_len = 0,
.array_max_len = 0,
}) catch return RuntimeError.OutOfMemory;
_ = try self.writeValue(input, &variable.value);
} else { } else {
return RuntimeError.NotFound; return RuntimeError.NotFound;
} }
} }
pub fn readOutput(self: *const Self, comptime T: type, output: []T, result: SpvWord) RuntimeError!void { pub fn readOutput(self: *const Self, output: []u8, result: SpvWord) RuntimeError!void {
if (std.mem.indexOf(SpvWord, &self.mod.output_locations, &.{result})) |_| { if (std.mem.indexOf(SpvWord, &self.mod.output_locations, &.{result})) |_| {
try self.readValue(T, output, &self.results[result].variant.?.Variable.value); _ = try self.readValue(output, &self.results[result].variant.?.Variable.value);
} else { } else {
return RuntimeError.NotFound; return RuntimeError.NotFound;
} }
} }
pub fn writeInput(self: *const Self, comptime T: type, input: []const T, result: SpvWord) RuntimeError!void { pub fn writeInput(self: *const Self, input: []const u8, result: SpvWord) RuntimeError!void {
if (std.mem.indexOf(SpvWord, &self.mod.input_locations, &.{result})) |_| { if (std.mem.indexOf(SpvWord, &self.mod.input_locations, &.{result})) |_| {
try self.writeValue(T, input, &self.results[result].variant.?.Variable.value); _ = try self.writeValue(input, &self.results[result].variant.?.Variable.value);
} else { } else {
return RuntimeError.NotFound; return RuntimeError.NotFound;
} }
@@ -197,144 +212,224 @@ fn reset(self: *Self) void {
self.current_function = null; self.current_function = null;
} }
fn readValue(self: *const Self, comptime T: type, output: []T, value: *const Result.Value) RuntimeError!void { fn readValue(self: *const Self, output: []u8, value: *const Result.Value) RuntimeError!usize {
switch (value.*) { switch (value.*) {
.Bool => |b| { .Bool => |b| {
if (T == bool) { output[0] = if (b == true) 1 else 0;
output[0] = b; return 1;
} else {
return RuntimeError.InvalidValueType;
}
}, },
.Int => |i| { .Int => |i| {
switch (T) { switch (i.bit_count) {
i8 => output[0] = i.sint8, 8 => output[0] = @bitCast(i.value.uint8),
i16 => output[0] = i.sint16, 16 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&i.value.uint16)),
i32 => output[0] = i.sint32, 32 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&i.value.uint32)),
i64 => output[0] = i.sint64, 64 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&i.value.uint64)),
u8 => output[0] = i.uint8, else => return RuntimeError.InvalidValueType,
u16 => output[0] = i.uint16,
u32 => output[0] = i.uint32,
u64 => output[0] = i.uint64,
inline else => return RuntimeError.InvalidValueType,
} }
return @divExact(i.bit_count, 8);
}, },
.Float => |f| { .Float => |f| {
switch (T) { switch (f.bit_count) {
f16 => output[0] = f.float16, 16 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&f.value.float16)),
f32 => output[0] = f.float32, 32 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&f.value.float32)),
f64 => output[0] = f.float64, 64 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&f.value.float64)),
inline else => return RuntimeError.InvalidValueType,
}
},
.Vector4f32 => |vec| inline for (0..4) |i| switch (T) {
f32 => output[i] = vec[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector3f32 => |vec| inline for (0..3) |i| switch (T) {
f32 => output[i] = vec[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector2f32 => |vec| inline for (0..2) |i| switch (T) {
f32 => output[i] = vec[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector4i32 => |vec| inline for (0..4) |i| switch (T) {
i32 => output[i] = vec[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector3i32 => |vec| inline for (0..3) |i| switch (T) {
i32 => output[i] = vec[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector2i32 => |vec| inline for (0..2) |i| switch (T) {
i32 => output[i] = vec[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector4u32 => |vec| inline for (0..4) |i| switch (T) {
u32 => output[i] = vec[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector3u32 => |vec| inline for (0..3) |i| switch (T) {
u32 => output[i] = vec[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector2u32 => |vec| inline for (0..2) |i| switch (T) {
u32 => output[i] = vec[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector, .Matrix, .Array, .Structure => |values| for (values, 0..) |v, i| try self.readValue(T, output[i..], &v),
else => return RuntimeError.InvalidValueType, 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 self.readValue(output[offset..], &v);
}
return offset;
},
.RuntimeArray => |opt_values| if (opt_values) |values| {
var offset: usize = 0;
for (values) |v| {
offset += try self.readValue(output[offset..], &v);
}
return offset;
},
else => return RuntimeError.InvalidValueType,
}
return 0;
} }
fn writeValue(self: *const Self, comptime T: type, input: []const T, value: *Result.Value) RuntimeError!void { fn writeValue(self: *const Self, input: []const u8, value: *Result.Value) RuntimeError!usize {
switch (value.*) { switch (value.*) {
.Bool => |*b| { .Bool => |*b| {
if (T == bool) { b.* = if (input[0] != 0) true else false;
b.* = input[0]; return 1;
} else {
return RuntimeError.InvalidValueType;
}
}, },
.Int => |*i| { .Int => |*i| {
switch (T) { switch (i.bit_count) {
i8 => i.sint8 = input[0], 8 => i.value.uint8 = @bitCast(input[0]),
i16 => i.sint16 = input[0], 16 => std.mem.copyForwards(u8, std.mem.asBytes(&i.value.uint16), input[0..2]),
i32 => i.sint32 = input[0], 32 => std.mem.copyForwards(u8, std.mem.asBytes(&i.value.uint32), input[0..4]),
i64 => i.sint64 = input[0], 64 => std.mem.copyForwards(u8, std.mem.asBytes(&i.value.uint64), input[0..8]),
u8 => i.uint8 = input[0],
u16 => i.uint16 = input[0],
u32 => i.uint32 = input[0],
u64 => i.uint64 = input[0],
inline else => return RuntimeError.InvalidValueType,
}
},
.Float => |*f| {
switch (T) {
f16 => f.float16 = input[0],
f32 => f.float32 = input[0],
f64 => f.float64 = input[0],
inline else => return RuntimeError.InvalidValueType,
}
},
.Vector4f32 => |*vec| inline for (0..4) |i| switch (T) {
f32 => vec[i] = input[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector3f32 => |*vec| inline for (0..3) |i| switch (T) {
f32 => vec[i] = input[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector2f32 => |*vec| inline for (0..2) |i| switch (T) {
f32 => vec[i] = input[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector4i32 => |*vec| inline for (0..4) |i| switch (T) {
i32 => vec[i] = input[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector3i32 => |*vec| inline for (0..3) |i| switch (T) {
i32 => vec[i] = input[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector2i32 => |*vec| inline for (0..2) |i| switch (T) {
i32 => vec[i] = input[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector4u32 => |*vec| inline for (0..4) |i| switch (T) {
u32 => vec[i] = input[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector3u32 => |*vec| inline for (0..3) |i| switch (T) {
u32 => vec[i] = input[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector2u32 => |*vec| inline for (0..2) |i| switch (T) {
u32 => vec[i] = input[i],
inline else => return RuntimeError.InvalidValueType,
},
.Vector, .Matrix, .Array, .Structure => |*values| for (values.*, 0..) |*v, i| try self.writeValue(T, input[i..], v),
else => return RuntimeError.InvalidValueType, 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;
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;
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;
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;
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;
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;
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;
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;
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;
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 self.writeValue(input[offset..], v);
}
return offset;
},
.RuntimeArray => |opt_values| if (opt_values) |*values| {
var offset: usize = 0;
for (values.*) |*v| {
offset += try self.writeValue(input[offset..], v);
}
return offset;
},
else => return RuntimeError.InvalidValueType,
}
return 0;
} }

View File

@@ -316,17 +316,17 @@ fn BitOperator(comptime T: ValueType, comptime Op: BitOp) type {
.BitFieldInsert => blk: { .BitFieldInsert => blk: {
const offset = try rt.results[try rt.it.next()].getValue(); const offset = try rt.results[try rt.it.next()].getValue();
const count = try rt.results[try rt.it.next()].getValue(); const count = try rt.results[try rt.it.next()].getValue();
break :blk bitInsert(TT, op1, op2, offset.Int.uint64, count.Int.uint64); break :blk bitInsert(TT, op1, op2, offset.Int.value.uint64, count.Int.value.uint64);
}, },
.BitFieldSExtract => blk: { .BitFieldSExtract => blk: {
if (T == .UInt) return RuntimeError.InvalidSpirV; if (T == .UInt) return RuntimeError.InvalidSpirV;
const count = try rt.results[try rt.it.next()].getValue(); const count = try rt.results[try rt.it.next()].getValue();
break :blk bitExtract(TT, op1, op2, count.Int.uint64); break :blk bitExtract(TT, op1, op2, count.Int.value.uint64);
}, },
.BitFieldUExtract => blk: { .BitFieldUExtract => blk: {
if (T == .SInt) return RuntimeError.InvalidSpirV; if (T == .SInt) return RuntimeError.InvalidSpirV;
const count = try rt.results[try rt.it.next()].getValue(); const count = try rt.results[try rt.it.next()].getValue();
break :blk bitExtract(TT, op1, op2, count.Int.uint64); break :blk bitExtract(TT, op1, op2, count.Int.value.uint64);
}, },
.BitwiseAnd => op1 & op2, .BitwiseAnd => op1 & op2,
@@ -728,7 +728,7 @@ fn MathEngine(comptime T: ValueType, comptime Op: MathOp) type {
inline fn applyVectorTimesScalarF32(d: []Result.Value, l: []const Result.Value, r: f32) void { inline fn applyVectorTimesScalarF32(d: []Result.Value, l: []const Result.Value, r: f32) void {
for (d, l) |*d_v, l_v| { for (d, l) |*d_v, l_v| {
d_v.Float.float32 = l_v.Float.float32 * r; d_v.Float.value.float32 = l_v.Float.value.float32 * r;
} }
} }
@@ -746,7 +746,7 @@ fn MathEngine(comptime T: ValueType, comptime Op: MathOp) type {
inline fn applySIMDVectorf32(comptime N: usize, d: *@Vector(N, f32), l: *const @Vector(N, f32), r: *const Result.Value) RuntimeError!void { inline fn applySIMDVectorf32(comptime N: usize, d: *@Vector(N, f32), l: *const @Vector(N, f32), r: *const Result.Value) RuntimeError!void {
switch (Op) { switch (Op) {
.VectorTimesScalar => applyVectorSIMDTimesScalarF32(N, d, l, r.Float.float32), .VectorTimesScalar => applyVectorSIMDTimesScalarF32(N, d, l, r.Float.value.float32),
else => { else => {
const rh: *const @Vector(N, f32) = switch (N) { const rh: *const @Vector(N, f32) = switch (N) {
2 => &r.Vector2f32, 2 => &r.Vector2f32,
@@ -764,7 +764,7 @@ fn MathEngine(comptime T: ValueType, comptime Op: MathOp) type {
.Int, .Float => try operator.applyScalar(lane_bits, dst, lhs, rhs), .Int, .Float => try operator.applyScalar(lane_bits, dst, lhs, rhs),
.Vector => |dst_vec| switch (Op) { .Vector => |dst_vec| switch (Op) {
.VectorTimesScalar => operator.applyVectorTimesScalarF32(dst_vec, lhs.Vector, rhs.Float.float32), .VectorTimesScalar => operator.applyVectorTimesScalarF32(dst_vec, lhs.Vector, rhs.Float.value.float32),
else => for (dst_vec, lhs.Vector, rhs.Vector) |*d_lane, *l_lane, *r_lane| { else => for (dst_vec, lhs.Vector, rhs.Vector) |*d_lane, *l_lane, *r_lane| {
try operator.applyScalar(lane_bits, d_lane, l_lane, r_lane); try operator.applyScalar(lane_bits, d_lane, l_lane, r_lane);
}, },
@@ -845,14 +845,14 @@ fn opBitcast(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
/// Asumes that values passed are primitives ints or floats /// Asumes that values passed are primitives ints or floats
fn cast(to: *Result.Value, from: *const Result.Value) RuntimeError!void { fn cast(to: *Result.Value, from: *const Result.Value) RuntimeError!void {
const from_bytes: u64 = switch (from.*) { const from_bytes: u64 = switch (from.*) {
.Float => |f| @bitCast(f.float64), .Float => |f| @bitCast(f.value.float64),
.Int => |i| i.uint64, .Int => |i| i.value.uint64,
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}; };
switch (to.*) { switch (to.*) {
.Float => |*f| f.float64 = @bitCast(from_bytes), .Float => |*f| f.value.float64 = @bitCast(from_bytes),
.Int => |*i| i.uint64 = from_bytes, .Int => |*i| i.value.uint64 = from_bytes,
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
} }
} }
@@ -887,12 +887,12 @@ fn copyValue(dst: *Result.Value, src: *const Result.Value) void {
.Pointer => |src_ptr| switch (src_ptr) { .Pointer => |src_ptr| switch (src_ptr) {
.f32_ptr => |src_f32_ptr| dst_f32_ptr.* = src_f32_ptr.*, .f32_ptr => |src_f32_ptr| dst_f32_ptr.* = src_f32_ptr.*,
.common => |src_val_ptr| switch (src_val_ptr.*) { .common => |src_val_ptr| switch (src_val_ptr.*) {
.Float => |f| dst_f32_ptr.* = f.float32, .Float => |f| dst_f32_ptr.* = f.value.float32,
else => unreachable, else => unreachable,
}, },
else => unreachable, else => unreachable,
}, },
.Float => |f| dst_f32_ptr.* = f.float32, .Float => |f| dst_f32_ptr.* = f.value.float32,
else => unreachable, else => unreachable,
} }
} }
@@ -902,12 +902,12 @@ fn copyValue(dst: *Result.Value, src: *const Result.Value) void {
.Pointer => |src_ptr| switch (src_ptr) { .Pointer => |src_ptr| switch (src_ptr) {
.i32_ptr => |src_i32_ptr| dst_i32_ptr.* = src_i32_ptr.*, .i32_ptr => |src_i32_ptr| dst_i32_ptr.* = src_i32_ptr.*,
.common => |src_val_ptr| switch (src_val_ptr.*) { .common => |src_val_ptr| switch (src_val_ptr.*) {
.Int => |i| dst_i32_ptr.* = i.sint32, .Int => |i| dst_i32_ptr.* = i.value.sint32,
else => unreachable, else => unreachable,
}, },
else => unreachable, else => unreachable,
}, },
.Int => |i| dst_i32_ptr.* = i.sint32, .Int => |i| dst_i32_ptr.* = i.value.sint32,
else => unreachable, else => unreachable,
} }
} }
@@ -917,12 +917,12 @@ fn copyValue(dst: *Result.Value, src: *const Result.Value) void {
.Pointer => |src_ptr| switch (src_ptr) { .Pointer => |src_ptr| switch (src_ptr) {
.u32_ptr => |src_u32_ptr| dst_u32_ptr.* = src_u32_ptr.*, .u32_ptr => |src_u32_ptr| dst_u32_ptr.* = src_u32_ptr.*,
.common => |src_val_ptr| switch (src_val_ptr.*) { .common => |src_val_ptr| switch (src_val_ptr.*) {
.Int => |i| dst_u32_ptr.* = i.uint32, .Int => |i| dst_u32_ptr.* = i.value.uint32,
else => unreachable, else => unreachable,
}, },
else => unreachable, else => unreachable,
}, },
.Int => |i| dst_u32_ptr.* = i.uint32, .Int => |i| dst_u32_ptr.* = i.value.uint32,
else => unreachable, else => unreachable,
} }
} }
@@ -987,15 +987,15 @@ pub fn getValuePrimitiveField(comptime T: ValueType, comptime BitCount: SpvWord,
return switch (T) { return switch (T) {
.Bool => &v.Bool, .Bool => &v.Bool,
.Float => switch (BitCount) { .Float => switch (BitCount) {
inline 16, 32, 64 => |i| &@field(v.Float, std.fmt.comptimePrint("float{}", .{i})), inline 16, 32, 64 => |i| &@field(v.Float.value, std.fmt.comptimePrint("float{}", .{i})),
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
.SInt => switch (BitCount) { .SInt => switch (BitCount) {
inline 8, 16, 32, 64 => |i| &@field(v.Int, std.fmt.comptimePrint("sint{}", .{i})), inline 8, 16, 32, 64 => |i| &@field(v.Int.value, std.fmt.comptimePrint("sint{}", .{i})),
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
.UInt => switch (BitCount) { .UInt => switch (BitCount) {
inline 8, 16, 32, 64 => |i| &@field(v.Int, std.fmt.comptimePrint("uint{}", .{i})), inline 8, 16, 32, 64 => |i| &@field(v.Int.value, std.fmt.comptimePrint("uint{}", .{i})),
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
}; };
@@ -1034,48 +1034,48 @@ fn opAccessChain(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) Runtim
.Int => |i| { .Int => |i| {
switch (value_ptr.*) { switch (value_ptr.*) {
.Vector, .Matrix, .Array, .Structure => |v| { .Vector, .Matrix, .Array, .Structure => |v| {
if (i.uint32 > v.len) return RuntimeError.InvalidSpirV; if (i.value.uint32 > v.len) return RuntimeError.InvalidSpirV;
value_ptr = &v[i.uint32]; value_ptr = &v[i.value.uint32];
}, },
.RuntimeArray => |opt_v| if (opt_v) |v| { .RuntimeArray => |opt_v| if (opt_v) |v| {
if (i.uint32 > v.len) return RuntimeError.InvalidSpirV; if (i.value.uint32 > v.len) return RuntimeError.InvalidSpirV;
value_ptr = &v[i.uint32]; value_ptr = &v[i.value.uint32];
} else return RuntimeError.InvalidSpirV, } else return RuntimeError.InvalidSpirV,
.Vector4f32 => |*v| { .Vector4f32 => |*v| {
if (i.uint32 > 4) return RuntimeError.InvalidSpirV; if (i.value.uint32 > 4) return RuntimeError.InvalidSpirV;
break :blk .{ .Pointer = .{ .f32_ptr = &v[i.uint32] } }; break :blk .{ .Pointer = .{ .f32_ptr = &v[i.value.uint32] } };
}, },
.Vector3f32 => |*v| { .Vector3f32 => |*v| {
if (i.uint32 > 3) return RuntimeError.InvalidSpirV; if (i.value.uint32 > 3) return RuntimeError.InvalidSpirV;
break :blk .{ .Pointer = .{ .f32_ptr = &v[i.uint32] } }; break :blk .{ .Pointer = .{ .f32_ptr = &v[i.value.uint32] } };
}, },
.Vector2f32 => |*v| { .Vector2f32 => |*v| {
if (i.uint32 > 2) return RuntimeError.InvalidSpirV; if (i.value.uint32 > 2) return RuntimeError.InvalidSpirV;
break :blk .{ .Pointer = .{ .f32_ptr = &v[i.uint32] } }; break :blk .{ .Pointer = .{ .f32_ptr = &v[i.value.uint32] } };
}, },
.Vector4i32 => |*v| { .Vector4i32 => |*v| {
if (i.uint32 > 4) return RuntimeError.InvalidSpirV; if (i.value.uint32 > 4) return RuntimeError.InvalidSpirV;
break :blk .{ .Pointer = .{ .i32_ptr = &v[i.uint32] } }; break :blk .{ .Pointer = .{ .i32_ptr = &v[i.value.uint32] } };
}, },
.Vector3i32 => |*v| { .Vector3i32 => |*v| {
if (i.uint32 > 3) return RuntimeError.InvalidSpirV; if (i.value.uint32 > 3) return RuntimeError.InvalidSpirV;
break :blk .{ .Pointer = .{ .i32_ptr = &v[i.uint32] } }; break :blk .{ .Pointer = .{ .i32_ptr = &v[i.value.uint32] } };
}, },
.Vector2i32 => |*v| { .Vector2i32 => |*v| {
if (i.uint32 > 2) return RuntimeError.InvalidSpirV; if (i.value.uint32 > 2) return RuntimeError.InvalidSpirV;
break :blk .{ .Pointer = .{ .i32_ptr = &v[i.uint32] } }; break :blk .{ .Pointer = .{ .i32_ptr = &v[i.value.uint32] } };
}, },
.Vector4u32 => |*v| { .Vector4u32 => |*v| {
if (i.uint32 > 4) return RuntimeError.InvalidSpirV; if (i.value.uint32 > 4) return RuntimeError.InvalidSpirV;
break :blk .{ .Pointer = .{ .u32_ptr = &v[i.uint32] } }; break :blk .{ .Pointer = .{ .u32_ptr = &v[i.value.uint32] } };
}, },
.Vector3u32 => |*v| { .Vector3u32 => |*v| {
if (i.uint32 > 3) return RuntimeError.InvalidSpirV; if (i.value.uint32 > 3) return RuntimeError.InvalidSpirV;
break :blk .{ .Pointer = .{ .u32_ptr = &v[i.uint32] } }; break :blk .{ .Pointer = .{ .u32_ptr = &v[i.value.uint32] } };
}, },
.Vector2u32 => |*v| { .Vector2u32 => |*v| {
if (i.uint32 > 2) return RuntimeError.InvalidSpirV; if (i.value.uint32 > 2) return RuntimeError.InvalidSpirV;
break :blk .{ .Pointer = .{ .u32_ptr = &v[i.uint32] } }; break :blk .{ .Pointer = .{ .u32_ptr = &v[i.value.uint32] } };
}, },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
} }
@@ -1134,31 +1134,31 @@ fn opCompositeConstruct(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime)
switch (value.*) { switch (value.*) {
.Vector4f32 => |*vec| inline for (0..4) |i| { .Vector4f32 => |*vec| inline for (0..4) |i| {
vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Float.float32; vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Float.value.float32;
}, },
.Vector3f32 => |*vec| inline for (0..3) |i| { .Vector3f32 => |*vec| inline for (0..3) |i| {
vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Float.float32; vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Float.value.float32;
}, },
.Vector2f32 => |*vec| inline for (0..2) |i| { .Vector2f32 => |*vec| inline for (0..2) |i| {
vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Float.float32; vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Float.value.float32;
}, },
.Vector4i32 => |*vec| inline for (0..4) |i| { .Vector4i32 => |*vec| inline for (0..4) |i| {
vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Int.sint32; vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Int.value.sint32;
}, },
.Vector3i32 => |*vec| inline for (0..3) |i| { .Vector3i32 => |*vec| inline for (0..3) |i| {
vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Int.sint32; vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Int.value.sint32;
}, },
.Vector2i32 => |*vec| inline for (0..2) |i| { .Vector2i32 => |*vec| inline for (0..2) |i| {
vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Int.sint32; vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Int.value.sint32;
}, },
.Vector4u32 => |*vec| inline for (0..4) |i| { .Vector4u32 => |*vec| inline for (0..4) |i| {
vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Int.uint32; vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Int.value.uint32;
}, },
.Vector3u32 => |*vec| inline for (0..3) |i| { .Vector3u32 => |*vec| inline for (0..3) |i| {
vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Int.uint32; vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Int.value.uint32;
}, },
.Vector2u32 => |*vec| inline for (0..2) |i| { .Vector2u32 => |*vec| inline for (0..2) |i| {
vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Int.uint32; vec[i] = (try rt.results[try rt.it.next()].getVariant()).Constant.value.Int.value.uint32;
}, },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
} }
@@ -1186,15 +1186,15 @@ fn opCompositeExtract(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Ru
continue; continue;
} }
switch (composite) { switch (composite) {
.Vector4f32 => |v| break :blk .{ .Float = .{ .float32 = v[member_id] } }, .Vector4f32 => |v| break :blk .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = v[member_id] } } },
.Vector3f32 => |v| break :blk .{ .Float = .{ .float32 = v[member_id] } }, .Vector3f32 => |v| break :blk .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = v[member_id] } } },
.Vector2f32 => |v| break :blk .{ .Float = .{ .float32 = v[member_id] } }, .Vector2f32 => |v| break :blk .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = v[member_id] } } },
.Vector4i32 => |v| break :blk .{ .Int = .{ .sint32 = v[member_id] } }, .Vector4i32 => |v| break :blk .{ .Int = .{ .bit_count = 32, .value = .{ .sint32 = v[member_id] } } },
.Vector3i32 => |v| break :blk .{ .Int = .{ .sint32 = v[member_id] } }, .Vector3i32 => |v| break :blk .{ .Int = .{ .bit_count = 32, .value = .{ .sint32 = v[member_id] } } },
.Vector2i32 => |v| break :blk .{ .Int = .{ .sint32 = v[member_id] } }, .Vector2i32 => |v| break :blk .{ .Int = .{ .bit_count = 32, .value = .{ .sint32 = v[member_id] } } },
.Vector4u32 => |v| break :blk .{ .Int = .{ .uint32 = v[member_id] } }, .Vector4u32 => |v| break :blk .{ .Int = .{ .bit_count = 32, .value = .{ .uint32 = v[member_id] } } },
.Vector3u32 => |v| break :blk .{ .Int = .{ .uint32 = v[member_id] } }, .Vector3u32 => |v| break :blk .{ .Int = .{ .bit_count = 32, .value = .{ .uint32 = v[member_id] } } },
.Vector2u32 => |v| break :blk .{ .Int = .{ .uint32 = v[member_id] } }, .Vector2u32 => |v| break :blk .{ .Int = .{ .bit_count = 32, .value = .{ .uint32 = v[member_id] } } },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
} }
} }
@@ -1212,18 +1212,18 @@ fn opConstant(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) R
if (word_count - 2 != 1) { if (word_count - 2 != 1) {
const low = @as(u64, try rt.it.next()); const low = @as(u64, try rt.it.next());
const high = @as(u64, try rt.it.next()); const high = @as(u64, try rt.it.next());
i.uint64 = (high << 32) | low; i.value.uint64 = (high << 32) | low;
} else { } else {
i.uint32 = try rt.it.next(); i.value.uint32 = try rt.it.next();
} }
}, },
.Float => |*f| { .Float => |*f| {
if (word_count - 2 != 1) { if (word_count - 2 != 1) {
const low = @as(u64, try rt.it.next()); const low = @as(u64, try rt.it.next());
const high = @as(u64, try rt.it.next()); const high = @as(u64, try rt.it.next());
f.float64 = @bitCast((high << 32) | low); f.value.float64 = @bitCast((high << 32) | low);
} else { } else {
f.float32 = @bitCast(try rt.it.next()); f.value.float32 = @bitCast(try rt.it.next());
} }
}, },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
@@ -1260,7 +1260,7 @@ fn opDot(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}; };
value.Float.float64 = 0.0; value.Float.value.float64 = 0.0;
switch (op1_value.*) { switch (op1_value.*) {
.Vector => |vec| for (vec, op2_value.Vector) |*op1_v, *op2_v| { .Vector => |vec| for (vec, op2_value.Vector) |*op1_v, *op2_v| {
@@ -1271,14 +1271,14 @@ fn opDot(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
} }
}, },
.Vector4f32 => |vec| value.Float.float32 = zm.dot4(vec, op2_value.Vector4f32)[0], .Vector4f32 => |vec| value.Float.value.float32 = zm.dot4(vec, op2_value.Vector4f32)[0],
.Vector3f32 => |vec| { .Vector3f32 => |vec| {
const op2_vec = op2_value.Vector3f32; const op2_vec = op2_value.Vector3f32;
value.Float.float32 = zm.dot3(zm.f32x4(vec[0], vec[1], vec[2], 0.0), zm.f32x4(op2_vec[0], op2_vec[1], op2_vec[2], 0.0))[0]; value.Float.value.float32 = zm.dot3(zm.f32x4(vec[0], vec[1], vec[2], 0.0), zm.f32x4(op2_vec[0], op2_vec[1], op2_vec[2], 0.0))[0];
}, },
.Vector2f32 => |vec| { .Vector2f32 => |vec| {
const op2_vec = op2_value.Vector2f32; const op2_vec = op2_value.Vector2f32;
value.Float.float32 = zm.dot2(zm.f32x4(vec[0], vec[1], 0.0, 0.0), zm.f32x4(op2_vec[0], op2_vec[1], 0.0, 0.0))[0]; value.Float.value.float32 = zm.dot2(zm.f32x4(vec[0], vec[1], 0.0, 0.0), zm.f32x4(op2_vec[0], op2_vec[1], 0.0, 0.0))[0];
}, },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
} }

View File

@@ -41,7 +41,7 @@ pub const case = struct {
try rt.callEntryPoint(allocator, try rt.getEntryPointByName("main")); try rt.callEntryPoint(allocator, try rt.getEntryPointByName("main"));
var output: [len]T = undefined; var output: [len]T = undefined;
try rt.readOutput(T, output[0..len], try rt.getResultByName(output_name)); try rt.readOutput(std.mem.sliceAsBytes(output[0..]), try rt.getResultByName(output_name));
try std.testing.expectEqualSlices(T, expected, &output); try std.testing.expectEqualSlices(T, expected, &output);
} }
@@ -67,11 +67,11 @@ pub const case = struct {
var rt = try spv.Runtime.init(allocator, &module); var rt = try spv.Runtime.init(allocator, &module);
defer rt.deinit(allocator); defer rt.deinit(allocator);
try rt.writeInput(T, input[0..len], try rt.getResultByName(input_name)); try rt.writeInput(std.mem.sliceAsBytes(input[0..len]), try rt.getResultByName(input_name));
try rt.callEntryPoint(allocator, try rt.getEntryPointByName("main")); try rt.callEntryPoint(allocator, try rt.getEntryPointByName("main"));
var output: [len]T = undefined; var output: [len]T = undefined;
try rt.readOutput(T, output[0..len], try rt.getResultByName(output_name)); try rt.readOutput(std.mem.sliceAsBytes(output[0..]), try rt.getResultByName(output_name));
try std.testing.expectEqualSlices(T, expected, &output); try std.testing.expectEqualSlices(T, expected, &output);
} }