| ... | @@ -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, // TODO | 468 | 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); |
| 439 | | 474 | |
| 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 | }; |
| 443 | | 478 | |
| | 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 | }; |
| 546 | | 625 | |
| 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 | } |
| 634 | | 714 | |
| 635 | const payload = try self.spv.arena.create(SpvType.Payload.Struct); | 715 | const payload = try self.spv.arena.create(SpvType.Payload.Struct); |