diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index d6997c7e6c..ec96c56ae9 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1254,6 +1254,7 @@ const NavGen = struct { } fn ptrType(self: *NavGen, child_ty: Type, storage_class: StorageClass, child_repr: Repr) !IdRef { + const zcu = self.pt.zcu; const key = .{ child_ty.toIntern(), storage_class, child_repr }; const entry = try self.ptr_types.getOrPut(self.gpa, key); if (entry.found_existing) { @@ -1276,6 +1277,17 @@ const NavGen = struct { const child_ty_id = try self.resolveType(child_ty, child_repr); + if (self.spv.hasFeature(.shader)) { + if (child_ty.zigTypeTag(zcu) == .@"struct") { + switch (storage_class) { + .Uniform, .PushConstant => try self.spv.decorate(child_ty_id, .Block), + else => {}, + } + } + + try self.spv.decorate(result_id, .{ .ArrayStride = .{ .array_stride = @intCast(child_ty.abiSize(zcu)) } }); + } + try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypePointer, .{ .id_result = result_id, .storage_class = storage_class, @@ -6426,9 +6438,8 @@ const NavGen = struct { .undef => return self.fail("assembly input with 'c' constraint cannot be undefined", .{}), - .int => { - try as.value_map.put(as.gpa, name, .{ .constant = @intCast(val.toUnsignedInt(zcu)) }); - }, + .int => try as.value_map.put(as.gpa, name, .{ .constant = @intCast(val.toUnsignedInt(zcu)) }), + .enum_literal => |str| try as.value_map.put(as.gpa, name, .{ .string = str.toSlice(ip) }), else => unreachable, // TODO } @@ -6510,7 +6521,7 @@ const NavGen = struct { .just_declared, .unresolved_forward_reference => unreachable, .ty => return self.fail("cannot return spir-v type as value from assembly", .{}), .value => |ref| return ref, - .constant => return self.fail("cannot return constant from assembly", .{}), + .constant, .string => return self.fail("cannot return constant from assembly", .{}), } // TODO: Multiple results diff --git a/src/codegen/spirv/Assembler.zig b/src/codegen/spirv/Assembler.zig index 6bb79a2ebe..0713a63a7e 100644 --- a/src/codegen/spirv/Assembler.zig +++ b/src/codegen/spirv/Assembler.zig @@ -135,6 +135,9 @@ const AsmValue = union(enum) { /// This is a pre-supplied constant integer value. constant: u32, + /// This is a pre-supplied constant string value. + string: []const u8, + /// Retrieve the result-id of this AsmValue. Asserts that this AsmValue /// is of a variant that allows the result to be obtained (not an unresolved /// forward declaration, not in the process of being declared, etc). @@ -144,6 +147,7 @@ const AsmValue = union(enum) { .unresolved_forward_reference, // TODO: Lower this value as constant? .constant, + .string, => unreachable, .value => |result| result, .ty => |result| result, @@ -645,6 +649,28 @@ fn parseBitEnum(self: *Assembler, kind: spec.OperandKind) !void { /// Also handles parsing any required extra operands. fn parseValueEnum(self: *Assembler, kind: spec.OperandKind) !void { const tok = self.currentToken(); + if (self.eatToken(.placeholder)) { + const name = self.tokenText(tok)[1..]; + const value = self.value_map.get(name) orelse { + return self.fail(tok.start, "invalid placeholder '${s}'", .{name}); + }; + switch (value) { + .constant => |literal32| { + try self.inst.operands.append(self.gpa, .{ .value = literal32 }); + }, + .string => |str| { + const enumerant = for (kind.enumerants()) |enumerant| { + if (std.mem.eql(u8, enumerant.name, str)) break enumerant; + } else { + return self.fail(tok.start, "'{s}' is not a valid value for enumeration {s}", .{ str, @tagName(kind) }); + }; + try self.inst.operands.append(self.gpa, .{ .value = enumerant.value }); + }, + else => return self.fail(tok.start, "value '{s}' cannot be used as placeholder", .{name}), + } + return; + } + try self.expectToken(.value); const text = self.tokenText(tok);