| ... | ... | @@ -238,7 +238,7 @@ pub const DeclGen = struct { |
| 238 | 238 | return try self.resolveDecl(fn_decl_index); |
| 239 | 239 | } |
| 240 | 240 | |
| 241 | | return try self.genConstant(ty, val, .direct); |
| 241 | return try self.constant(ty, val, .direct); |
| 242 | 242 | } |
| 243 | 243 | const index = Air.refToIndex(inst).?; |
| 244 | 244 | return self.inst_results.get(index).?; // Assertion means instruction does not dominate usage. |
| ... | ... | @@ -394,15 +394,15 @@ pub const DeclGen = struct { |
| 394 | 394 | return result_id; |
| 395 | 395 | } |
| 396 | 396 | |
| 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 { |
| 398 | 398 | const result_id = self.spv.allocId(); |
| 399 | | try self.genConstantForId(result_id, ty, val, repr); |
| 399 | try self.genConstant(result_id, ty, val, repr); |
| 400 | 400 | return result_id; |
| 401 | 401 | } |
| 402 | 402 | |
| 403 | 403 | /// Generate a constant representing `val`. |
| 404 | 404 | /// 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 { |
| 406 | 406 | const target = self.getTarget(); |
| 407 | 407 | const section = &self.spv.sections.types_globals_constants; |
| 408 | 408 | const result_ty_ref = try self.resolveType(ty, repr); |
| ... | ... | @@ -453,7 +453,7 @@ pub const DeclGen = struct { |
| 453 | 453 | const constituents = try self.spv.gpa.alloc(IdRef, len); |
| 454 | 454 | defer self.spv.gpa.free(constituents); |
| 455 | 455 | 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); |
| 457 | 457 | } |
| 458 | 458 | try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{ |
| 459 | 459 | .id_result_type = result_ty_id, |
| ... | ... | @@ -469,12 +469,12 @@ pub const DeclGen = struct { |
| 469 | 469 | const constituents = try self.spv.gpa.alloc(IdRef, total_len); |
| 470 | 470 | defer self.spv.gpa.free(constituents); |
| 471 | 471 | |
| 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); |
| 473 | 473 | for (constituents[0..len]) |*elem| { |
| 474 | 474 | elem.* = elem_val_id; |
| 475 | 475 | } |
| 476 | 476 | if (ty.sentinel()) |sentinel| { |
| 477 | | constituents[len] = try self.genConstant(elem_ty, sentinel, repr); |
| 477 | constituents[len] = try self.constant(elem_ty, sentinel, repr); |
| 478 | 478 | } |
| 479 | 479 | try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{ |
| 480 | 480 | .id_result_type = result_ty_id, |
| ... | ... | @@ -492,7 +492,7 @@ pub const DeclGen = struct { |
| 492 | 492 | const total_len = @intCast(u32, ty.arrayLenIncludingSentinel()); |
| 493 | 493 | const constituents = try self.spv.gpa.alloc(IdRef, total_len); |
| 494 | 494 | defer self.spv.gpa.free(constituents); |
| 495 | | for (bytes) |byte, i| { |
| 495 | for (bytes, 0..) |byte, i| { |
| 496 | 496 | constituents[i] = self.spv.allocId(); |
| 497 | 497 | try self.spv.emitConstant(elem_ty_id, constituents[i], .{ .uint32 = byte }); |
| 498 | 498 | } |
| ... | ... | @@ -518,7 +518,7 @@ pub const DeclGen = struct { |
| 518 | 518 | const elem_refs = try self.gpa.alloc(IdRef, vector_len); |
| 519 | 519 | defer self.gpa.free(elem_refs); |
| 520 | 520 | 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); |
| 522 | 522 | } |
| 523 | 523 | try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{ |
| 524 | 524 | .id_result_type = result_ty_id, |
| ... | ... | @@ -543,7 +543,7 @@ pub const DeclGen = struct { |
| 543 | 543 | for (tuple.types, 0..) |field_ty, i| { |
| 544 | 544 | const field_val = tuple.values[i]; |
| 545 | 545 | 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); |
| 547 | 547 | member_i += 1; |
| 548 | 548 | } |
| 549 | 549 | |
| ... | ... | @@ -561,7 +561,7 @@ pub const DeclGen = struct { |
| 561 | 561 | var member_i: usize = 0; |
| 562 | 562 | for (struct_ty.fields.values(), 0..) |field, i| { |
| 563 | 563 | 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); |
| 565 | 565 | member_i += 1; |
| 566 | 566 | } |
| 567 | 567 | |
| ... | ... | @@ -582,8 +582,8 @@ pub const DeclGen = struct { |
| 582 | 582 | const slice = val.castTag(.slice).?.data; |
| 583 | 583 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 584 | 584 | |
| 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); |
| 587 | 587 | |
| 588 | 588 | const constituents = [_]IdRef{ ptr_id, len_id }; |
| 589 | 589 | try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{ |
| ... | ... | @@ -594,6 +594,45 @@ pub const DeclGen = struct { |
| 594 | 594 | }, |
| 595 | 595 | else => return self.todo("pointer of value type {s}", .{@tagName(val.tag())}), |
| 596 | 596 | }, |
| 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 | }, |
| 597 | 636 | .Fn => switch (repr) { |
| 598 | 637 | .direct => unreachable, |
| 599 | 638 | .indirect => return self.todo("function pointers", .{}), |
| ... | ... | @@ -606,7 +645,7 @@ pub const DeclGen = struct { |
| 606 | 645 | fn genDeclRef(self: *DeclGen, result_ty_ref: SpvType.Ref, result_id: IdRef, decl_index: Decl.Index) Error!void { |
| 607 | 646 | const decl = self.module.declPtr(decl_index); |
| 608 | 647 | 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); |
| 610 | 649 | try self.variable(.global, result_id, result_ty_ref, decl_id); |
| 611 | 650 | } |
| 612 | 651 | |
| ... | ... | @@ -814,7 +853,9 @@ pub const DeclGen = struct { |
| 814 | 853 | const payload_ty = ty.optionalChild(&buf); |
| 815 | 854 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 816 | 855 | // 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); |
| 818 | 859 | } |
| 819 | 860 | |
| 820 | 861 | const payload_ty_ref = try self.resolveType(payload_ty, .indirect); |
| ... | ... | @@ -823,7 +864,7 @@ pub const DeclGen = struct { |
| 823 | 864 | return payload_ty_ref; |
| 824 | 865 | } |
| 825 | 866 | |
| 826 | | const bool_ty_ref = try self.resolveType(Type.initTag(.bool), .indirect); |
| 867 | const bool_ty_ref = try self.resolveType(Type.bool, .indirect); |
| 827 | 868 | |
| 828 | 869 | // its an actual optional |
| 829 | 870 | return try self.simpleStructType(&.{ |
| ... | ... | @@ -906,7 +947,7 @@ pub const DeclGen = struct { |
| 906 | 947 | .name = fqn, |
| 907 | 948 | }); |
| 908 | 949 | } else { |
| 909 | | try self.genConstantForId(result_id, decl.ty, decl.val, .direct); |
| 950 | try self.genConstant(result_id, decl.ty, decl.val, .direct); |
| 910 | 951 | } |
| 911 | 952 | } |
| 912 | 953 | |
| ... | ... | @@ -1256,7 +1297,7 @@ pub const DeclGen = struct { |
| 1256 | 1297 | var lhs_id = try self.resolve(bin_op.lhs); |
| 1257 | 1298 | var rhs_id = try self.resolve(bin_op.rhs); |
| 1258 | 1299 | 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); |
| 1260 | 1301 | const op_ty = self.air.typeOf(bin_op.lhs); |
| 1261 | 1302 | assert(op_ty.eql(self.air.typeOf(bin_op.rhs), self.module)); |
| 1262 | 1303 | |
| ... | ... | @@ -1350,7 +1391,7 @@ pub const DeclGen = struct { |
| 1350 | 1391 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1351 | 1392 | const operand_id = try self.resolve(ty_op.operand); |
| 1352 | 1393 | 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); |
| 1354 | 1395 | try self.func.body.emit(self.spv.gpa, .OpLogicalNot, .{ |
| 1355 | 1396 | .id_result_type = result_type_id, |
| 1356 | 1397 | .id_result = result_id, |