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 {...@@ -410,6 +410,44 @@ pub const DeclGen = struct {
410 .value = value,410 .value = value,
411 });411 });
412 },412 },
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 },
413 .Vector => switch (val.tag()) {451 .Vector => switch (val.tag()) {
414 .aggregate => {452 .aggregate => {
415 const elem_vals = val.castTag(.aggregate).?.data;453 const elem_vals = val.castTag(.aggregate).?.data;
...@@ -427,20 +465,20 @@ pub const DeclGen = struct {...@@ -427,20 +465,20 @@ pub const DeclGen = struct {
427 .constituents = elem_refs,465 .constituents = elem_refs,
428 });466 });
429 },467 },
430 else => unreachable, // TODO468 else => return self.todo("vector constant with tag {s}", .{@tagName(val.tag())}),
431 },469 },
432 .Enum => {470 .Enum => {
433 var int_buffer: Value.Payload.U64 = undefined;471 var ty_buffer: Type.Payload.Bits = undefined;
434 const int_val = val.enumToInt(ty, &int_buffer).toUnsignedInt(target);472 const int_ty = ty.intTagType(&ty_buffer);
435
436 var buffer: Type.Payload.Bits = undefined;
437 const int_ty = ty.intTagType(&buffer);
438 const int_info = int_ty.intInfo(target);473 const int_info = int_ty.intInfo(target);
439474
440 const backing_bits = self.backingIntBits(int_info.bits) orelse {475 const backing_bits = self.backingIntBits(int_info.bits) orelse {
441 return self.todo("implement composite int constants for {}", .{int_ty.fmtDebug()});476 return self.todo("implement composite int constants for {}", .{int_ty.fmtDebug()});
442 };477 };
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
444 const value: spec.LiteralContextDependentNumber = switch (backing_bits) {482 const value: spec.LiteralContextDependentNumber = switch (backing_bits) {
445 1...32 => .{ .uint32 = @truncate(u32, int_val) },483 1...32 => .{ .uint32 = @truncate(u32, int_val) },
446 33...64 => .{ .uint64 = int_val },484 33...64 => .{ .uint64 = int_val },
...@@ -453,6 +491,48 @@ pub const DeclGen = struct {...@@ -453,6 +491,48 @@ pub const DeclGen = struct {
453 .value = value,491 .value = value,
454 });492 });
455 },493 },
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 },
456 .Void => unreachable,536 .Void => unreachable,
457 .Fn => unreachable,537 .Fn => unreachable,
458 else => return self.todo("constant generation of type {s}: {}", .{ @tagName(ty.zigTypeTag()), ty.fmtDebug() }),538 else => return self.todo("constant generation of type {s}: {}", .{ @tagName(ty.zigTypeTag()), ty.fmtDebug() }),
...@@ -539,9 +619,8 @@ pub const DeclGen = struct {...@@ -539,9 +619,8 @@ pub const DeclGen = struct {
539 },619 },
540 .Array => {620 .Array => {
541 const elem_ty = ty.childType();621 const elem_ty = ty.childType();
542 const total_len_u64 = ty.arrayLen() + @boolToInt(ty.sentinel() != null);622 const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel()) orelse {
543 const total_len = std.math.cast(u32, total_len_u64) orelse {623 return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel()});
544 return self.fail("array type of {} elements is too large", .{total_len_u64});
545 };624 };
546625
547 const payload = try self.spv.arena.create(SpvType.Payload.Array);626 const payload = try self.spv.arena.create(SpvType.Payload.Array);
...@@ -630,6 +709,7 @@ pub const DeclGen = struct {...@@ -630,6 +709,7 @@ pub const DeclGen = struct {
630 .ty = try self.resolveType(field_ty),709 .ty = try self.resolveType(field_ty),
631 .offset = 0,710 .offset = 0,
632 };711 };
712 member_index += 1;
633 }713 }
634714
635 const payload = try self.spv.arena.create(SpvType.Payload.Struct);715 const payload = try self.spv.arena.create(SpvType.Payload.Struct);