| ... | ... | @@ -32,12 +32,28 @@ const IncomingBlock = struct { |
| 32 | 32 | break_value_id: IdRef, |
| 33 | 33 | }; |
| 34 | 34 | |
| 35 | | pub const BlockMap = std.AutoHashMapUnmanaged(Air.Inst.Index, struct { |
| 35 | const BlockMap = std.AutoHashMapUnmanaged(Air.Inst.Index, struct { |
| 36 | 36 | label_id: IdRef, |
| 37 | 37 | incoming_blocks: *std.ArrayListUnmanaged(IncomingBlock), |
| 38 | 38 | }); |
| 39 | 39 | |
| 40 | | pub const DeclMap = std.AutoHashMap(Module.Decl.Index, IdResult); |
| 40 | /// Linking information about a particular decl. |
| 41 | /// The active field of this enum depends on the type of the corresponding decl. |
| 42 | const DeclLink = union { |
| 43 | /// Linking information about a function. |
| 44 | /// Active when the decl is a function. |
| 45 | func: struct { |
| 46 | /// Result-id of the OpFunction instruction. |
| 47 | result_id: IdResult, |
| 48 | }, |
| 49 | /// Linking information about a global. This index points into the |
| 50 | /// SPIR-V module's `globals` array. |
| 51 | /// Active when the decl is a variable. |
| 52 | global: SpvModule.Global.Index, |
| 53 | }; |
| 54 | |
| 55 | /// Maps Zig decl indices to linking SPIR-V linking information. |
| 56 | pub const DeclLinkMap = std.AutoHashMap(Module.Decl.Index, DeclLink); |
| 41 | 57 | |
| 42 | 58 | /// This structure is used to compile a declaration, and contains all relevant meta-information to deal with that. |
| 43 | 59 | pub const DeclGen = struct { |
| ... | ... | @@ -61,8 +77,8 @@ pub const DeclGen = struct { |
| 61 | 77 | /// Note: If the declaration is not a function, this value will be undefined! |
| 62 | 78 | liveness: Liveness, |
| 63 | 79 | |
| 64 | | /// Maps Zig Decl indices to SPIR-V result indices. |
| 65 | | decl_ids: *DeclMap, |
| 80 | /// Maps Zig Decl indices to SPIR-V globals. |
| 81 | decl_link: *DeclLinkMap, |
| 66 | 82 | |
| 67 | 83 | /// An array of function argument result-ids. Each index corresponds with the |
| 68 | 84 | /// function argument of the same index. |
| ... | ... | @@ -152,7 +168,7 @@ pub const DeclGen = struct { |
| 152 | 168 | allocator: Allocator, |
| 153 | 169 | module: *Module, |
| 154 | 170 | spv: *SpvModule, |
| 155 | | decl_ids: *DeclMap, |
| 171 | decl_link: *DeclLinkMap, |
| 156 | 172 | ) DeclGen { |
| 157 | 173 | return .{ |
| 158 | 174 | .gpa = allocator, |
| ... | ... | @@ -161,7 +177,7 @@ pub const DeclGen = struct { |
| 161 | 177 | .decl_index = undefined, |
| 162 | 178 | .air = undefined, |
| 163 | 179 | .liveness = undefined, |
| 164 | | .decl_ids = decl_ids, |
| 180 | .decl_link = decl_link, |
| 165 | 181 | .next_arg_index = undefined, |
| 166 | 182 | .current_block_label_id = undefined, |
| 167 | 183 | .error_msg = undefined, |
| ... | ... | @@ -235,7 +251,8 @@ pub const DeclGen = struct { |
| 235 | 251 | .function => val.castTag(.function).?.data.owner_decl, |
| 236 | 252 | else => unreachable, |
| 237 | 253 | }; |
| 238 | | return try self.resolveDecl(fn_decl_index); |
| 254 | const link = try self.resolveDecl(fn_decl_index); |
| 255 | return link.func.result_id; |
| 239 | 256 | } |
| 240 | 257 | |
| 241 | 258 | return try self.constant(ty, val); |
| ... | ... | @@ -246,17 +263,22 @@ pub const DeclGen = struct { |
| 246 | 263 | |
| 247 | 264 | /// Fetch or allocate a result id for decl index. This function also marks the decl as alive. |
| 248 | 265 | /// Note: Function does not actually generate the decl. |
| 249 | | fn resolveDecl(self: *DeclGen, decl_index: Module.Decl.Index) !IdResult { |
| 266 | fn resolveDecl(self: *DeclGen, decl_index: Module.Decl.Index) !DeclLink { |
| 250 | 267 | const decl = self.module.declPtr(decl_index); |
| 251 | 268 | self.module.markDeclAlive(decl); |
| 252 | 269 | |
| 253 | | const entry = try self.decl_ids.getOrPut(decl_index); |
| 254 | | if (entry.found_existing) { |
| 255 | | return entry.value_ptr.*; |
| 256 | | } |
| 270 | const entry = try self.decl_link.getOrPut(decl_index); |
| 257 | 271 | const result_id = self.spv.allocId(); |
| 258 | | entry.value_ptr.* = result_id; |
| 259 | | return result_id; |
| 272 | |
| 273 | if (!entry.found_existing) { |
| 274 | if (decl.val.castTag(.function)) |_| { |
| 275 | entry.value_ptr.* = .{.func = .{ .result_id = result_id }}; |
| 276 | } else { |
| 277 | entry.value_ptr.* = .{ .global = try self.spv.allocGlobal() }; |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | return entry.value_ptr.*; |
| 260 | 282 | } |
| 261 | 283 | |
| 262 | 284 | /// Start a new SPIR-V block, Emits the label of the new block, and stores which |
| ... | ... | @@ -363,7 +385,7 @@ pub const DeclGen = struct { |
| 363 | 385 | // As of yet, there is no vector support in the self-hosted compiler. |
| 364 | 386 | .Vector => self.todo("implement arithmeticTypeInfo for Vector", .{}), |
| 365 | 387 | // TODO: For which types is this the case? |
| 366 | | else => self.todo("implement arithmeticTypeInfo for {}", .{ty.fmtDebug()}), |
| 388 | else => self.todo("implement arithmeticTypeInfo for {}", .{ty.fmt(self.module)}), |
| 367 | 389 | }; |
| 368 | 390 | } |
| 369 | 391 | |
| ... | ... | @@ -399,7 +421,7 @@ pub const DeclGen = struct { |
| 399 | 421 | try self.spv.sections.types_globals_constants.emit( |
| 400 | 422 | self.spv.gpa, |
| 401 | 423 | .OpUndef, |
| 402 | | .{ .id_result_type = self.typeId(ty_ref), .id_result = result_id }, |
| 424 | .{ .id_result_type = self.typeId(ty_ref), .id_result = result_id } |
| 403 | 425 | ); |
| 404 | 426 | return result_id; |
| 405 | 427 | } |
| ... | ... | @@ -423,6 +445,11 @@ pub const DeclGen = struct { |
| 423 | 445 | /// If full, its flushed. |
| 424 | 446 | partial_word: std.BoundedArray(u8, @sizeOf(Word)) = .{}, |
| 425 | 447 | |
| 448 | /// Utility function to get the section that instructions should be lowered to. |
| 449 | fn section(self: *@This()) *SpvSection { |
| 450 | return &self.dg.spv.globals.section; |
| 451 | } |
| 452 | |
| 426 | 453 | /// Flush the partial_word to the members. If the partial_word is not |
| 427 | 454 | /// filled, this adds padding bytes (which are undefined). |
| 428 | 455 | fn flush(self: *@This()) !void { |
| ... | ... | @@ -438,6 +465,7 @@ pub const DeclGen = struct { |
| 438 | 465 | |
| 439 | 466 | const word = @bitCast(Word, self.partial_word.buffer); |
| 440 | 467 | const result_id = self.dg.spv.allocId(); |
| 468 | // TODO: Integrate with caching mechanism |
| 441 | 469 | try self.dg.spv.emitConstant(self.u32_ty_id, result_id, .{ .uint32 = word }); |
| 442 | 470 | try self.members.append(.{ .ty = self.u32_ty_ref }); |
| 443 | 471 | try self.initializers.append(result_id); |
| ... | ... | @@ -523,10 +551,52 @@ pub const DeclGen = struct { |
| 523 | 551 | try self.addBytes(std.mem.asBytes(&int_bits)[0..@intCast(usize, len)]); |
| 524 | 552 | } |
| 525 | 553 | |
| 554 | fn addDeclRef(self: *@This(), ty: Type, decl_index: Decl.Index) !void { |
| 555 | const dg = self.dg; |
| 556 | |
| 557 | const ty_ref = try self.dg.resolveType(ty, .indirect); |
| 558 | const ty_id = dg.typeId(ty_ref); |
| 559 | |
| 560 | const decl = dg.module.declPtr(decl_index); |
| 561 | const link = try dg.resolveDecl(decl_index); |
| 562 | |
| 563 | switch (decl.val.tag()) { |
| 564 | .function => { |
| 565 | // TODO: Properly lower function pointers. For now we are going to hack around it and |
| 566 | // just generate an empty pointer. Function pointers are represented by usize for now, |
| 567 | // though. |
| 568 | try self.addInt(Type.usize, Value.initTag(.zero)); |
| 569 | return; |
| 570 | }, |
| 571 | .extern_fn => unreachable, // TODO |
| 572 | else => { |
| 573 | const result_id = dg.spv.allocId(); |
| 574 | log.debug("addDeclRef {s} = {}", .{ decl.name, result_id.id }); |
| 575 | |
| 576 | const global = dg.spv.globalPtr(link.global); |
| 577 | try dg.spv.addGlobalDependency(link.global); |
| 578 | // TODO: Do we need a storage class cast here? |
| 579 | // TODO: We can probably eliminate these casts |
| 580 | try dg.spv.globals.section.emitSpecConstantOp(dg.spv.gpa, .OpBitcast, .{ |
| 581 | .id_result_type = ty_id, |
| 582 | .id_result = result_id, |
| 583 | .operand = global.result_id, |
| 584 | }); |
| 585 | |
| 586 | try self.addPtr(ty_ref, result_id); |
| 587 | }, |
| 588 | } |
| 589 | } |
| 590 | |
| 526 | 591 | fn lower(self: *@This(), ty: Type, val: Value) !void { |
| 527 | 592 | const target = self.dg.getTarget(); |
| 528 | 593 | const dg = self.dg; |
| 529 | 594 | |
| 595 | if (val.isUndef()) { |
| 596 | const size = ty.abiSize(target); |
| 597 | return try self.addUndef(size); |
| 598 | } |
| 599 | |
| 530 | 600 | switch (ty.zigTypeTag()) { |
| 531 | 601 | .Int => try self.addInt(ty, val), |
| 532 | 602 | .Bool => try self.addConstBool(val.toBool()), |
| ... | ... | @@ -558,22 +628,20 @@ pub const DeclGen = struct { |
| 558 | 628 | try self.addByte(@intCast(u8, sentinel.toUnsignedInt(target))); |
| 559 | 629 | } |
| 560 | 630 | }, |
| 631 | .bytes => { |
| 632 | const bytes = val.castTag(.bytes).?.data; |
| 633 | try self.addBytes(bytes); |
| 634 | }, |
| 561 | 635 | else => |tag| return dg.todo("indirect array constant with tag {s}", .{@tagName(tag)}), |
| 562 | 636 | }, |
| 563 | 637 | .Pointer => switch (val.tag()) { |
| 564 | 638 | .decl_ref_mut => { |
| 565 | | const ptr_ty_ref = try dg.resolveType(ty, .indirect); |
| 566 | | const ptr_id = dg.spv.allocId(); |
| 567 | 639 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; |
| 568 | | try dg.genDeclRef(ptr_ty_ref, ptr_id, decl_index); |
| 569 | | try self.addPtr(ptr_ty_ref, ptr_id); |
| 640 | try self.addDeclRef(ty, decl_index); |
| 570 | 641 | }, |
| 571 | 642 | .decl_ref => { |
| 572 | | const ptr_ty_ref = try dg.resolveType(ty, .indirect); |
| 573 | | const ptr_id = dg.spv.allocId(); |
| 574 | 643 | const decl_index = val.castTag(.decl_ref).?.data; |
| 575 | | try dg.genDeclRef(ptr_ty_ref, ptr_id, decl_index); |
| 576 | | try self.addPtr(ptr_ty_ref, ptr_id); |
| 644 | try self.addDeclRef(ty, decl_index); |
| 577 | 645 | }, |
| 578 | 646 | .slice => { |
| 579 | 647 | const slice = val.castTag(.slice).?.data; |
| ... | ... | @@ -730,22 +798,31 @@ pub const DeclGen = struct { |
| 730 | 798 | // - Underaligned pointers. These need to be packed into the word array by using a mixture of |
| 731 | 799 | // OpSpecConstantOp instructions such as OpConvertPtrToU, OpBitcast, OpShift, etc. |
| 732 | 800 | |
| 733 | | log.debug("lowerIndirectConstant: ty = {}, val = {}", .{ ty.fmtDebug(), val.fmtDebug() }); |
| 801 | assert(storage_class != .Generic and storage_class != .Function); |
| 734 | 802 | |
| 735 | | const constant_section = &self.spv.sections.types_globals_constants; |
| 803 | log.debug("lowerIndirectConstant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtDebug() }); |
| 804 | |
| 805 | const section = &self.spv.globals.section; |
| 736 | 806 | |
| 737 | 807 | const ty_ref = try self.resolveType(ty, .indirect); |
| 738 | 808 | const ptr_ty_ref = try self.spv.ptrType(ty_ref, storage_class, alignment); |
| 739 | 809 | |
| 810 | const target = self.getTarget(); |
| 811 | |
| 740 | 812 | if (val.isUndef()) { |
| 741 | 813 | // Special case: the entire value is undefined. In this case, we can just |
| 742 | 814 | // generate an OpVariable with no initializer. |
| 743 | | try constant_section.emit(self.spv.gpa, .OpVariable, .{ |
| 815 | return try section.emit(self.spv.gpa, .OpVariable, .{ |
| 744 | 816 | .id_result_type = self.typeId(ptr_ty_ref), |
| 745 | 817 | .id_result = result_id, |
| 746 | 818 | .storage_class = storage_class, |
| 747 | 819 | }); |
| 748 | | return; |
| 820 | } else if (ty.abiSize(target) == 0) { |
| 821 | // Special case: if the type has no size, then return an undefined pointer. |
| 822 | return try section.emit(self.spv.gpa, .OpUndef, .{ |
| 823 | .id_result_type = self.typeId(ptr_ty_ref), |
| 824 | .id_result = result_id, |
| 825 | }); |
| 749 | 826 | } |
| 750 | 827 | |
| 751 | 828 | const u32_ty_ref = try self.intType(.unsigned, 32); |
| ... | ... | @@ -757,62 +834,42 @@ pub const DeclGen = struct { |
| 757 | 834 | .initializers = std.ArrayList(IdRef).init(self.gpa), |
| 758 | 835 | }; |
| 759 | 836 | |
| 760 | | try icl.lower(ty, val); |
| 761 | | try icl.flush(); |
| 762 | | |
| 763 | 837 | defer icl.members.deinit(); |
| 764 | 838 | defer icl.initializers.deinit(); |
| 765 | 839 | |
| 840 | try icl.lower(ty, val); |
| 841 | try icl.flush(); |
| 842 | |
| 766 | 843 | const constant_struct_ty_ref = try self.spv.simpleStructType(icl.members.items); |
| 767 | 844 | const ptr_constant_struct_ty_ref = try self.spv.ptrType(constant_struct_ty_ref, storage_class, alignment); |
| 768 | 845 | |
| 769 | 846 | const constant_struct_id = self.spv.allocId(); |
| 770 | | try constant_section.emit(self.spv.gpa, .OpSpecConstantComposite, .{ |
| 847 | try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{ |
| 771 | 848 | .id_result_type = self.typeId(constant_struct_ty_ref), |
| 772 | 849 | .id_result = constant_struct_id, |
| 773 | 850 | .constituents = icl.initializers.items, |
| 774 | 851 | }); |
| 775 | 852 | |
| 776 | 853 | const var_id = self.spv.allocId(); |
| 777 | | switch (storage_class) { |
| 778 | | .Generic => unreachable, |
| 779 | | .Function => { |
| 780 | | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| 781 | | .id_result_type = self.typeId(ptr_constant_struct_ty_ref), |
| 782 | | .id_result = var_id, |
| 783 | | .storage_class = storage_class, |
| 784 | | .initializer = constant_struct_id, |
| 785 | | }); |
| 786 | | // TODO: Set alignment of OpVariable. |
| 787 | | |
| 788 | | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| 789 | | .id_result_type = self.typeId(ptr_ty_ref), |
| 790 | | .id_result = result_id, |
| 791 | | .operand = var_id, |
| 792 | | }); |
| 793 | | }, |
| 794 | | else => { |
| 795 | | try constant_section.emit(self.spv.gpa, .OpVariable, .{ |
| 796 | | .id_result_type = self.typeId(ptr_constant_struct_ty_ref), |
| 797 | | .id_result = var_id, |
| 798 | | .storage_class = storage_class, |
| 799 | | .initializer = constant_struct_id, |
| 800 | | }); |
| 801 | | // TODO: Set alignment of OpVariable. |
| 802 | | |
| 803 | | try constant_section.emitSpecConstantOp(self.spv.gpa, .OpBitcast, .{ |
| 804 | | .id_result_type = self.typeId(ptr_ty_ref), |
| 805 | | .id_result = result_id, |
| 806 | | .operand = var_id, |
| 807 | | }); |
| 808 | | }, |
| 809 | | } |
| 854 | try section.emit(self.spv.gpa, .OpVariable, .{ |
| 855 | .id_result_type = self.typeId(ptr_constant_struct_ty_ref), |
| 856 | .id_result = var_id, |
| 857 | .storage_class = storage_class, |
| 858 | .initializer = constant_struct_id, |
| 859 | }); |
| 860 | // TODO: Set alignment of OpVariable. |
| 861 | // TODO: We may be able to eliminate this cast. |
| 862 | try section.emitSpecConstantOp(self.spv.gpa, .OpBitcast, .{ |
| 863 | .id_result_type = self.typeId(ptr_ty_ref), |
| 864 | .id_result = result_id, |
| 865 | .operand = var_id, |
| 866 | }); |
| 810 | 867 | } |
| 811 | 868 | |
| 812 | 869 | /// This function generates a load for a constant in direct (ie, non-memory) representation. |
| 813 | 870 | /// When the constant is simple, it can be generated directly using OpConstant instructions. When |
| 814 | 871 | /// the constant is more complicated however, it needs to be lowered to an indirect constant, which |
| 815 | | /// is then loaded using OpLoad. Such values are loaded into the Function address space by default. |
| 872 | /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default. |
| 816 | 873 | /// This function should only be called during function code generation. |
| 817 | 874 | fn constant(self: *DeclGen, ty: Type, val: Value) !IdRef { |
| 818 | 875 | const target = self.getTarget(); |
| ... | ... | @@ -846,53 +903,27 @@ pub const DeclGen = struct { |
| 846 | 903 | } |
| 847 | 904 | }, |
| 848 | 905 | else => { |
| 849 | | // The value cannot be generated directly, so generate it as an indirect function-local |
| 850 | | // constant, and then perform an OpLoad. |
| 851 | | const ptr_id = self.spv.allocId(); |
| 906 | // The value cannot be generated directly, so generate it as an indirect constant, |
| 907 | // and then perform an OpLoad. |
| 852 | 908 | const alignment = ty.abiAlignment(target); |
| 853 | | try self.lowerIndirectConstant(ptr_id, ty, val, .Function, alignment); |
| 909 | const global_index = try self.spv.allocGlobal(); |
| 910 | log.debug("constant {}", .{global_index}); |
| 911 | const ptr_id = self.spv.beginGlobal(global_index); |
| 912 | defer self.spv.endGlobal(); |
| 913 | try self.lowerIndirectConstant(ptr_id, ty, val, .UniformConstant, alignment); |
| 854 | 914 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| 855 | 915 | .id_result_type = result_ty_id, |
| 856 | 916 | .id_result = result_id, |
| 857 | 917 | .pointer = ptr_id, |
| 858 | 918 | }); |
| 859 | | // TODO: Convert bools? This logic should hook into `load`. |
| 919 | // TODO: Convert bools? This logic should hook into `load`. It should be a dead |
| 920 | // path though considering .Bool is handled above. |
| 860 | 921 | }, |
| 861 | 922 | } |
| 862 | 923 | |
| 863 | 924 | return result_id; |
| 864 | 925 | } |
| 865 | 926 | |
| 866 | | fn genDeclRef(self: *DeclGen, result_ty_ref: SpvType.Ref, result_id: IdRef, decl_index: Decl.Index) Error!void { |
| 867 | | // TODO: Clean up |
| 868 | | const decl = self.module.declPtr(decl_index); |
| 869 | | self.module.markDeclAlive(decl); |
| 870 | | // _ = result_ty_ref; |
| 871 | | // const decl_id = try self.constant(decl.ty, decl.val, .indirect); |
| 872 | | // try self.variable(.global, result_id, result_ty_ref, decl_id); |
| 873 | | const result_storage_class = self.spv.typeRefType(result_ty_ref).payload(.pointer).storage_class; |
| 874 | | const indirect_result_id = if (result_storage_class != .CrossWorkgroup) |
| 875 | | self.spv.allocId() |
| 876 | | else |
| 877 | | result_id; |
| 878 | | |
| 879 | | try self.lowerIndirectConstant( |
| 880 | | indirect_result_id, |
| 881 | | decl.ty, |
| 882 | | decl.val, |
| 883 | | .CrossWorkgroup, // TODO: Make this .Function if required |
| 884 | | decl.@"align", |
| 885 | | ); |
| 886 | | const section = &self.spv.sections.types_globals_constants; |
| 887 | | if (result_storage_class != .CrossWorkgroup) { |
| 888 | | try section.emitSpecConstantOp(self.spv.gpa, .OpPtrCastToGeneric, .{ |
| 889 | | .id_result_type = self.typeId(result_ty_ref), |
| 890 | | .id_result = result_id, |
| 891 | | .pointer = indirect_result_id, |
| 892 | | }); |
| 893 | | } |
| 894 | | } |
| 895 | | |
| 896 | 927 | /// Turn a Zig type into a SPIR-V Type, and return its type result-id. |
| 897 | 928 | fn resolveTypeId(self: *DeclGen, ty: Type) !IdResultType { |
| 898 | 929 | const type_ref = try self.resolveType(ty, .direct); |
| ... | ... | @@ -996,7 +1027,7 @@ pub const DeclGen = struct { |
| 996 | 1027 | |
| 997 | 1028 | /// Turn a Zig type into a SPIR-V Type, and return a reference to it. |
| 998 | 1029 | fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!SpvType.Ref { |
| 999 | | log.debug("resolveType: ty = {}", .{ty.fmtDebug()}); |
| 1030 | log.debug("resolveType: ty = {}", .{ty.fmt(self.module)}); |
| 1000 | 1031 | const target = self.getTarget(); |
| 1001 | 1032 | switch (ty.zigTypeTag()) { |
| 1002 | 1033 | .Void, .NoReturn => return try self.spv.resolveType(SpvType.initTag(.void)), |
| ... | ... | @@ -1042,23 +1073,30 @@ pub const DeclGen = struct { |
| 1042 | 1073 | }; |
| 1043 | 1074 | return try self.spv.arrayType(total_len, elem_ty_ref); |
| 1044 | 1075 | }, |
| 1045 | | .Fn => { |
| 1046 | | // TODO: Put this somewhere in Sema.zig |
| 1047 | | if (ty.fnIsVarArgs()) |
| 1048 | | return self.fail("VarArgs functions are unsupported for SPIR-V", .{}); |
| 1076 | .Fn => switch (repr) { |
| 1077 | .direct => { |
| 1078 | // TODO: Put this somewhere in Sema.zig |
| 1079 | if (ty.fnIsVarArgs()) |
| 1080 | return self.fail("VarArgs functions are unsupported for SPIR-V", .{}); |
| 1049 | 1081 | |
| 1050 | | // TODO: Parameter passing convention etc. |
| 1082 | // TODO: Parameter passing convention etc. |
| 1051 | 1083 | |
| 1052 | | const param_types = try self.spv.arena.alloc(SpvType.Ref, ty.fnParamLen()); |
| 1053 | | for (param_types, 0..) |*param, i| { |
| 1054 | | param.* = try self.resolveType(ty.fnParamType(i), .direct); |
| 1055 | | } |
| 1084 | const param_types = try self.spv.arena.alloc(SpvType.Ref, ty.fnParamLen()); |
| 1085 | for (param_types, 0..) |*param, i| { |
| 1086 | param.* = try self.resolveType(ty.fnParamType(i), .direct); |
| 1087 | } |
| 1056 | 1088 | |
| 1057 | | const return_type = try self.resolveType(ty.fnReturnType(), .direct); |
| 1089 | const return_type = try self.resolveType(ty.fnReturnType(), .direct); |
| 1058 | 1090 | |
| 1059 | | const payload = try self.spv.arena.create(SpvType.Payload.Function); |
| 1060 | | payload.* = .{ .return_type = return_type, .parameters = param_types }; |
| 1061 | | return try self.spv.resolveType(SpvType.initPayload(&payload.base)); |
| 1091 | const payload = try self.spv.arena.create(SpvType.Payload.Function); |
| 1092 | payload.* = .{ .return_type = return_type, .parameters = param_types }; |
| 1093 | return try self.spv.resolveType(SpvType.initPayload(&payload.base)); |
| 1094 | }, |
| 1095 | .indirect => { |
| 1096 | // TODO: Represent function pointers properly. |
| 1097 | // For now, just use an usize type. |
| 1098 | return try self.sizeType(); |
| 1099 | }, |
| 1062 | 1100 | }, |
| 1063 | 1101 | .Pointer => { |
| 1064 | 1102 | const ptr_info = ty.ptrInfo().data; |
| ... | ... | @@ -1196,14 +1234,16 @@ pub const DeclGen = struct { |
| 1196 | 1234 | |
| 1197 | 1235 | fn genDecl(self: *DeclGen) !void { |
| 1198 | 1236 | const decl = self.module.declPtr(self.decl_index); |
| 1199 | | const result_id = try self.resolveDecl(self.decl_index); |
| 1237 | const link = try self.resolveDecl(self.decl_index); |
| 1200 | 1238 | |
| 1201 | 1239 | if (decl.val.castTag(.function)) |_| { |
| 1240 | log.debug("genDecl function {s} = {}", .{decl.name, link.func.result_id.id}); |
| 1241 | |
| 1202 | 1242 | assert(decl.ty.zigTypeTag() == .Fn); |
| 1203 | 1243 | const prototype_id = try self.resolveTypeId(decl.ty); |
| 1204 | 1244 | try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{ |
| 1205 | 1245 | .id_result_type = try self.resolveTypeId(decl.ty.fnReturnType()), |
| 1206 | | .id_result = result_id, |
| 1246 | .id_result = link.func.result_id, |
| 1207 | 1247 | .function_control = .{}, // TODO: We can set inline here if the type requires it. |
| 1208 | 1248 | .function_type = prototype_id, |
| 1209 | 1249 | }); |
| ... | ... | @@ -1243,7 +1283,7 @@ pub const DeclGen = struct { |
| 1243 | 1283 | defer self.module.gpa.free(fqn); |
| 1244 | 1284 | |
| 1245 | 1285 | try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ |
| 1246 | | .target = result_id, |
| 1286 | .target = link.func.result_id, |
| 1247 | 1287 | .name = fqn, |
| 1248 | 1288 | }); |
| 1249 | 1289 | } else { |
| ... | ... | @@ -1264,9 +1304,13 @@ pub const DeclGen = struct { |
| 1264 | 1304 | else => storage_class, |
| 1265 | 1305 | }; |
| 1266 | 1306 | |
| 1307 | const global_result_id = self.spv.beginGlobal(link.global); |
| 1308 | defer self.spv.endGlobal(); |
| 1309 | log.debug("genDecl {}", .{link.global}); |
| 1310 | |
| 1267 | 1311 | const var_result_id = switch (storage_class) { |
| 1268 | 1312 | .Generic => self.spv.allocId(), |
| 1269 | | else => result_id, |
| 1313 | else => global_result_id, |
| 1270 | 1314 | }; |
| 1271 | 1315 | |
| 1272 | 1316 | try self.lowerIndirectConstant( |
| ... | ... | @@ -1278,12 +1322,13 @@ pub const DeclGen = struct { |
| 1278 | 1322 | ); |
| 1279 | 1323 | |
| 1280 | 1324 | if (storage_class == .Generic) { |
| 1281 | | const section = &self.spv.sections.types_globals_constants; |
| 1325 | const section = &self.spv.globals.section; |
| 1282 | 1326 | const ty_ref = try self.resolveType(decl.ty, .indirect); |
| 1283 | 1327 | const ptr_ty_ref = try self.spv.ptrType(ty_ref, storage_class, decl.@"align"); |
| 1328 | // TODO: Can we eliminate this cast? |
| 1284 | 1329 | try section.emitSpecConstantOp(self.spv.gpa, .OpPtrCastToGeneric, .{ |
| 1285 | 1330 | .id_result_type = self.typeId(ptr_ty_ref), |
| 1286 | | .id_result = result_id, |
| 1331 | .id_result = global_result_id, |
| 1287 | 1332 | .pointer = var_result_id, |
| 1288 | 1333 | }); |
| 1289 | 1334 | } |
| ... | ... | @@ -1972,6 +2017,7 @@ pub const DeclGen = struct { |
| 1972 | 2017 | .id_result = result_id, |
| 1973 | 2018 | .pointer = alloc_result_id, |
| 1974 | 2019 | }), |
| 2020 | // TODO: Can we do without this cast or move it to runtime? |
| 1975 | 2021 | else => try section.emitSpecConstantOp(self.spv.gpa, .OpPtrCastToGeneric, .{ |
| 1976 | 2022 | .id_result_type = self.typeId(ptr_ty_ref), |
| 1977 | 2023 | .id_result = result_id, |