authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2022-12-11 14:40:18+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-04-09 01:51:53+02:00
log75abe3b43bf28dc1cd1ab06cc9403d4fa93e7002
treea9c386790fd00061ba65d4d88dee11f71ea81640
parent0c53fea42cea8543733612c7c63a6982ca6e59e6
signaturelock-open Commit is signed but in an unrecognized format.

spirv: optional constants

Implements lowering optional constants in the SPIR-V backend.

1 files changed, 60 insertions(+), 19 deletions(-)

src/codegen/spirv.zig+60-19
......@@ -238,7 +238,7 @@ pub const DeclGen = struct {
238238 return try self.resolveDecl(fn_decl_index);
239239 }
240240
241 return try self.genConstant(ty, val, .direct);
241 return try self.constant(ty, val, .direct);
242242 }
243243 const index = Air.refToIndex(inst).?;
244244 return self.inst_results.get(index).?; // Assertion means instruction does not dominate usage.
......@@ -394,15 +394,15 @@ pub const DeclGen = struct {
394394 return result_id;
395395 }
396396
397 fn genConstant(self: *DeclGen, ty: Type, val: Value, repr: Repr) Error!IdRef {
397 fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) Error!IdRef {
398398 const result_id = self.spv.allocId();
399 try self.genConstantForId(result_id, ty, val, repr);
399 try self.genConstant(result_id, ty, val, repr);
400400 return result_id;
401401 }
402402
403403 /// Generate a constant representing `val`.
404404 /// TODO: Deduplication?
405 fn genConstantForId(self: *DeclGen, result_id: IdRef, ty: Type, val: Value, repr: Repr) Error!void {
405 fn genConstant(self: *DeclGen, result_id: IdRef, ty: Type, val: Value, repr: Repr) Error!void {
406406 const target = self.getTarget();
407407 const section = &self.spv.sections.types_globals_constants;
408408 const result_ty_ref = try self.resolveType(ty, repr);
......@@ -453,7 +453,7 @@ pub const DeclGen = struct {
453453 const constituents = try self.spv.gpa.alloc(IdRef, len);
454454 defer self.spv.gpa.free(constituents);
455455 for (elem_vals[0..len], 0..) |elem_val, i| {
456 constituents[i] = try self.genConstant(elem_ty, elem_val, repr);
456 constituents[i] = try self.constant(elem_ty, elem_val, repr);
457457 }
458458 try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{
459459 .id_result_type = result_ty_id,
......@@ -469,12 +469,12 @@ pub const DeclGen = struct {
469469 const constituents = try self.spv.gpa.alloc(IdRef, total_len);
470470 defer self.spv.gpa.free(constituents);
471471
472 const elem_val_id = try self.genConstant(elem_ty, elem_val, repr);
472 const elem_val_id = try self.constant(elem_ty, elem_val, repr);
473473 for (constituents[0..len]) |*elem| {
474474 elem.* = elem_val_id;
475475 }
476476 if (ty.sentinel()) |sentinel| {
477 constituents[len] = try self.genConstant(elem_ty, sentinel, repr);
477 constituents[len] = try self.constant(elem_ty, sentinel, repr);
478478 }
479479 try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{
480480 .id_result_type = result_ty_id,
......@@ -492,7 +492,7 @@ pub const DeclGen = struct {
492492 const total_len = @intCast(u32, ty.arrayLenIncludingSentinel());
493493 const constituents = try self.spv.gpa.alloc(IdRef, total_len);
494494 defer self.spv.gpa.free(constituents);
495 for (bytes) |byte, i| {
495 for (bytes, 0..) |byte, i| {
496496 constituents[i] = self.spv.allocId();
497497 try self.spv.emitConstant(elem_ty_id, constituents[i], .{ .uint32 = byte });
498498 }
......@@ -518,7 +518,7 @@ pub const DeclGen = struct {
518518 const elem_refs = try self.gpa.alloc(IdRef, vector_len);
519519 defer self.gpa.free(elem_refs);
520520 for (elem_refs, 0..) |*elem, i| {
521 elem.* = try self.genConstant(elem_ty, elem_vals[i], repr);
521 elem.* = try self.constant(elem_ty, elem_vals[i], repr);
522522 }
523523 try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{
524524 .id_result_type = result_ty_id,
......@@ -543,7 +543,7 @@ pub const DeclGen = struct {
543543 for (tuple.types, 0..) |field_ty, i| {
544544 const field_val = tuple.values[i];
545545 if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits()) continue;
546 constituents[member_i] = try self.genConstant(field_ty, field_val, repr);
546 constituents[member_i] = try self.constant(field_ty, field_val, repr);
547547 member_i += 1;
548548 }
549549
......@@ -561,7 +561,7 @@ pub const DeclGen = struct {
561561 var member_i: usize = 0;
562562 for (struct_ty.fields.values(), 0..) |field, i| {
563563 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
564 constituents[member_i] = try self.genConstant(field.ty, field_vals[i], repr);
564 constituents[member_i] = try self.constant(field.ty, field_vals[i], repr);
565565 member_i += 1;
566566 }
567567
......@@ -582,8 +582,8 @@ pub const DeclGen = struct {
582582 const slice = val.castTag(.slice).?.data;
583583 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
584584
585 const ptr_id = try self.genConstant(ty.slicePtrFieldType(&buf), slice.ptr, .indirect);
586 const len_id = try self.genConstant(Type.usize, slice.len, .indirect);
585 const ptr_id = try self.constant(ty.slicePtrFieldType(&buf), slice.ptr, .indirect);
586 const len_id = try self.constant(Type.usize, slice.len, .indirect);
587587
588588 const constituents = [_]IdRef{ ptr_id, len_id };
589589 try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{
......@@ -594,6 +594,45 @@ pub const DeclGen = struct {
594594 },
595595 else => return self.todo("pointer of value type {s}", .{@tagName(val.tag())}),
596596 },
597 .Optional => {
598 var buf: Type.Payload.ElemType = undefined;
599 const payload_ty = ty.optionalChild(&buf);
600
601 const has_payload = !val.isNull();
602
603 // Note: keep in sync with the resolveType implementation for optionals.
604 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
605 // Just a bool. Note: always in indirect representation.
606 try self.genConstInt(result_ty_ref, result_id, @boolToInt(has_payload));
607 } else if (ty.optionalReprIsPayload()) {
608 // A nullable pointer.
609 if (val.castTag(.opt_payload)) |payload| {
610 try self.genConstant(result_id, payload_ty, payload.data, repr);
611 } else if (has_payload) {
612 try self.genConstant(result_id, payload_ty, val, repr);
613 } else {
614 try section.emit(self.spv.gpa, .OpConstantNull, .{
615 .id_result_type = result_ty_id,
616 .id_result = result_id,
617 });
618 }
619 return;
620 }
621
622 // Struct-and-field pair.
623 // Note: If this optional has no payload, we initialize the the data member with OpUndef.
624 const bool_ty_ref = try self.resolveType(Type.bool, .indirect);
625 const valid_id = try self.constInt(bool_ty_ref, @boolToInt(has_payload));
626 const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else Value.undef;
627 const payload_id = try self.constant(payload_ty, payload_val, .indirect);
628
629 const constituents = [_]IdRef{ payload_id, valid_id };
630 try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{
631 .id_result_type = result_ty_id,
632 .id_result = result_id,
633 .constituents = &constituents,
634 });
635 },
597636 .Fn => switch (repr) {
598637 .direct => unreachable,
599638 .indirect => return self.todo("function pointers", .{}),
......@@ -606,7 +645,7 @@ pub const DeclGen = struct {
606645 fn genDeclRef(self: *DeclGen, result_ty_ref: SpvType.Ref, result_id: IdRef, decl_index: Decl.Index) Error!void {
607646 const decl = self.module.declPtr(decl_index);
608647 self.module.markDeclAlive(decl);
609 const decl_id = try self.genConstant(decl.ty, decl.val, .indirect);
648 const decl_id = try self.constant(decl.ty, decl.val, .indirect);
610649 try self.variable(.global, result_id, result_ty_ref, decl_id);
611650 }
612651
......@@ -814,7 +853,9 @@ pub const DeclGen = struct {
814853 const payload_ty = ty.optionalChild(&buf);
815854 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
816855 // Just use a bool.
817 return try self.resolveType(Type.initTag(.bool), repr);
856 // Note: Always generate the bool with indirect format, to save on some sanity
857 // Perform the converison to a direct bool when the field is extracted.
858 return try self.resolveType(Type.bool, .indirect);
818859 }
819860
820861 const payload_ty_ref = try self.resolveType(payload_ty, .indirect);
......@@ -823,7 +864,7 @@ pub const DeclGen = struct {
823864 return payload_ty_ref;
824865 }
825866
826 const bool_ty_ref = try self.resolveType(Type.initTag(.bool), .indirect);
867 const bool_ty_ref = try self.resolveType(Type.bool, .indirect);
827868
828869 // its an actual optional
829870 return try self.simpleStructType(&.{
......@@ -906,7 +947,7 @@ pub const DeclGen = struct {
906947 .name = fqn,
907948 });
908949 } else {
909 try self.genConstantForId(result_id, decl.ty, decl.val, .direct);
950 try self.genConstant(result_id, decl.ty, decl.val, .direct);
910951 }
911952 }
912953
......@@ -1256,7 +1297,7 @@ pub const DeclGen = struct {
12561297 var lhs_id = try self.resolve(bin_op.lhs);
12571298 var rhs_id = try self.resolve(bin_op.rhs);
12581299 const result_id = self.spv.allocId();
1259 const result_type_id = try self.resolveTypeId(Type.initTag(.bool));
1300 const result_type_id = try self.resolveTypeId(Type.bool);
12601301 const op_ty = self.air.typeOf(bin_op.lhs);
12611302 assert(op_ty.eql(self.air.typeOf(bin_op.rhs), self.module));
12621303
......@@ -1350,7 +1391,7 @@ pub const DeclGen = struct {
13501391 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
13511392 const operand_id = try self.resolve(ty_op.operand);
13521393 const result_id = self.spv.allocId();
1353 const result_type_id = try self.resolveTypeId(Type.initTag(.bool));
1394 const result_type_id = try self.resolveTypeId(Type.bool);
13541395 try self.func.body.emit(self.spv.gpa, .OpLogicalNot, .{
13551396 .id_result_type = result_type_id,
13561397 .id_result = result_id,