Skip to content

Commit 2b12dd0

Browse files
spirv: enhance assembler to handle constant strings and result IDs
1 parent 7da4e30 commit 2b12dd0

File tree

3 files changed

+84
-3
lines changed

3 files changed

+84
-3
lines changed

src/codegen/spirv.zig

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6439,7 +6439,8 @@ const NavGen = struct {
64396439

64406440
// TODO: This entire function should be handled a bit better...
64416441
const ip = &zcu.intern_pool;
6442-
switch (ip.indexToKey(val.toIntern())) {
6442+
const key = ip.indexToKey(val.toIntern());
6443+
switch (key) {
64436444
.int_type,
64446445
.ptr_type,
64456446
.array_type,
@@ -6461,6 +6462,27 @@ const NavGen = struct {
64616462

64626463
.int => try as.value_map.put(as.gpa, name, .{ .constant = @intCast(val.toUnsignedInt(zcu)) }),
64636464
.enum_literal => |str| try as.value_map.put(as.gpa, name, .{ .string = str.toSlice(ip) }),
6465+
.ptr => |ptr| {
6466+
switch (ptr.base_addr) {
6467+
.uav => |uav| {
6468+
const pointee_val = uav.val;
6469+
const pointee_key = ip.indexToKey(pointee_val);
6470+
switch (pointee_key) {
6471+
.aggregate => |aggregate| {
6472+
if (Type.fromInterned(pointee_key.aggregate.ty).zigTypeTag(zcu) == .array and aggregate.storage == .bytes) {
6473+
const pointee_type = Type.fromInterned(pointee_key.aggregate.ty);
6474+
const bytes = aggregate.storage.bytes.toSlice(pointee_type.arrayLenIncludingSentinel(zcu), ip);
6475+
try as.value_map.put(as.gpa, name, .{ .string = bytes });
6476+
} else {
6477+
return self.fail("unsupported pointee constant type for 'c' constraint (ptr.uav.aggregate case - pointee type tag: {}, storage: {})", .{ Type.fromInterned(pointee_key.aggregate.ty).zigTypeTag(zcu), aggregate.storage });
6478+
}
6479+
},
6480+
else => return self.fail("unsupported pointee constant type for 'c' constraint (ptr.uav case): {}", .{pointee_key}),
6481+
}
6482+
},
6483+
else => return self.fail("unsupported pointer base address type for 'c' constraint: {}", .{ptr.base_addr}),
6484+
}
6485+
},
64646486

64656487
else => unreachable, // TODO
64666488
}

src/codegen/spirv/Assembler.zig

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,22 @@ const AsmValue = union(enum) {
152152
.ty => |result| result,
153153
};
154154
}
155+
156+
/// Retrieve the result-id of this AsmValue, creating constants as needed.
157+
/// This is used by the assembler to convert constants and strings to result IDs.
158+
pub fn resultIdOrConstant(self: AsmValue, spv: *SpvModule) !Id {
159+
return switch (self) {
160+
.just_declared,
161+
.unresolved_forward_reference,
162+
.constant,
163+
=> unreachable, // TODO: Create constant integer instruction
164+
.string => |str| {
165+
return try spv.constStringGlobal(str);
166+
},
167+
.value => |result| result,
168+
.ty => |result| result,
169+
};
170+
}
155171
};
156172

157173
/// This map type maps results to values. Results can be addressed either by name (without the %), or by
@@ -508,7 +524,7 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue {
508524
.ref_id => |index| {
509525
const result = try self.resolveRef(index);
510526
try section.ensureUnusedCapacity(self.spv.gpa, 1);
511-
section.writeOperand(spec.Id, result.resultId());
527+
section.writeOperand(spec.Id, try result.resultIdOrConstant(self.spv));
512528
},
513529
.string => |offset| {
514530
const text = std.mem.sliceTo(self.inst.string_bytes.items[offset..], 0);
@@ -559,7 +575,7 @@ fn resolveRef(self: *Assembler, ref: AsmValue.Ref) !AsmValue {
559575

560576
fn resolveRefId(self: *Assembler, ref: AsmValue.Ref) !Id {
561577
const value = try self.resolveRef(ref);
562-
return value.resultId();
578+
return value.resultIdOrConstant(self.spv);
563579
}
564580

565581
/// Attempt to parse an instruction into `self.inst`.

src/codegen/spirv/Module.zig

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ cache: struct {
171171
extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, Id) = .empty,
172172
decorations: std.AutoHashMapUnmanaged(struct { Id, spec.Decoration }, void) = .empty,
173173
builtins: std.AutoHashMapUnmanaged(struct { Id, spec.BuiltIn }, Decl.Index) = .empty,
174+
const_strings: std.StringHashMapUnmanaged(Id) = .empty,
174175

175176
bool_const: [2]?Id = .{ null, null },
176177
} = .{},
@@ -229,6 +230,7 @@ pub fn deinit(self: *Module) void {
229230
self.cache.extended_instruction_set.deinit(self.gpa);
230231
self.cache.decorations.deinit(self.gpa);
231232
self.cache.builtins.deinit(self.gpa);
233+
self.cache.const_strings.deinit(self.gpa);
232234

233235
self.decls.deinit(self.gpa);
234236
self.decl_deps.deinit(self.gpa);
@@ -504,6 +506,47 @@ pub fn resolveString(self: *Module, string: []const u8) !Id {
504506
return id;
505507
}
506508

509+
pub fn constStringGlobal(self: *Module, str: []const u8) !Id {
510+
if (self.cache.const_strings.get(str)) |id| return id;
511+
512+
const u8_ty = try self.intType(.unsigned, 8);
513+
const len = str.len + 1;
514+
const len_id = try self.constant(try self.intType(.unsigned, 32), .{ .uint32 = @intCast(len) });
515+
const arr_ty = try self.arrayType(len_id, u8_ty);
516+
517+
const char_ids = try self.gpa.alloc(Id, len);
518+
defer self.gpa.free(char_ids);
519+
for (str, 0..) |c, i| {
520+
char_ids[i] = try self.constant(u8_ty, .{ .uint32 = c });
521+
}
522+
char_ids[str.len] = try self.constant(u8_ty, .{ .uint32 = 0 });
523+
524+
const const_arr_id = self.allocId();
525+
try self.sections.types_globals_constants.emit(self.gpa, .OpConstantComposite, .{
526+
.id_result_type = arr_ty,
527+
.id_result = const_arr_id,
528+
.constituents = char_ids,
529+
});
530+
531+
const ptr_ty = self.allocId();
532+
try self.sections.types_globals_constants.emit(self.gpa, .OpTypePointer, .{
533+
.id_result = ptr_ty,
534+
.storage_class = .uniform_constant,
535+
.type = arr_ty,
536+
});
537+
538+
const var_id = self.allocId();
539+
try self.sections.types_globals_constants.emit(self.gpa, .OpVariable, .{
540+
.id_result_type = ptr_ty,
541+
.id_result = var_id,
542+
.storage_class = .uniform_constant,
543+
.initializer = const_arr_id,
544+
});
545+
546+
try self.cache.const_strings.put(self.gpa, try self.arena.allocator().dupe(u8, str), var_id);
547+
return var_id;
548+
}
549+
507550
pub fn structType(self: *Module, result_id: Id, types: []const Id, maybe_names: ?[]const []const u8) !void {
508551
try self.sections.types_globals_constants.emit(self.gpa, .OpTypeStruct, .{
509552
.id_result = result_id,

0 commit comments

Comments
 (0)