From 23e210c38f9c35e26ac43f6f585c6d8a4751e318 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 27 Nov 2022 12:51:05 +0100 Subject: [PATCH] spirv: (some) array and struct constants Starts implementing constant lowering for some array and struct constants. In particular, TODO are packed structs. --- src/codegen/spirv.zig | 98 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 9 deletions(-) diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index f691c4ce417f2aaf12a9af81195737784ecc8618..5c55e68eb9d7df3cddcfd8d1551ac3785487ba6d 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -410,6 +410,44 @@ pub const DeclGen = struct { .value = value, }); }, + .Array => switch (val.tag()) { + .aggregate => { // todo: combine with Vector + const elem_vals = val.castTag(.aggregate).?.data; + const elem_ty = ty.elemType(); + const len = @intCast(u32, ty.arrayLenIncludingSentinel()); // TODO: limit spir-v to 32 bit arrays in a more elegant way. + const constituents = try self.spv.gpa.alloc(IdRef, len); + defer self.spv.gpa.free(constituents); + for (elem_vals[0..len]) |elem_val, i| { + constituents[i] = try self.genConstant(elem_ty, elem_val); + } + try section.emit(self.spv.gpa, .OpConstantComposite, .{ + .id_result_type = result_type_id, + .id_result = result_id, + .constituents = constituents, + }); + }, + .repeated => { + const elem_val = val.castTag(.repeated).?.data; + const elem_ty = ty.elemType(); + const len = @intCast(u32, ty.arrayLenIncludingSentinel()); // TODO: limit spir-v to 32 bit arrays in a more elegant way. + const constituents = try self.spv.gpa.alloc(IdRef, len); + defer self.spv.gpa.free(constituents); + + const elem_val_id = try self.genConstant(elem_ty, elem_val); + for (constituents[0..len]) |*elem| { + elem.* = elem_val_id; + } + if (ty.sentinel()) |sentinel| { + constituents[len] = try self.genConstant(elem_ty, sentinel); + } + try section.emit(self.spv.gpa, .OpConstantComposite, .{ + .id_result_type = result_type_id, + .id_result = result_id, + .constituents = constituents, + }); + }, + else => return self.todo("array constant with tag {s}", .{@tagName(val.tag())}), + }, .Vector => switch (val.tag()) { .aggregate => { const elem_vals = val.castTag(.aggregate).?.data; @@ -427,20 +465,20 @@ pub const DeclGen = struct { .constituents = elem_refs, }); }, - else => unreachable, // TODO + else => return self.todo("vector constant with tag {s}", .{@tagName(val.tag())}), }, .Enum => { - var int_buffer: Value.Payload.U64 = undefined; - const int_val = val.enumToInt(ty, &int_buffer).toUnsignedInt(target); - - var buffer: Type.Payload.Bits = undefined; - const int_ty = ty.intTagType(&buffer); + var ty_buffer: Type.Payload.Bits = undefined; + const int_ty = ty.intTagType(&ty_buffer); const int_info = int_ty.intInfo(target); const backing_bits = self.backingIntBits(int_info.bits) orelse { return self.todo("implement composite int constants for {}", .{int_ty.fmtDebug()}); }; + var int_buffer: Value.Payload.U64 = undefined; + const int_val = val.enumToInt(ty, &int_buffer).toUnsignedInt(target); // TODO: composite integer constants + const value: spec.LiteralContextDependentNumber = switch (backing_bits) { 1...32 => .{ .uint32 = @truncate(u32, int_val) }, 33...64 => .{ .uint64 = int_val }, @@ -453,6 +491,48 @@ pub const DeclGen = struct { .value = value, }); }, + .Struct => { + const constituents = if (ty.isSimpleTupleOrAnonStruct()) blk: { + const tuple = ty.tupleFields(); + const constituents = try self.spv.gpa.alloc(IdRef, tuple.types.len); + errdefer self.spv.gpa.free(constituents); + + var member_index: usize = 0; + for (tuple.types) |field_ty, i| { + const field_val = tuple.values[i]; + if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits()) continue; + constituents[member_index] = try self.genConstant(field_ty, field_val); + member_index += 1; + } + + break :blk constituents[0..member_index]; + } else blk: { + const struct_ty = ty.castTag(.@"struct").?.data; + + if (struct_ty.layout == .Packed) { + return self.todo("packed struct constants", .{}); + } + + const field_vals = val.castTag(.aggregate).?.data; + const constituents = try self.spv.gpa.alloc(IdRef, struct_ty.fields.count()); + errdefer self.spv.gpa.free(constituents); + var member_index: usize = 0; + for (struct_ty.fields.values()) |field, i| { + if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; + constituents[member_index] = try self.genConstant(field.ty, field_vals[i]); + member_index += 1; + } + + break :blk constituents[0..member_index]; + }; + defer self.spv.gpa.free(constituents); + + try section.emit(self.spv.gpa, .OpConstantComposite, .{ + .id_result_type = result_type_id, + .id_result = result_id, + .constituents = constituents, + }); + }, .Void => unreachable, .Fn => unreachable, else => return self.todo("constant generation of type {s}: {}", .{ @tagName(ty.zigTypeTag()), ty.fmtDebug() }), @@ -539,9 +619,8 @@ pub const DeclGen = struct { }, .Array => { const elem_ty = ty.childType(); - const total_len_u64 = ty.arrayLen() + @boolToInt(ty.sentinel() != null); - const total_len = std.math.cast(u32, total_len_u64) orelse { - return self.fail("array type of {} elements is too large", .{total_len_u64}); + const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel()) orelse { + return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel()}); }; const payload = try self.spv.arena.create(SpvType.Payload.Array); @@ -630,6 +709,7 @@ pub const DeclGen = struct { .ty = try self.resolveType(field_ty), .offset = 0, }; + member_index += 1; } const payload = try self.spv.arena.create(SpvType.Payload.Struct); -- 2.54.0