| ... | ... | @@ -521,59 +521,6 @@ pub const DeclGen = struct { |
| 521 | 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 | 524 | /// This function generates a load for a constant in direct (ie, non-memory) representation. |
| 578 | 525 | /// When the constant is simple, it can be generated directly using OpConstant instructions. |
| 579 | 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 | 743 | |
| 797 | 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 | 748 | else => unreachable, |
| 801 | 749 | }, |
| 802 | 750 | .un => |un| { |
| ... | ... | @@ -817,9 +765,9 @@ pub const DeclGen = struct { |
| 817 | 765 | const result_ty_ref = try self.resolveType(ptr_ty, .direct); |
| 818 | 766 | const mod = self.module; |
| 819 | 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 | 770 | .anon_decl => @panic("TODO"), |
| 822 | | .mut_decl => |decl_mut| return try self.constructDeclRef(ptr_ty, decl_mut.decl), |
| 823 | 771 | .int => |int| { |
| 824 | 772 | const ptr_id = self.spv.allocId(); |
| 825 | 773 | // TODO: This can probably be an OpSpecConstantOp Bitcast, but |
| ... | ... | @@ -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 | 856 | // Turn a Zig type's name into a cache reference. |
| 850 | 857 | fn resolveTypeName(self: *DeclGen, ty: Type) !CacheString { |
| 851 | 858 | var name = std.ArrayList(u8).init(self.gpa); |
| ... | ... | @@ -1126,10 +1133,16 @@ pub const DeclGen = struct { |
| 1126 | 1133 | |
| 1127 | 1134 | var it = struct_type.iterateRuntimeOrder(ip); |
| 1128 | 1135 | while (it.next()) |field_index| { |
| 1129 | | const field_ty = struct_type.field_types.get(ip)[field_index]; |
| 1130 | | const field_name = ip.stringToSlice(struct_type.field_names.get(ip)[field_index]); |
| 1131 | | try member_types.append(try self.resolveType(field_ty.toType(), .indirect)); |
| 1132 | | try member_names.append(try self.spv.resolveString(field_name)); |
| 1136 | const field_ty = struct_type.field_types.get(ip)[field_index].toType(); |
| 1137 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1138 | // This is a zero-bit field - we only needed it for the alignment. |
| 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 | 1148 | const ty_ref = try self.spv.resolve(.{ .struct_type = .{ |