adding OpFMul
All checks were successful
Test / build (push) Successful in 46s
Build / build (push) Successful in 58s

This commit is contained in:
2026-01-12 16:59:53 +01:00
parent 8a79e8316d
commit 14e802709c
7 changed files with 90 additions and 37 deletions

View File

@@ -17,7 +17,7 @@ pub fn build(b: *std.Build) void {
.name = "spirv_interpreter", .name = "spirv_interpreter",
.root_module = mod, .root_module = mod,
.linkage = .dynamic, .linkage = .dynamic,
.use_llvm = true, //.use_llvm = true,
}); });
const lib_install = b.addInstallArtifact(lib, .{}); const lib_install = b.addInstallArtifact(lib, .{});

View File

@@ -9,7 +9,9 @@ struct FragOut
[entry(frag)] [entry(frag)]
fn main() -> FragOut fn main() -> FragOut
{ {
let ratio = vec4[f32](2.0, 2.0, 8.0, 0.25);
let output: FragOut; let output: FragOut;
output.color = vec4[f32](4.0, 3.0, 2.0, 1.0); output.color = vec4[f32](4.0, 3.0, 2.0, 1.0) * ratio;
return output; return output;
} }

Binary file not shown.

View File

@@ -1,7 +1,7 @@
; SPIR-V ; SPIR-V
; Version: 1.0 ; Version: 1.0
; Generator: SirLynix Nazara ShaderLang Compiler; 4226 ; Generator: SirLynix Nazara ShaderLang Compiler; 4226
; Bound: 23 ; Bound: 29
; Schema: 0 ; Schema: 0
OpCapability Shader OpCapability Shader
OpMemoryModel Logical GLSL450 OpMemoryModel Logical GLSL450
@@ -21,23 +21,30 @@
%v4float = OpTypeVector %float 4 %v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float %_ptr_Output_v4float = OpTypePointer Output %v4float
%FragOut = OpTypeStruct %v4float %FragOut = OpTypeStruct %v4float
%float_2 = OpConstant %float 2
%float_8 = OpConstant %float 8
%float_0_25 = OpConstant %float 0.25
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Function_FragOut = OpTypePointer Function %FragOut %_ptr_Function_FragOut = OpTypePointer Function %FragOut
%int = OpTypeInt 32 1 %int = OpTypeInt 32 1
%int_0 = OpConstant %int 0 %int_0 = OpConstant %int 0
%float_4 = OpConstant %float 4 %float_4 = OpConstant %float 4
%float_3 = OpConstant %float 3 %float_3 = OpConstant %float 3
%float_2 = OpConstant %float 2
%float_1 = OpConstant %float 1 %float_1 = OpConstant %float 1
%_ptr_Function_v4float = OpTypePointer Function %v4float
%color = OpVariable %_ptr_Output_v4float Output %color = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %2 %main = OpFunction %void None %2
%16 = OpLabel %19 = OpLabel
%17 = OpVariable %_ptr_Function_FragOut Function %20 = OpVariable %_ptr_Function_v4float Function
%18 = OpCompositeConstruct %v4float %float_4 %float_3 %float_2 %float_1 %21 = OpVariable %_ptr_Function_FragOut Function
%19 = OpAccessChain %_ptr_Function_v4float %17 %int_0 %22 = OpCompositeConstruct %v4float %float_2 %float_2 %float_8 %float_0_25
OpStore %19 %18 OpStore %20 %22
%21 = OpLoad %FragOut %17 %23 = OpCompositeConstruct %v4float %float_4 %float_3 %float_2 %float_1
%22 = OpCompositeExtract %v4float %21 0 %24 = OpLoad %v4float %20
OpStore %color %22 %25 = OpFMul %v4float %23 %24
%26 = OpAccessChain %_ptr_Function_v4float %21 %int_0
OpStore %26 %25
%27 = OpLoad %FragOut %21
%28 = OpCompositeExtract %v4float %27 0
OpStore %color %28
OpReturn OpReturn
OpFunctionEnd OpFunctionEnd

