| ... | @@ -521,59 +521,6 @@ pub const DeclGen = struct { | ... | @@ -521,59 +521,6 @@ pub const DeclGen = struct { |
| 521 | return result_id; | 521 | return result_id; |
| 522 | } | 522 | } |
| 523 | | 523 | |
| 524 | fn constructDeclRef(self: *DeclGen, ty: Type, decl_index: Decl.Index) !IdRef { | | |
| 525 | const mod = self.module; | | |
| 526 | const ty_ref = try self.resolveType(ty, .direct); | | |
| 527 | const ty_id = self.typeId(ty_ref); | | |
| 528 | const decl = mod.declPtr(decl_index); | | |
| 529 | const spv_decl_index = try self.resolveDecl(decl_index); | | |
| 530 | switch (mod.intern_pool.indexToKey(decl.val.ip_index)) { | | |
| 531 | .func => { | | |
| 532 | // TODO: Properly lower function pointers. For now we are going to hack around it and | | |
| 533 | // just generate an empty pointer. Function pointers are represented by a pointer to usize. | | |
| 534 | // TODO: Add dependency | | |
| 535 | return try self.spv.constNull(ty_ref); | | |
| 536 | }, | | |
| 537 | .extern_func => unreachable, // TODO | | |
| 538 | else => { | | |
| 539 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; | | |
| 540 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); | | |
| 541 | | | |
| 542 | const final_storage_class = spvStorageClass(decl.@"addrspace"); | | |
| 543 | | | |
| 544 | const decl_ty_ref = try self.resolveType(decl.ty, .indirect); | | |
| 545 | const decl_ptr_ty_ref = try self.spv.ptrType(decl_ty_ref, final_storage_class); | | |
| 546 | | | |
| 547 | const ptr_id = switch (final_storage_class) { | | |
| 548 | .Generic => blk: { | | |
| 549 | // Pointer should be Generic, but is actually placed in CrossWorkgroup. | | |
| 550 | const result_id = self.spv.allocId(); | | |
| 551 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ | | |
| 552 | .id_result_type = self.typeId(decl_ptr_ty_ref), | | |
| 553 | .id_result = result_id, | | |
| 554 | .pointer = decl_id, | | |
| 555 | }); | | |
| 556 | break :blk result_id; | | |
| 557 | }, | | |
| 558 | else => decl_id, | | |
| 559 | }; | | |
| 560 | | | |
| 561 | if (decl_ptr_ty_ref != ty_ref) { | | |
| 562 | // Differing pointer types, insert a cast. | | |
| 563 | const casted_ptr_id = self.spv.allocId(); | | |
| 564 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ | | |
| 565 | .id_result_type = ty_id, | | |
| 566 | .id_result = casted_ptr_id, | | |
| 567 | .operand = ptr_id, | | |
| 568 | }); | | |
| 569 | return casted_ptr_id; | | |
| 570 | } else { | | |
| 571 | return ptr_id; | | |
| 572 | } | | |
| 573 | }, | | |
| 574 | } | | |
| 575 | } | | |
| 576 | | | |
| 577 | /// This function generates a load for a constant in direct (ie, non-memory) representation. | 524 | /// This function generates a load for a constant in direct (ie, non-memory) representation. |
| 578 | /// When the constant is simple, it can be generated directly using OpConstant instructions. | 525 | /// When the constant is simple, it can be generated directly using OpConstant instructions. |
| 579 | /// When the constant is more complicated however, it needs to be constructed using multiple values. This | 526 | /// When the constant is more complicated however, it needs to be constructed using multiple values. This |
| ... | @@ -796,7 +743,8 @@ pub const DeclGen = struct { | ... | @@ -796,7 +743,8 @@ pub const DeclGen = struct { |
| 796 | | 743 | |
| 797 | return try self.constructStruct(result_ty_ref, constituents.items); | 744 | return try self.constructStruct(result_ty_ref, constituents.items); |
| 798 | }, | 745 | }, |
| 799 | .vector_type, .anon_struct_type => unreachable, // TODO | 746 | .vector_type => unreachable, // TODO |
| | 747 | .anon_struct_type => unreachable, // TODO |
| 800 | else => unreachable, | 748 | else => unreachable, |
| 801 | }, | 749 | }, |
| 802 | .un => |un| { | 750 | .un => |un| { |
| ... | @@ -817,9 +765,9 @@ pub const DeclGen = struct { | ... | @@ -817,9 +765,9 @@ pub const DeclGen = struct { |
| 817 | const result_ty_ref = try self.resolveType(ptr_ty, .direct); | 765 | const result_ty_ref = try self.resolveType(ptr_ty, .direct); |
| 818 | const mod = self.module; | 766 | const mod = self.module; |
| 819 | switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { | 767 | switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { |
| 820 | .decl => |decl| return try self.constructDeclRef(ptr_ty, decl), | 768 | .decl => |decl| return try self.constantDeclRef(ptr_ty, decl), |
| | 769 | .mut_decl => |decl_mut| return try self.constantDeclRef(ptr_ty, decl_mut.decl), |
| 821 | .anon_decl => @panic("TODO"), | 770 | .anon_decl => @panic("TODO"), |
| 822 | .mut_decl => |decl_mut| return try self.constructDeclRef(ptr_ty, decl_mut.decl), | | |
| 823 | .int => |int| { | 771 | .int => |int| { |
| 824 | const ptr_id = self.spv.allocId(); | 772 | const ptr_id = self.spv.allocId(); |
| 825 | // TODO: This can probably be an OpSpecConstantOp Bitcast, but | 773 | // TODO: This can probably be an OpSpecConstantOp Bitcast, but |
| ... | @@ -846,6 +794,65 @@ pub const DeclGen = struct { | ... | @@ -846,6 +794,65 @@ pub const DeclGen = struct { |
| 846 | } | 794 | } |
| 847 | } | 795 | } |
| 848 | | 796 | |
| | 797 | fn constantDeclRef(self: *DeclGen, ty: Type, decl_index: Decl.Index) !IdRef { |
| | 798 | const mod = self.module; |
| | 799 | const ty_ref = try self.resolveType(ty, .direct); |
| | 800 | const ty_id = self.typeId(ty_ref); |
| | 801 | const decl = mod.declPtr(decl_index); |
| | 802 | switch (mod.intern_pool.indexToKey(decl.val.ip_index)) { |
| | 803 | .func => { |
| | 804 | // TODO: Properly lower function pointers. For now we are going to hack around it and |
| | 805 | // just generate an empty pointer. Function pointers are represented by a pointer to usize. |
| | 806 | // TODO: Add dependency |
| | 807 | return try self.spv.constNull(ty_ref); |
| | 808 | }, |
| | 809 | .extern_func => unreachable, // TODO |
| | 810 | else => {}, |
| | 811 | } |
| | 812 | |
| | 813 | if (!decl.ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) { |
| | 814 | // Pointer to nothing - return undefined. |
| | 815 | return self.spv.constUndef(ty_ref); |
| | 816 | } |
| | 817 | |
| | 818 | const spv_decl_index = try self.resolveDecl(decl_index); |
| | 819 | |
| | 820 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; |
| | 821 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); |
| | 822 | |
| | 823 | const final_storage_class = spvStorageClass(decl.@"addrspace"); |
| | 824 | |
| | 825 | const decl_ty_ref = try self.resolveType(decl.ty, .indirect); |
| | 826 | const decl_ptr_ty_ref = try self.spv.ptrType(decl_ty_ref, final_storage_class); |
| | 827 | |
| | 828 | const ptr_id = switch (final_storage_class) { |
| | 829 | .Generic => blk: { |
| | 830 | // Pointer should be Generic, but is actually placed in CrossWorkgroup. |
| | 831 | const result_id = self.spv.allocId(); |
| | 832 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ |
| | 833 | .id_result_type = self.typeId(decl_ptr_ty_ref), |
| | 834 | .id_result = result_id, |
| | 835 | .pointer = decl_id, |
| | 836 | }); |
| | 837 | break :blk result_id; |
| | 838 | }, |
| | 839 | else => decl_id, |
| | 840 | }; |
| | 841 | |
| | 842 | if (decl_ptr_ty_ref != ty_ref) { |
| | 843 | // Differing pointer types, insert a cast. |
| | 844 | const casted_ptr_id = self.spv.allocId(); |
| | 845 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| | 846 | .id_result_type = ty_id, |
| | 847 | .id_result = casted_ptr_id, |
| | 848 | .operand = ptr_id, |
| | 849 | }); |
| | 850 | return casted_ptr_id; |
| | 851 | } else { |
| | 852 | return ptr_id; |
| | 853 | } |
| | 854 | } |
| | 855 | |
| 849 | // Turn a Zig type's name into a cache reference. | 856 | // Turn a Zig type's name into a cache reference. |
| 850 | fn resolveTypeName(self: *DeclGen, ty: Type) !CacheString { | 857 | fn resolveTypeName(self: *DeclGen, ty: Type) !CacheString { |
| 851 | var name = std.ArrayList(u8).init(self.gpa); | 858 | var name = std.ArrayList(u8).init(self.gpa); |
| ... | @@ -1126,10 +1133,16 @@ pub const DeclGen = struct { | ... | @@ -1126,10 +1133,16 @@ pub const DeclGen = struct { |
| 1126 | | 1133 | |
| 1127 | var it = struct_type.iterateRuntimeOrder(ip); | 1134 | var it = struct_type.iterateRuntimeOrder(ip); |
| 1128 | while (it.next()) |field_index| { | 1135 | while (it.next()) |field_index| { |
| 1129 | const field_ty = struct_type.field_types.get(ip)[field_index]; | 1136 | const field_ty = struct_type.field_types.get(ip)[field_index].toType(); |
| 1130 | const field_name = ip.stringToSlice(struct_type.field_names.get(ip)[field_index]); | 1137 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1131 | try member_types.append(try self.resolveType(field_ty.toType(), .indirect)); | 1138 | // This is a zero-bit field - we only needed it for the alignment. |
| 1132 | try member_names.append(try self.spv.resolveString(field_name)); | 1139 | continue; |
| | 1140 | } |
| | 1141 | |
| | 1142 | const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse |
| | 1143 | try ip.getOrPutStringFmt(mod.gpa, "{d}", .{field_index}); |
| | 1144 | try member_types.append(try self.resolveType(field_ty, .indirect)); |
| | 1145 | try member_names.append(try self.spv.resolveString(ip.stringToSlice(field_name))); |
| 1133 | } | 1146 | } |
| 1134 | | 1147 | |
| 1135 | const ty_ref = try self.spv.resolve(.{ .struct_type = .{ | 1148 | const ty_ref = try self.spv.resolve(.{ .struct_type = .{ |