authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2022-11-27 12:51:05+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-04-09 01:51:50+02:00
log23e210c38f9c35e26ac43f6f585c6d8a4751e318
tree9e4dc53c6e3cddf5bd03dba4d75409e7bcf885df
parentbca6f2901af5e2ff30f1ff1780eb23b5e05e2f86
signaturelock-open Commit is signed but in an unrecognized format.

spirv: (some) array and struct constants

Starts implementing constant lowering for some array and struct constants. In particular, TODO are packed structs.

1 files changed, 89 insertions(+), 9 deletions(-)

src/codegen/spirv.zig+89-9
......@@ -410,6 +410,44 @@ pub const DeclGen = struct {
410410 .value = value,
411411 });
412412 },
413 .Array => switch (val.tag()) {
414 .aggregate => { // todo: combine with Vector
415 const elem_vals = val.castTag(.aggregate).?.data;
416 const elem_ty = ty.elemType();
417 const len = @intCast(u32, ty.arrayLenIncludingSentinel()); // TODO: limit spir-v to 32 bit arrays in a more elegant way.
418 const constituents = try self.spv.gpa.alloc(IdRef, len);
419 defer self.spv.gpa.free(constituents);
420 for (elem_vals[0..len]) |elem_val, i| {
421 constituents[i] = try self.genConstant(elem_ty, elem_val);
422 }
423 try section.emit(self.spv.gpa, .OpConstantComposite, .{
424 .id_result_type = result_type_id,
425 .id_result = result_id,
426 .constituents = constituents,
427 });
428 },
429 .repeated => {
430 const elem_val = val.castTag(.repeated).?.data;
431 const elem_ty = ty.elemType();
432 const len = @intCast(u32, ty.arrayLenIncludingSentinel()); // TODO: limit spir-v to 32 bit arrays in a more elegant way.
433 const constituents = try self.spv.gpa.alloc(IdRef, len);
434 defer self.spv.gpa.free(constituents);
435
436 const elem_val_id = try self.genConstant(elem_ty, elem_val);
437 for (constituents[0..len]) |*elem| {
438 elem.* = elem_val_id;
439 }
440 if (ty.sentinel()) |sentinel| {
441 constituents[len] = try self.genConstant(elem_ty, sentinel);
442 }
443 try section.emit(self.spv.gpa, .OpConstantComposite, .{
444 .id_result_type = result_type_id,
445 .id_result = result_id,
446 .constituents = constituents,
447 });
448 },
449 else => return self.todo("array constant with tag {s}", .{@tagName(val.tag())}),
450 },
413451 .Vector => switch (val.tag()) {
414452 .aggregate => {
415453 const elem_vals = val.castTag(.aggregate).?.data;
......@@ -427,20 +465,20 @@ pub const DeclGen = struct {
427465 .constituents = elem_refs,
428466 });
429467 },
430 else => unreachable, // TODO
468 else => return self.todo("vector constant with tag {s}", .{@tagName(val.tag())}),
431469 },
432470 .Enum => {
433 var int_buffer: Value.Payload.U64 = undefined;
434 const int_val = val.enumToInt(ty, &int_buffer).toUnsignedInt(target);
435
436 var buffer: Type.Payload.Bits = undefined;
437 const int_ty = ty.intTagType(&buffer);
471 var ty_buffer: Type.Payload.Bits = undefined;
472 const int_ty = ty.intTagType(&ty_buffer);
438473 const int_info = int_ty.intInfo(target);
439474
440475 const backing_bits = self.backingIntBits(int_info.bits) orelse {
441476 return self.todo("implement composite int constants for {}", .{int_ty.fmtDebug()});
442477 };
443478
479 var int_buffer: Value.Payload.U64 = undefined;
480 const int_val = val.enumToInt(ty, &int_buffer).toUnsignedInt(target); // TODO: composite integer constants
481
444482 const value: spec.LiteralContextDependentNumber = switch (backing_bits) {
445483 1...32 => .{ .uint32 = @truncate(u32, int_val) },
446484 33...64 => .{ .uint64 = int_val },
......@@ -453,6 +491,48 @@ pub const DeclGen = struct {
453491 .value = value,
454492 });
455493 },
494 .Struct => {
495 const constituents = if (ty.isSimpleTupleOrAnonStruct()) blk: {
496 const tuple = ty.tupleFields();
497 const constituents = try self.spv.gpa.alloc(IdRef, tuple.types.len);
498 errdefer self.spv.gpa.free(constituents);
499
500 var member_index: usize = 0;
501 for (tuple.types) |field_ty, i| {
502 const field_val = tuple.values[i];
503 if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits()) continue;
504 constituents[member_index] = try self.genConstant(field_ty, field_val);
505 member_index += 1;
506 }
507
508 break :blk constituents[0..member_index];
509 } else blk: {
510 const struct_ty = ty.castTag(.@"struct").?.data;
511
512 if (struct_ty.layout == .Packed) {
513 return self.todo("packed struct constants", .{});
514 }
515
516 const field_vals = val.castTag(.aggregate).?.data;
517 const constituents = try self.spv.gpa.alloc(IdRef, struct_ty.fields.count());
518 errdefer self.spv.gpa.free(constituents);
519 var member_index: usize = 0;
520 for (struct_ty.fields.values()) |field, i| {
521 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
522 constituents[member_index] = try self.genConstant(field.ty, field_vals[i]);
523 member_index += 1;
524 }
525
526 break :blk constituents[0..member_index];
527 };
528 defer self.spv.gpa.free(constituents);
529
530 try section.emit(self.spv.gpa, .OpConstantComposite, .{
531 .id_result_type = result_type_id,
532 .id_result = result_id,
533 .constituents = constituents,
534 });
535 },
456536 .Void => unreachable,
457537 .Fn => unreachable,
458538 else => return self.todo("constant generation of type {s}: {}", .{ @tagName(ty.zigTypeTag()), ty.fmtDebug() }),
......@@ -539,9 +619,8 @@ pub const DeclGen = struct {
539619 },
540620 .Array => {
541621 const elem_ty = ty.childType();
542 const total_len_u64 = ty.arrayLen() + @boolToInt(ty.sentinel() != null);
543 const total_len = std.math.cast(u32, total_len_u64) orelse {
544 return self.fail("array type of {} elements is too large", .{total_len_u64});
622 const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel()) orelse {
623 return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel()});
545624 };
546625
547626 const payload = try self.spv.arena.create(SpvType.Payload.Array);
......@@ -630,6 +709,7 @@ pub const DeclGen = struct {
630709 .ty = try self.resolveType(field_ty),
631710 .offset = 0,
632711 };
712 member_index += 1;
633713 }
634714
635715 const payload = try self.spv.arena.create(SpvType.Payload.Struct);