View File

@@ -160,7 +160,12 @@ pub fn init(allocator: std.mem.Allocator, source: []const SpvWord) ModuleError!S
entry_points, entry_points,
}); });
//@import("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,
// .struct_max_len = 0,
// .array_max_len = 0,
//}) catch return ModuleError.OutOfMemory;
} }
return self; return self;

View File

@@ -293,6 +293,14 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
self.decorations.deinit(allocator); self.decorations.deinit(allocator);
} }
pub fn getValue(self: *Self) RuntimeError!*Value {
return switch (self.variant orelse return RuntimeError.InvalidSpirV) {
.Variable => |*v| &v.value,
.Constant => |*v| v,
else => RuntimeError.InvalidSpirV,
};
}
/// Performs a deep copy /// Performs a deep copy
pub fn dupe(self: *const Self, allocator: std.mem.Allocator) RuntimeError!Self { pub fn dupe(self: *const Self, allocator: std.mem.Allocator) RuntimeError!Self {
return .{ return .{
@@ -330,7 +338,7 @@ pub fn dupe(self: *const Self, allocator: std.mem.Allocator) RuntimeError!Self {
}, },
}, },
}, },
else => {}, else => break :blk .{ .Type = t },
}, },
.Variable => |v| break :blk .{ .Variable => |v| break :blk .{
.Variable = .{ .Variable = .{

View File

@@ -19,7 +19,7 @@ pub const SetupDispatcher = block: {
@setEvalBranchQuota(65535); @setEvalBranchQuota(65535);
break :block std.EnumMap(spv.SpvOp, OpCodeFunc).init(.{ break :block std.EnumMap(spv.SpvOp, OpCodeFunc).init(.{
.Capability = opCapability, .Capability = opCapability,
.CompositeConstruct = opCompositeConstructSetup, .CompositeConstruct = autoSetupConstant,
.Constant = opConstant, .Constant = opConstant,
.Decorate = opDecorate, .Decorate = opDecorate,
.EntryPoint = opEntryPoint, .EntryPoint = opEntryPoint,
@@ -27,7 +27,7 @@ pub const SetupDispatcher = block: {
.Function = opFunction, .Function = opFunction,
.FunctionEnd = opFunctionEnd, .FunctionEnd = opFunctionEnd,
.Label = opLabel, .Label = opLabel,
.Load = opLoadSetup, .Load = autoSetupConstant,
.MemberDecorate = opDecorateMember, .MemberDecorate = opDecorateMember,
.MemberName = opMemberName, .MemberName = opMemberName,
.MemoryModel = opMemoryModel, .MemoryModel = opMemoryModel,
@@ -44,6 +44,7 @@ pub const SetupDispatcher = block: {
.TypeVector = opTypeVector, .TypeVector = opTypeVector,
.TypeVoid = opTypeVoid, .TypeVoid = opTypeVoid,
.Variable = opVariable, .Variable = opVariable,
.FMul = autoSetupConstant,
}); });
}; };
@@ -56,6 +57,7 @@ pub const RuntimeDispatcher = block: {
.Load = opLoad, .Load = opLoad,
.Return = opReturn, .Return = opReturn,
.Store = opStore, .Store = opStore,
.FMul = opFMul,
}); });
}; };
@@ -272,7 +274,7 @@ fn opTypeVector(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!voi
.Type = .{ .Type = .{
.Vector = .{ .Vector = .{
.components_type_word = components_type_word, .components_type_word = components_type_word,
.components_type = switch (rt.mod.results[components_type_word].variant.?) { .components_type = switch (rt.mod.results[components_type_word].variant orelse return RuntimeError.InvalidSpirV) {
.Type => |t| @as(Result.Type, t), .Type => |t| @as(Result.Type, t),
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
@@ -289,7 +291,7 @@ fn opTypeMatrix(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!voi
.Type = .{ .Type = .{
.Matrix = .{ .Matrix = .{
.column_type_word = column_type_word, .column_type_word = column_type_word,
.column_type = switch (rt.mod.results[column_type_word].variant.?) { .column_type = switch (rt.mod.results[column_type_word].variant orelse return RuntimeError.InvalidSpirV) {
.Type => |t| @as(Result.Type, t), .Type => |t| @as(Result.Type, t),
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
@@ -459,10 +461,6 @@ fn opLabel(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
}; };
} }
fn opCompositeConstructSetup(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
_ = try setupConstant(allocator, rt);
}
fn opCompositeConstruct(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void { fn opCompositeConstruct(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
_ = rt.it.skip(); _ = rt.it.skip();
const id = try rt.it.next(); const id = try rt.it.next();
@@ -501,16 +499,7 @@ fn opAccessChain(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) Runtim
const base_id = try rt.it.next(); const base_id = try rt.it.next();
const base = &rt.results[base_id]; const base = &rt.results[base_id];
var value_ptr = blk: { var value_ptr = try base.getValue();
if (base.variant) |variant| {
switch (variant) {
.Variable => |v| break :blk &v.value,
.Constant => |v| break :blk &v,
else => {},
}
}
return RuntimeError.InvalidSpirV;
};
const index_count = word_count - 3; const index_count = word_count - 3;
for (0..index_count) |_| { for (0..index_count) |_| {
@@ -570,10 +559,6 @@ fn opStore(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
); );
} }
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 { fn opLoad(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
_ = rt.it.skip(); _ = rt.it.skip();
const id = try rt.it.next(); const id = try rt.it.next();
@@ -605,6 +590,48 @@ fn opReturn(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
} }
} }
fn opFMul(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
const res_type = try rt.it.next();
const id = try rt.it.next();
const op1 = try rt.it.next();
const op2 = try rt.it.next();
const target_type = (rt.results[res_type].variant orelse return RuntimeError.InvalidSpirV).Type;
const target = &rt.results[id];
const value = try target.getValue();
const op1_target = &rt.results[op1];
const op1_value = try op1_target.getValue();
const op2_target = &rt.results[op2];
const op2_value = try op2_target.getValue();
const float_size = sw: switch (target_type) {
.Vector => |v| continue :sw (rt.results[v.components_type_word].variant orelse return RuntimeError.InvalidSpirV).Type,
.Float => |f| f.bit_length,
else => return RuntimeError.InvalidSpirV,
};
switch (value.*) {
.Float => switch (float_size) {
16 => value.Float.float16 = op1_value.Float.float16 * op2_value.Float.float16,
32 => value.Float.float32 = op1_value.Float.float32 * op2_value.Float.float32,
64 => value.Float.float64 = op1_value.Float.float64 * op2_value.Float.float64,
else => return RuntimeError.InvalidSpirV,
},
.Vector => |vec| for (vec, op1_value.Vector, op2_value.Vector) |*val, op1_v, op2_v| {
switch (float_size) {
16 => val.Float.float16 = op1_v.Float.float16 * op2_v.Float.float16,
32 => val.Float.float32 = op1_v.Float.float32 * op2_v.Float.float32,
64 => val.Float.float64 = op1_v.Float.float64 * op2_v.Float.float64,
else => return RuntimeError.InvalidSpirV,
}
},
else => return RuntimeError.InvalidSpirV,
}
}
fn setupConstant(allocator: std.mem.Allocator, rt: *Runtime) RuntimeError!*Result { fn setupConstant(allocator: std.mem.Allocator, rt: *Runtime) RuntimeError!*Result {
const res_type = try rt.it.next(); const res_type = try rt.it.next();
const id = try rt.it.next(); const id = try rt.it.next();
@@ -619,6 +646,10 @@ fn setupConstant(allocator: std.mem.Allocator, rt: *Runtime) RuntimeError!*Resul
return target; return target;
} }
fn autoSetupConstant(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
_ = try setupConstant(allocator, rt);
}
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| {