refactoring constant creation
All checks were successful
Test / build (push) Successful in 24s
Build / build (push) Successful in 1m35s

This commit is contained in:
2026-01-10 02:23:15 +01:00
parent a996a41290
commit 5b9f5c93fb
2 changed files with 248 additions and 98 deletions

View File

@@ -55,9 +55,9 @@ const Decoration = struct {
}; };
pub const Value = union(Type) { pub const Value = union(Type) {
Void: noreturn, Void,
Bool: bool, Bool: bool,
Int: union { Int: extern union {
sint8: i8, sint8: i8,
sint16: i16, sint16: i16,
sint32: i32, sint32: i32,
@@ -67,7 +67,7 @@ pub const Value = union(Type) {
uint32: u32, uint32: u32,
uint64: u64, uint64: u64,
}, },
Float: union { Float: extern union {
float16: f16, float16: f16,
float32: f32, float32: f32,
float64: f64, float64: f64,
@@ -76,24 +76,103 @@ pub const Value = union(Type) {
Matrix: []Value, Matrix: []Value,
Array: struct {}, Array: struct {},
RuntimeArray: struct {}, RuntimeArray: struct {},
Structure: struct {}, Structure: []Value,
Function: noreturn, Function,
Image: struct {}, Image: struct {},
Sampler: struct {}, Sampler: struct {},
SampledImage: struct {}, SampledImage: struct {},
Pointer: noreturn, Pointer,
fn initMembers(self: *Value, allocator: std.mem.Allocator, results: []const Self, target: SpvWord) RuntimeError!void {
const resolved = results[target].resolveType(results);
const member_count = resolved.getMemberCounts();
switch (resolved.variant.?) {
.Type => |t| switch (t) {
.Bool, .Int, .Float => std.debug.assert(member_count == 1),
.Structure => |s| {
_ = s;
//self.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 ?
// inline else => |tag| @unionInit(Value, @tagName(tag), undefined),
// };
//}
},
.Matrix => |m| {
self.Matrix = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory;
for (self.Matrix) |*value| {
value.* = switch (m.column_type) {
inline else => |tag| @unionInit(Value, @tagName(tag), undefined),
}; };
}
},
.Array => |a| {
_ = a;
},
.Vector => |v| {
self.Vector = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory;
for (self.Vector) |*value| {
value.* = switch (v.components_type) {
inline else => |tag| @unionInit(Value, @tagName(tag), undefined),
};
}
},
else => {},
},
else => {},
}
}
};
//void spvm_member_allocate_typed_value(spvm_member_t val, spvm_result* results, spvm_word type)
//{
// spvm_result_t type_info = spvm_state_get_type_info(results, &results[type]);
// assert(type != 0);
//
// if (type_info->value_type == spvm_value_type_void ||
// type_info->value_type == spvm_value_type_int ||
// type_info->value_type == spvm_value_type_float ||
// type_info->value_type == spvm_value_type_bool) {
// assert(type_info->member_count == 1u);
// } else {
// spvm_member_allocate_value(val, type_info->member_count);
// }
//
// val->type = type;
//
// if (type_info->value_type == spvm_value_type_struct) {
// for (spvm_word i = 0; i < val->member_count; i++) {
// spvm_member_allocate_typed_value(&val->members[i], results, type_info->params[i]);
// }
// }
// else if (type_info->value_type == spvm_value_type_matrix) {
// 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();
name: ?[]const u8, name: ?[]const u8,
parent: ?*const Self,
member_names: std.ArrayList([]const u8),
decorations: std.ArrayList(Decoration), decorations: std.ArrayList(Decoration),
parent: ?*const Self,
variant: ?union(Variant) { variant: ?union(Variant) {
String: []const u8, String: []const u8,
Extension: struct {}, Extension: struct {},
@@ -112,18 +191,18 @@ variant: ?union(Variant) {
member_count: SpvWord, member_count: SpvWord,
}, },
Matrix: struct { Matrix: struct {
column_type_word: SpvWord,
column_type: Type, column_type: Type,
member_count: SpvWord, member_count: SpvWord,
}, },
Array: struct {}, Array: struct {},
RuntimeArray: struct {}, RuntimeArray: struct {},
Structure: struct { Structure: struct {
/// Allocated array
members: []const SpvWord, members: []const SpvWord,
member_names: std.ArrayList([]const u8),
}, },
Function: struct { Function: struct {
return_type: SpvWord, return_type: SpvWord,
/// Allocated array
params: []const SpvWord, params: []const SpvWord,
}, },
Image: struct {}, Image: struct {},
@@ -136,13 +215,12 @@ variant: ?union(Variant) {
}, },
Variable: struct { Variable: struct {
storage_class: spv.SpvStorageClass, storage_class: spv.SpvStorageClass,
value: Value, values: []Value,
}, },
Constant: Value, Constant: []Value,
Function: struct { Function: struct {
return_type: SpvWord, return_type: SpvWord,
function_type: SpvWord, function_type: SpvWord,
/// Allocated array
params: []const SpvWord, params: []const SpvWord,
}, },
AccessChain: struct {}, AccessChain: struct {},
@@ -154,7 +232,6 @@ pub fn init() Self {
return .{ return .{
.name = null, .name = null,
.parent = null, .parent = null,
.member_names = .empty,
.decorations = .empty, .decorations = .empty,
.variant = null, .variant = null,
}; };
@@ -164,22 +241,23 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
if (self.name) |name| { if (self.name) |name| {
allocator.free(name); allocator.free(name);
} }
for (self.member_names.items) |name| { if (self.variant) |*variant| {
switch (variant.*) {
.Type => |*t| switch (t.*) {
.Function => |data| allocator.free(data.params),
.Structure => |*data| {
allocator.free(data.members);
for (data.member_names.items) |name| {
allocator.free(name); allocator.free(name);
} }
if (self.variant) |variant| { data.member_names.deinit(allocator);
switch (variant) {
.Type => |t| {
switch (t) {
.Function => |data| allocator.free(data.params),
.Structure => |data| allocator.free(data.members),
else => {},
}
}, },
else => {}, else => {},
},
.Constant => |values| allocator.free(values),
else => {},
} }
} }
self.member_names.deinit(allocator);
self.decorations.deinit(allocator); self.decorations.deinit(allocator);
} }
@@ -196,17 +274,67 @@ pub fn resolveType(self: *const Self, results: []const Self) *const Self {
self; self;
} }
pub fn initConstantValue(self: *Self, results: []const Self, target: SpvWord) RuntimeError!void { pub fn getMemberCounts(self: *const Self) usize {
_ = self; if (self.variant) |variant| {
const resolved = results[target].resolveType(results);
if (resolved.variant) |variant| {
switch (variant) { switch (variant) {
.Type => |t| switch (t) { .Type => |t| switch (t) {
//.Structure => |s| .Bool, .Int, .Float, .Image, .Sampler => return 1,
.Vector => |v| return v.member_count,
.Matrix => |m| return m.member_count,
.SampledImage => return 2,
.Structure => |s| return s.members.len,
.Function => |f| return f.params.len,
else => {},
},
else => {},
}
}
return 0;
}
pub fn initConstantValue(self: *Self, allocator: std.mem.Allocator, results: []const Self, target: SpvWord) 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.?) {
.Type => |t| switch (t) {
.Bool => values[0] = .{ .Bool = undefined },
.Int => values[0] = .{ .Int = undefined },
.Float => values[0] = .{ .Float = undefined },
.Vector => |v| {
for (values) |*value| {
value.* = switch (v.components_type) {
inline else => |tag| @unionInit(Value, @tagName(tag), undefined),
};
}
},
.Matrix => |m| {
for (values) |*value| {
try value.initMembers(allocator, results, m.column_type_word);
}
},
.Array => |a| {
_ = a;
},
.Structure => |s| {
for (values, s.members) |*value, member_type| {
try value.initMembers(allocator, results, member_type);
}
},
.Image => {},
.Sampler => {}, // No op
.SampledImage => {},
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
} }
} }
return RuntimeError.InvalidSpirV;
}

View File

@@ -157,12 +157,30 @@ fn opMemberName(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime)
var result = &rt.mod.results.items[id]; var result = &rt.mod.results.items[id];
if (memb + 1 > result.member_names.items.len) { if (result.variant == null) {
_ = result.member_names.resize(allocator, memb + 1) catch return RuntimeError.OutOfMemory; result.variant = .{
.Type = .{
.Structure = .{
.members = undefined,
.member_names = .empty,
},
},
};
} }
switch (result.variant.?) {
.Type => |*t| switch (t.*) {
.Structure => |*s| {
if (memb + 1 > s.member_names.items.len) {
_ = s.member_names.resize(allocator, memb + 1) catch return RuntimeError.OutOfMemory;
}
const slen = word_count - 2; const slen = word_count - 2;
result.member_names.items[memb] = try readStringN(allocator, &rt.it, slen); s.member_names.items[memb] = try readStringN(allocator, &rt.it, slen);
},
else => unreachable,
},
else => unreachable,
}
} }
fn opMemoryModel(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { fn opMemoryModel(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {
@@ -260,10 +278,12 @@ 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();
rt.mod.results.items[id].variant = .{ rt.mod.results.items[id].variant = .{
.Type = .{ .Type = .{
.Matrix = .{ .Matrix = .{
.column_type = switch (rt.mod.results.items[try rt.it.next()].variant.?) { .column_type_word = column_type_word,
.column_type = switch (rt.mod.results.items[column_type_word].variant.?) {
.Type => |t| @as(Result.Type, t), .Type => |t| @as(Result.Type, t),
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
@@ -287,21 +307,34 @@ 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();
rt.mod.results.items[id].variant = .{ const members = blk: {
.Type = .{
.Structure = .{
.members = blk: {
const members = allocator.alloc(SpvWord, word_count - 1) catch return RuntimeError.OutOfMemory; const members = allocator.alloc(SpvWord, word_count - 1) catch return RuntimeError.OutOfMemory;
errdefer allocator.free(members); errdefer allocator.free(members);
for (members) |*member| { for (members) |*member| {
member.* = try rt.it.next(); member.* = try rt.it.next();
} }
break :blk members; break :blk members;
};
if (rt.mod.results.items[id].variant) |*variant| {
switch (variant.*) {
.Type => |*t| switch (t.*) {
.Structure => |*s| s.members = members,
else => unreachable,
}, },
else => unreachable,
}
} else {
rt.mod.results.items[id].variant = .{
.Type = .{
.Structure = .{
.members = members,
.member_names = .empty,
}, },
}, },
}; };
} }
}
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();
@@ -322,45 +355,31 @@ fn opTypeFunction(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtim
}; };
} }
fn opConstant(_: 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 var_type = try rt.it.next();
const id = try rt.it.next(); const id = try rt.it.next();
rt.mod.results.items[id].variant = .{
.Constant = value: { const target = &rt.mod.results.items[id];
const resolved = rt.mod.results.items[var_type].resolveType(rt.mod.results.items); try target.initConstantValue(allocator, rt.mod.results.items, var_type);
if (resolved.variant) |variant| {
switch (variant) { // No check on null and sizes, absolute trust in this shit
.Type => |t| switch (t) { switch (target.variant.?.Constant[0]) {
.Int => { .Int => |*i| {
break :value if (word_count - 2 != 1) .{ if (word_count - 2 != 1) {
.Int = .{ i.uint64 = @as(u64, try rt.it.next()) | (@as(u64, try rt.it.next()) >> 32);
.uint64 = @as(u64, try rt.it.next()) | (@as(u64, try rt.it.next()) >> 32), } else {
}, i.uint32 = try rt.it.next();
} else .{
.Int = .{
.uint32 = try rt.it.next(),
},
};
},
.Float => {
break :value if (word_count - 2 != 1) .{
.Float = .{
.float64 = @bitCast(@as(u64, try rt.it.next()) | (@as(u64, try rt.it.next()) >> 32)),
},
} else .{
.Float = .{
.float32 = @bitCast(try rt.it.next()),
},
};
},
else => {}, // Will fallback on error,
},
else => {}, // Will fallback on error
} }
}
return RuntimeError.InvalidSpirV;
}, },
}; .Float => |*f| {
if (word_count - 2 != 1) {
f.float64 = @bitCast(@as(u64, try rt.it.next()) | (@as(u64, try rt.it.next()) >> 32));
} else {
f.float32 = @bitCast(try rt.it.next());
}
},
else => return RuntimeError.InvalidSpirV,
}
} }
fn opVariable(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void { fn opVariable(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
@@ -368,18 +387,21 @@ fn opVariable(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeEr
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; _ = initializer;
rt.mod.results.items[id].variant = .{ //rt.mod.results.items[id].variant = .{
.Variable = .{ // .Variable = .{
.storage_class = storage_class, // .storage_class = storage_class,
.value = value: { // .value = value: {
const resolved = rt.mod.results.items[var_type].resolveType(rt.mod.results.items); // const resolved = rt.mod.results.items[var_type].resolveType(rt.mod.results.items);
_ = resolved; // _ = resolved;
break :value undefined; // break :value undefined;
}, // },
}, // },
}; //};
} }
fn opFunction(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { fn opFunction(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void {