Skip to content

Commit d1b74cd

Browse files
spirv: enhance assembler to handle constant strings and result IDs
1 parent 164ef95 commit d1b74cd

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
@@ -6471,7 +6471,8 @@ const NavGen = struct {
64716471

64726472
// TODO: This entire function should be handled a bit better...
64736473
const ip = &zcu.intern_pool;
6474-
switch (ip.indexToKey(val.toIntern())) {
6474+
const key = ip.indexToKey(val.toIntern());
6475+
switch (key) {
64756476
.int_type,
64766477
.ptr_type,
64776478
.array_type,
@@ -6493,6 +6494,27 @@ const NavGen = struct {
64936494

64946495
.int => try as.value_map.put(as.gpa, name, .{ .constant = @intCast(val.toUnsignedInt(zcu)) }),
64956496
.enum_literal => |str| try as.value_map.put(as.gpa, name, .{ .string = str.toSlice(ip) }),
6497+
.ptr => |ptr| {
6498+
switch (ptr.base_addr) {
6499+
.uav => |uav| {
6500+
const pointee_val = uav.val;
6501+
const pointee_key = ip.indexToKey(pointee_val);
6502+
switch (pointee_key) {
6503+
.aggregate => |aggregate| {
6504+
if (Type.fromInterned(pointee_key.aggregate.ty).zigTypeTag(zcu) == .array and aggregate.storage == .bytes) {
6505+
const pointee_type = Type.fromInterned(pointee_key.aggregate.ty);
6506+
const bytes = aggregate.storage.bytes.toSlice(pointee_type.arrayLenIncludingSentinel(zcu), ip);
6507+
try as.value_map.put(as.gpa, name, .{ .string = bytes });
6508+
} else {
6509+
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 });
6510+
}
6511+
},
6512+
else => return self.fail("unsupported pointee constant type for 'c' constraint (ptr.uav case): {}", .{pointee_key}),
6513+
}
6514+
},
6515+
else => return self.fail("unsupported pointer base address type for 'c' constraint: {}", .{ptr.base_addr}),
6516+
}
6517+
},
64966518

64976519
else => unreachable, // TODO
64986520
}

src/codegen/spirv/Assembler.zig

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

158174
/// This map type maps results to values. Results can be addressed either by name (without the %), or by
@@ -517,7 +533,7 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue {
517533
.ref_id => |index| {
518534
const result = try self.resolveRef(index);
519535
try section.ensureUnusedCapacity(self.spv.gpa, 1);
520-
section.writeOperand(spec.IdRef, result.resultId());
536+
section.writeOperand(spec.IdRef, try result.resultIdOrConstant(self.spv));
521537
},
522538
.string => |offset| {
523539
const text = std.mem.sliceTo(self.inst.string_bytes.items[offset..], 0);
@@ -568,7 +584,7 @@ fn resolveRef(self: *Assembler, ref: AsmValue.Ref) !AsmValue {
568584

569585
fn resolveRefId(self: *Assembler, ref: AsmValue.Ref) !IdRef {
570586
const value = try self.resolveRef(ref);
571-
return value.resultId();
587+
return value.resultIdOrConstant(self.spv);
572588
}
573589

574590
/// 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
@@ -173,6 +173,7 @@ cache: struct {
173173
extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, IdRef) = .empty,
174174
decorations: std.AutoHashMapUnmanaged(struct { IdRef, spec.Decoration }, void) = .empty,
175175
builtins: std.AutoHashMapUnmanaged(struct { IdRef, spec.BuiltIn }, Decl.Index) = .empty,
176+
const_strings: std.StringHashMapUnmanaged(IdRef) = .empty,
176177

177178
bool_const: [2]?IdRef = .{ null, null },
178179
} = .{},
@@ -231,6 +232,7 @@ pub fn deinit(self: *Module) void {
231232
self.cache.extended_instruction_set.deinit(self.gpa);
232233
self.cache.decorations.deinit(self.gpa);
233234
self.cache.builtins.deinit(self.gpa);
235+
self.cache.const_strings.deinit(self.gpa);
234236

235237
self.decls.deinit(self.gpa);
236238
self.decl_deps.deinit(self.gpa);
@@ -506,6 +508,47 @@ pub fn resolveString(self: *Module, string: []const u8) !IdRef {
506508
return id;
507509
}
508510

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

0 commit comments

Comments
 (0)