Commit 7872082939

Ali Cheraghi <alichraghi@proton.me>
2025-02-15 06:07:22
spirv: extend supported `c` constraint values
1 parent d5e1cb3
Changed files (2)
src
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);
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