| ... | @@ -2,7 +2,6 @@ const std = @import("std"); | ... | @@ -2,7 +2,6 @@ const std = @import("std"); |
| 2 | const mem = std.mem; | 2 | const mem = std.mem; |
| 3 | const Allocator = std.mem.Allocator; | 3 | const Allocator = std.mem.Allocator; |
| 4 | const ArrayListUnmanaged = std.ArrayListUnmanaged; | 4 | const ArrayListUnmanaged = std.ArrayListUnmanaged; |
| 5 | const LinkedList = std.TailQueue; | | |
| 6 | const Value = @import("value.zig").Value; | 5 | const Value = @import("value.zig").Value; |
| 7 | const Type = @import("type.zig").Type; | 6 | const Type = @import("type.zig").Type; |
| 8 | const TypedValue = @import("TypedValue.zig"); | 7 | const TypedValue = @import("TypedValue.zig"); |
| ... | @@ -168,17 +167,6 @@ pub const Inst = struct { | ... | @@ -168,17 +167,6 @@ pub const Inst = struct { |
| 168 | }; | 167 | }; |
| 169 | }; | 168 | }; |
| 170 | | 169 | |
| 171 | fn swapRemoveElem(allocator: *Allocator, comptime T: type, item: T, list: *ArrayListUnmanaged(T)) void { | | |
| 172 | var i: usize = 0; | | |
| 173 | while (i < list.items.len) { | | |
| 174 | if (list.items[i] == item) { | | |
| 175 | list.swapRemove(allocator, i); | | |
| 176 | continue; | | |
| 177 | } | | |
| 178 | i += 1; | | |
| 179 | } | | |
| 180 | } | | |
| 181 | | | |
| 182 | pub const Module = struct { | 170 | pub const Module = struct { |
| 183 | /// General-purpose allocator. | 171 | /// General-purpose allocator. |
| 184 | allocator: *Allocator, | 172 | allocator: *Allocator, |
| ... | @@ -203,6 +191,8 @@ pub const Module = struct { | ... | @@ -203,6 +191,8 @@ pub const Module = struct { |
| 203 | optimize_mode: std.builtin.Mode, | 191 | optimize_mode: std.builtin.Mode, |
| 204 | link_error_flags: link.ElfFile.ErrorFlags = link.ElfFile.ErrorFlags{}, | 192 | link_error_flags: link.ElfFile.ErrorFlags = link.ElfFile.ErrorFlags{}, |
| 205 | | 193 | |
| | 194 | work_stack: ArrayListUnmanaged(WorkItem) = ArrayListUnmanaged(WorkItem){}, |
| | 195 | |
| 206 | /// We optimize memory usage for a compilation with no compile errors by storing the | 196 | /// We optimize memory usage for a compilation with no compile errors by storing the |
| 207 | /// error messages and mapping outside of `Decl`. | 197 | /// error messages and mapping outside of `Decl`. |
| 208 | /// The ErrorMsg memory is owned by the decl, using Module's allocator. | 198 | /// The ErrorMsg memory is owned by the decl, using Module's allocator. |
| ... | @@ -218,6 +208,11 @@ pub const Module = struct { | ... | @@ -218,6 +208,11 @@ pub const Module = struct { |
| 218 | /// The ErrorMsg memory is owned by the `Export`, using Module's allocator. | 208 | /// The ErrorMsg memory is owned by the `Export`, using Module's allocator. |
| 219 | failed_exports: std.AutoHashMap(*Export, *ErrorMsg), | 209 | failed_exports: std.AutoHashMap(*Export, *ErrorMsg), |
| 220 | | 210 | |
| | 211 | pub const WorkItem = union(enum) { |
| | 212 | /// Write the machine code for a Decl to the output file. |
| | 213 | codegen_decl: *Decl, |
| | 214 | }; |
| | 215 | |
| 221 | pub const Export = struct { | 216 | pub const Export = struct { |
| 222 | options: std.builtin.ExportOptions, | 217 | options: std.builtin.ExportOptions, |
| 223 | /// Byte offset into the file that contains the export directive. | 218 | /// Byte offset into the file that contains the export directive. |
| ... | @@ -322,11 +317,13 @@ pub const Module = struct { | ... | @@ -322,11 +317,13 @@ pub const Module = struct { |
| 322 | } | 317 | } |
| 323 | }; | 318 | }; |
| 324 | | 319 | |
| 325 | /// Memory is managed by the arena of the owning Decl. | 320 | /// Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator. |
| 326 | pub const Fn = struct { | 321 | pub const Fn = struct { |
| | 322 | /// This memory owned by the Decl's TypedValue.Managed arena allocator. |
| 327 | fn_type: Type, | 323 | fn_type: Type, |
| 328 | analysis: union(enum) { | 324 | analysis: union(enum) { |
| 329 | queued, | 325 | /// The value is the source instruction. |
| | 326 | queued: *text.Inst.Fn, |
| 330 | in_progress: *Analysis, | 327 | in_progress: *Analysis, |
| 331 | /// There will be a corresponding ErrorMsg in Module.failed_fns | 328 | /// There will be a corresponding ErrorMsg in Module.failed_fns |
| 332 | failure, | 329 | failure, |
| ... | @@ -336,11 +333,14 @@ pub const Module = struct { | ... | @@ -336,11 +333,14 @@ pub const Module = struct { |
| 336 | /// self-hosted supports proper struct types and Zig AST => ZIR. | 333 | /// self-hosted supports proper struct types and Zig AST => ZIR. |
| 337 | scope: *Scope.ZIRModule, | 334 | scope: *Scope.ZIRModule, |
| 338 | | 335 | |
| 339 | /// This memory managed by the general purpose allocator. | 336 | /// This memory is temporary and points to stack memory for the duration |
| | 337 | /// of Fn analysis. |
| 340 | pub const Analysis = struct { | 338 | pub const Analysis = struct { |
| 341 | inner_block: Scope.Block, | 339 | inner_block: Scope.Block, |
| 342 | /// null value means a semantic analysis error happened. | 340 | /// null value means a semantic analysis error happened. |
| 343 | inst_table: std.AutoHashMap(*text.Inst, ?*Inst), | 341 | inst_table: std.AutoHashMap(*text.Inst, ?*Inst), |
| | 342 | /// Owns the memory for instructions |
| | 343 | arena: std.heap.ArenaAllocator, |
| 344 | }; | 344 | }; |
| 345 | }; | 345 | }; |
| 346 | | 346 | |
| ... | @@ -354,6 +354,26 @@ pub const Module = struct { | ... | @@ -354,6 +354,26 @@ pub const Module = struct { |
| 354 | return @fieldParentPtr(T, "base", base); | 354 | return @fieldParentPtr(T, "base", base); |
| 355 | } | 355 | } |
| 356 | | 356 | |
| | 357 | /// Asserts the scope has a parent which is a DeclAnalysis and |
| | 358 | /// returns the arena Allocator. |
| | 359 | pub fn arena(self: *Scope) *Allocator { |
| | 360 | switch (self.tag) { |
| | 361 | .block => return self.cast(Block).?.arena, |
| | 362 | .decl => return &self.cast(DeclAnalysis).?.arena.allocator, |
| | 363 | .zir_module => unreachable, |
| | 364 | } |
| | 365 | } |
| | 366 | |
| | 367 | /// Asserts the scope has a parent which is a DeclAnalysis and |
| | 368 | /// returns the Decl. |
| | 369 | pub fn decl(self: *Scope) *Decl { |
| | 370 | switch (self.tag) { |
| | 371 | .block => return self.cast(Block).?.decl, |
| | 372 | .decl => return self.cast(DeclAnalysis).?.decl, |
| | 373 | .zir_module => unreachable, |
| | 374 | } |
| | 375 | } |
| | 376 | |
| 357 | pub const Tag = enum { | 377 | pub const Tag = enum { |
| 358 | zir_module, | 378 | zir_module, |
| 359 | block, | 379 | block, |
| ... | @@ -404,7 +424,10 @@ pub const Module = struct { | ... | @@ -404,7 +424,10 @@ pub const Module = struct { |
| 404 | pub const base_tag: Tag = .block; | 424 | pub const base_tag: Tag = .block; |
| 405 | base: Scope = Scope{ .tag = base_tag }, | 425 | base: Scope = Scope{ .tag = base_tag }, |
| 406 | func: *Fn, | 426 | func: *Fn, |
| | 427 | decl: *Decl, |
| 407 | instructions: ArrayListUnmanaged(*Inst), | 428 | instructions: ArrayListUnmanaged(*Inst), |
| | 429 | /// Points to the arena allocator of DeclAnalysis |
| | 430 | arena: *Allocator, |
| 408 | }; | 431 | }; |
| 409 | | 432 | |
| 410 | /// This is a temporary structure, references to it are valid only | 433 | /// This is a temporary structure, references to it are valid only |
| ... | @@ -413,6 +436,7 @@ pub const Module = struct { | ... | @@ -413,6 +436,7 @@ pub const Module = struct { |
| 413 | pub const base_tag: Tag = .decl; | 436 | pub const base_tag: Tag = .decl; |
| 414 | base: Scope = Scope{ .tag = base_tag }, | 437 | base: Scope = Scope{ .tag = base_tag }, |
| 415 | decl: *Decl, | 438 | decl: *Decl, |
| | 439 | arena: std.heap.ArenaAllocator, |
| 416 | }; | 440 | }; |
| 417 | }; | 441 | }; |
| 418 | | 442 | |
| ... | @@ -616,21 +640,62 @@ pub const Module = struct { | ... | @@ -616,21 +640,62 @@ pub const Module = struct { |
| 616 | | 640 | |
| 617 | // Here we ensure enough queue capacity to store all the decls, so that later we can use | 641 | // Here we ensure enough queue capacity to store all the decls, so that later we can use |
| 618 | // appendAssumeCapacity. | 642 | // appendAssumeCapacity. |
| 619 | try self.analysis_queue.ensureCapacity(self.analysis_queue.items.len + contents.module.decls.len); | 643 | try self.work_stack.ensureCapacity( |
| | 644 | self.allocator, |
| | 645 | self.work_stack.items.len + src_module.decls.len, |
| | 646 | ); |
| 620 | | 647 | |
| 621 | for (contents.module.decls) |decl| { | 648 | for (src_module.decls) |decl| { |
| 622 | if (decl.cast(text.Inst.Export)) |export_inst| { | 649 | if (decl.cast(text.Inst.Export)) |export_inst| { |
| 623 | try analyzeExport(self, &root_scope.base, export_inst); | 650 | try analyzeExport(self, &root_scope.base, export_inst); |
| 624 | } | 651 | } |
| 625 | } | 652 | } |
| 626 | | 653 | |
| 627 | while (self.analysis_queue.popOrNull()) |work_item| { | 654 | while (self.work_stack.pop()) |work_item| switch (work_item) { |
| 628 | switch (work_item) { | 655 | .codegen_decl => |decl| switch (decl.analysis) { |
| 629 | .decl => |decl| switch (decl.analysis) { | 656 | .success => { |
| 630 | .success => try self.bin_file.updateDecl(self, decl), | 657 | if (decl.typed_value.most_recent.typed_value.val.cast(Value.Function)) |payload| { |
| | 658 | switch (payload.func.analysis) { |
| | 659 | .queued => self.analyzeFnBody(decl, payload.func) catch |err| switch (err) { |
| | 660 | error.AnalysisFail => { |
| | 661 | assert(func_payload.func.analysis == .failure); |
| | 662 | continue; |
| | 663 | }, |
| | 664 | else => |e| return e, |
| | 665 | }, |
| | 666 | .in_progress => unreachable, |
| | 667 | .failure => continue, |
| | 668 | .success => {}, |
| | 669 | } |
| | 670 | } |
| | 671 | try self.bin_file.updateDecl(self, decl); |
| 631 | }, | 672 | }, |
| 632 | } | 673 | }, |
| 633 | } | 674 | }; |
| | 675 | } |
| | 676 | |
| | 677 | fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { |
| | 678 | // Use the Decl's arena for function memory. |
| | 679 | var arena = decl.typed_value.most_recent.arena.?.promote(self.allocator); |
| | 680 | defer decl.typed_value.most_recent.arena.?.* = arena.state; |
| | 681 | var analysis: Analysis = .{ |
| | 682 | .inner_block = .{ |
| | 683 | .func = func, |
| | 684 | .decl = decl, |
| | 685 | .instructions = .{}, |
| | 686 | .arena = &arena.allocator, |
| | 687 | }, |
| | 688 | .inst_table = std.AutoHashMap(*text.Inst, ?*Inst).init(self.allocator), |
| | 689 | }; |
| | 690 | defer analysis.inner_block.instructions.deinit(); |
| | 691 | defer analysis.inst_table.deinit(); |
| | 692 | |
| | 693 | const fn_inst = func.analysis.queued; |
| | 694 | func.analysis = .{ .in_progress = &analysis }; |
| | 695 | |
| | 696 | try self.analyzeBody(&analysis.inner_block, fn_inst.positionals.body); |
| | 697 | |
| | 698 | func.analysis = .{ .success = .{ .instructions = analysis.inner_block.instructions.toOwnedSlice() } }; |
| 634 | } | 699 | } |
| 635 | | 700 | |
| 636 | fn resolveDecl(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Decl { | 701 | fn resolveDecl(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Decl { |
| ... | @@ -656,19 +721,27 @@ pub const Module = struct { | ... | @@ -656,19 +721,27 @@ pub const Module = struct { |
| 656 | }; | 721 | }; |
| 657 | | 722 | |
| 658 | var decl_scope: Scope.DeclAnalysis = .{ | 723 | var decl_scope: Scope.DeclAnalysis = .{ |
| 659 | .base = .{ .parent = scope }, | | |
| 660 | .decl = new_decl, | 724 | .decl = new_decl, |
| | 725 | .arena = std.heap.ArenaAllocator.init(self.allocator), |
| 661 | }; | 726 | }; |
| 662 | const typed_value = self.analyzeInstConst(&decl_scope.base, old_inst) catch |err| switch (err) { | 727 | errdefer decl_scope.arena.deinit(); |
| 663 | error.AnalysisFail => { | 728 | |
| 664 | assert(new_decl.analysis == .failure); | 729 | const arena_state = try self.allocator.create(std.heap.ArenaAllocator.State); |
| 665 | return error.AnalysisFail; | 730 | errdefer self.allocator.destroy(arena_state); |
| | 731 | |
| | 732 | const typed_value = try self.analyzeInstConst(&decl_scope.base, old_inst); |
| | 733 | |
| | 734 | arena_state.* = decl_scope.arena; |
| | 735 | |
| | 736 | new_decl.typed_value = .{ |
| | 737 | .most_recent = .{ |
| | 738 | .typed_value = typed_value, |
| | 739 | .arena = arena_state, |
| 666 | }, | 740 | }, |
| 667 | else => |e| return e, | | |
| 668 | }; | 741 | }; |
| 669 | new_decl.analysis = .{ .success = typed_value }; | 742 | new_decl.analysis = .complete; |
| 670 | // We ensureCapacity when scanning for decls. | 743 | // We ensureCapacity when scanning for decls. |
| 671 | self.analysis_queue.appendAssumeCapacity(.{ .decl = new_decl }); | 744 | self.work_stack.appendAssumeCapacity(self.allocator, .{ .codegen_decl = new_decl }); |
| 672 | return new_decl; | 745 | return new_decl; |
| 673 | } | 746 | } |
| 674 | } | 747 | } |
| ... | @@ -708,7 +781,7 @@ pub const Module = struct { | ... | @@ -708,7 +781,7 @@ pub const Module = struct { |
| 708 | | 781 | |
| 709 | fn resolveInstConst(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!TypedValue { | 782 | fn resolveInstConst(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!TypedValue { |
| 710 | const new_inst = try self.resolveInst(scope, old_inst); | 783 | const new_inst = try self.resolveInst(scope, old_inst); |
| 711 | const val = try self.resolveConstValue(new_inst); | 784 | const val = try self.resolveConstValue(scope, new_inst); |
| 712 | return TypedValue{ | 785 | return TypedValue{ |
| 713 | .ty = new_inst.ty, | 786 | .ty = new_inst.ty, |
| 714 | .val = val, | 787 | .val = val, |
| ... | @@ -716,7 +789,7 @@ pub const Module = struct { | ... | @@ -716,7 +789,7 @@ pub const Module = struct { |
| 716 | } | 789 | } |
| 717 | | 790 | |
| 718 | fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value { | 791 | fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value { |
| 719 | return (try self.resolveDefinedValue(base)) orelse | 792 | return (try self.resolveDefinedValue(scope, base)) orelse |
| 720 | return self.fail(scope, base.src, "unable to resolve comptime value", .{}); | 793 | return self.fail(scope, base.src, "unable to resolve comptime value", .{}); |
| 721 | } | 794 | } |
| 722 | | 795 | |
| ... | @@ -734,15 +807,15 @@ pub const Module = struct { | ... | @@ -734,15 +807,15 @@ pub const Module = struct { |
| 734 | const new_inst = try self.resolveInst(scope, old_inst); | 807 | const new_inst = try self.resolveInst(scope, old_inst); |
| 735 | const wanted_type = Type.initTag(.const_slice_u8); | 808 | const wanted_type = Type.initTag(.const_slice_u8); |
| 736 | const coerced_inst = try self.coerce(scope, wanted_type, new_inst); | 809 | const coerced_inst = try self.coerce(scope, wanted_type, new_inst); |
| 737 | const val = try self.resolveConstValue(coerced_inst); | 810 | const val = try self.resolveConstValue(scope, coerced_inst); |
| 738 | return val.toAllocatedBytes(&self.arena.allocator); | 811 | return val.toAllocatedBytes(scope.arena()); |
| 739 | } | 812 | } |
| 740 | | 813 | |
| 741 | fn resolveType(self: *Module, scope: *Scope, old_inst: *text.Inst) !Type { | 814 | fn resolveType(self: *Module, scope: *Scope, old_inst: *text.Inst) !Type { |
| 742 | const new_inst = try self.resolveInst(scope, old_inst); | 815 | const new_inst = try self.resolveInst(scope, old_inst); |
| 743 | const wanted_type = Type.initTag(.@"type"); | 816 | const wanted_type = Type.initTag(.@"type"); |
| 744 | const coerced_inst = try self.coerce(scope, wanted_type, new_inst); | 817 | const coerced_inst = try self.coerce(scope, wanted_type, new_inst); |
| 745 | const val = try self.resolveConstValue(coerced_inst); | 818 | const val = try self.resolveConstValue(scope, coerced_inst); |
| 746 | return val.toType(); | 819 | return val.toType(); |
| 747 | } | 820 | } |
| 748 | | 821 | |
| ... | @@ -764,7 +837,7 @@ pub const Module = struct { | ... | @@ -764,7 +837,7 @@ pub const Module = struct { |
| 764 | const new_export = try self.allocator.create(Export); | 837 | const new_export = try self.allocator.create(Export); |
| 765 | errdefer self.allocator.destroy(new_export); | 838 | errdefer self.allocator.destroy(new_export); |
| 766 | | 839 | |
| 767 | const owner_decl = scope.getDecl(); | 840 | const owner_decl = scope.decl(); |
| 768 | | 841 | |
| 769 | new_export.* = .{ | 842 | new_export.* = .{ |
| 770 | .options = .{ .data = .{ .name = symbol_name } }, | 843 | .options = .{ .data = .{ .name = symbol_name } }, |
| ... | @@ -810,7 +883,7 @@ pub const Module = struct { | ... | @@ -810,7 +883,7 @@ pub const Module = struct { |
| 810 | } | 883 | } |
| 811 | | 884 | |
| 812 | fn addNewInst(self: *Module, block: *Scope.Block, src: usize, ty: Type, comptime T: type) !*T { | 885 | fn addNewInst(self: *Module, block: *Scope.Block, src: usize, ty: Type, comptime T: type) !*T { |
| 813 | const inst = try self.arena.allocator.create(T); | 886 | const inst = try block.arena.create(T); |
| 814 | inst.* = .{ | 887 | inst.* = .{ |
| 815 | .base = .{ | 888 | .base = .{ |
| 816 | .tag = T.base_tag, | 889 | .tag = T.base_tag, |
| ... | @@ -823,8 +896,8 @@ pub const Module = struct { | ... | @@ -823,8 +896,8 @@ pub const Module = struct { |
| 823 | return inst; | 896 | return inst; |
| 824 | } | 897 | } |
| 825 | | 898 | |
| 826 | fn constInst(self: *Module, src: usize, typed_value: TypedValue) !*Inst { | 899 | fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst { |
| 827 | const const_inst = try self.arena.allocator.create(Inst.Constant); | 900 | const const_inst = try scope.arena().create(Inst.Constant); |
| 828 | const_inst.* = .{ | 901 | const_inst.* = .{ |
| 829 | .base = .{ | 902 | .base = .{ |
| 830 | .tag = Inst.Constant.base_tag, | 903 | .tag = Inst.Constant.base_tag, |
| ... | @@ -836,71 +909,71 @@ pub const Module = struct { | ... | @@ -836,71 +909,71 @@ pub const Module = struct { |
| 836 | return &const_inst.base; | 909 | return &const_inst.base; |
| 837 | } | 910 | } |
| 838 | | 911 | |
| 839 | fn constStr(self: *Module, src: usize, str: []const u8) !*Inst { | 912 | fn constStr(self: *Module, scope: *Scope, src: usize, str: []const u8) !*Inst { |
| 840 | const array_payload = try self.arena.allocator.create(Type.Payload.Array_u8_Sentinel0); | 913 | const array_payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0); |
| 841 | array_payload.* = .{ .len = str.len }; | 914 | array_payload.* = .{ .len = str.len }; |
| 842 | | 915 | |
| 843 | const ty_payload = try self.arena.allocator.create(Type.Payload.SingleConstPointer); | 916 | const ty_payload = try scope.arena().create(Type.Payload.SingleConstPointer); |
| 844 | ty_payload.* = .{ .pointee_type = Type.initPayload(&array_payload.base) }; | 917 | ty_payload.* = .{ .pointee_type = Type.initPayload(&array_payload.base) }; |
| 845 | | 918 | |
| 846 | const bytes_payload = try self.arena.allocator.create(Value.Payload.Bytes); | 919 | const bytes_payload = try scope.arena().create(Value.Payload.Bytes); |
| 847 | bytes_payload.* = .{ .data = str }; | 920 | bytes_payload.* = .{ .data = str }; |
| 848 | | 921 | |
| 849 | return self.constInst(src, .{ | 922 | return self.constInst(scope, src, .{ |
| 850 | .ty = Type.initPayload(&ty_payload.base), | 923 | .ty = Type.initPayload(&ty_payload.base), |
| 851 | .val = Value.initPayload(&bytes_payload.base), | 924 | .val = Value.initPayload(&bytes_payload.base), |
| 852 | }); | 925 | }); |
| 853 | } | 926 | } |
| 854 | | 927 | |
| 855 | fn constType(self: *Module, src: usize, ty: Type) !*Inst { | 928 | fn constType(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst { |
| 856 | return self.constInst(src, .{ | 929 | return self.constInst(scope, src, .{ |
| 857 | .ty = Type.initTag(.type), | 930 | .ty = Type.initTag(.type), |
| 858 | .val = try ty.toValue(&self.arena.allocator), | 931 | .val = try ty.toValue(scope.arena()), |
| 859 | }); | 932 | }); |
| 860 | } | 933 | } |
| 861 | | 934 | |
| 862 | fn constVoid(self: *Module, src: usize) !*Inst { | 935 | fn constVoid(self: *Module, scope: *Scope, src: usize) !*Inst { |
| 863 | return self.constInst(src, .{ | 936 | return self.constInst(scope, src, .{ |
| 864 | .ty = Type.initTag(.void), | 937 | .ty = Type.initTag(.void), |
| 865 | .val = Value.initTag(.the_one_possible_value), | 938 | .val = Value.initTag(.the_one_possible_value), |
| 866 | }); | 939 | }); |
| 867 | } | 940 | } |
| 868 | | 941 | |
| 869 | fn constUndef(self: *Module, src: usize, ty: Type) !*Inst { | 942 | fn constUndef(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst { |
| 870 | return self.constInst(src, .{ | 943 | return self.constInst(scope, src, .{ |
| 871 | .ty = ty, | 944 | .ty = ty, |
| 872 | .val = Value.initTag(.undef), | 945 | .val = Value.initTag(.undef), |
| 873 | }); | 946 | }); |
| 874 | } | 947 | } |
| 875 | | 948 | |
| 876 | fn constBool(self: *Module, src: usize, v: bool) !*Inst { | 949 | fn constBool(self: *Module, scope: *Scope, src: usize, v: bool) !*Inst { |
| 877 | return self.constInst(src, .{ | 950 | return self.constInst(scope, src, .{ |
| 878 | .ty = Type.initTag(.bool), | 951 | .ty = Type.initTag(.bool), |
| 879 | .val = ([2]Value{ Value.initTag(.bool_false), Value.initTag(.bool_true) })[@boolToInt(v)], | 952 | .val = ([2]Value{ Value.initTag(.bool_false), Value.initTag(.bool_true) })[@boolToInt(v)], |
| 880 | }); | 953 | }); |
| 881 | } | 954 | } |
| 882 | | 955 | |
| 883 | fn constIntUnsigned(self: *Module, src: usize, ty: Type, int: u64) !*Inst { | 956 | fn constIntUnsigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: u64) !*Inst { |
| 884 | const int_payload = try self.arena.allocator.create(Value.Payload.Int_u64); | 957 | const int_payload = try scope.arena().create(Value.Payload.Int_u64); |
| 885 | int_payload.* = .{ .int = int }; | 958 | int_payload.* = .{ .int = int }; |
| 886 | | 959 | |
| 887 | return self.constInst(src, .{ | 960 | return self.constInst(scope, src, .{ |
| 888 | .ty = ty, | 961 | .ty = ty, |
| 889 | .val = Value.initPayload(&int_payload.base), | 962 | .val = Value.initPayload(&int_payload.base), |
| 890 | }); | 963 | }); |
| 891 | } | 964 | } |
| 892 | | 965 | |
| 893 | fn constIntSigned(self: *Module, src: usize, ty: Type, int: i64) !*Inst { | 966 | fn constIntSigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: i64) !*Inst { |
| 894 | const int_payload = try self.arena.allocator.create(Value.Payload.Int_i64); | 967 | const int_payload = try scope.arena().create(Value.Payload.Int_i64); |
| 895 | int_payload.* = .{ .int = int }; | 968 | int_payload.* = .{ .int = int }; |
| 896 | | 969 | |
| 897 | return self.constInst(src, .{ | 970 | return self.constInst(scope, src, .{ |
| 898 | .ty = ty, | 971 | .ty = ty, |
| 899 | .val = Value.initPayload(&int_payload.base), | 972 | .val = Value.initPayload(&int_payload.base), |
| 900 | }); | 973 | }); |
| 901 | } | 974 | } |
| 902 | | 975 | |
| 903 | fn constIntBig(self: *Module, src: usize, ty: Type, big_int: BigIntConst) !*Inst { | 976 | fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigIntConst) !*Inst { |
| 904 | const val_payload = if (big_int.positive) blk: { | 977 | const val_payload = if (big_int.positive) blk: { |
| 905 | if (big_int.to(u64)) |x| { | 978 | if (big_int.to(u64)) |x| { |
| 906 | return self.constIntUnsigned(src, ty, x); | 979 | return self.constIntUnsigned(src, ty, x); |
| ... | @@ -908,7 +981,7 @@ pub const Module = struct { | ... | @@ -908,7 +981,7 @@ pub const Module = struct { |
| 908 | error.NegativeIntoUnsigned => unreachable, | 981 | error.NegativeIntoUnsigned => unreachable, |
| 909 | error.TargetTooSmall => {}, // handled below | 982 | error.TargetTooSmall => {}, // handled below |
| 910 | } | 983 | } |
| 911 | const big_int_payload = try self.arena.allocator.create(Value.Payload.IntBigPositive); | 984 | const big_int_payload = try scope.arena().create(Value.Payload.IntBigPositive); |
| 912 | big_int_payload.* = .{ .limbs = big_int.limbs }; | 985 | big_int_payload.* = .{ .limbs = big_int.limbs }; |
| 913 | break :blk &big_int_payload.base; | 986 | break :blk &big_int_payload.base; |
| 914 | } else blk: { | 987 | } else blk: { |
| ... | @@ -918,12 +991,12 @@ pub const Module = struct { | ... | @@ -918,12 +991,12 @@ pub const Module = struct { |
| 918 | error.NegativeIntoUnsigned => unreachable, | 991 | error.NegativeIntoUnsigned => unreachable, |
| 919 | error.TargetTooSmall => {}, // handled below | 992 | error.TargetTooSmall => {}, // handled below |
| 920 | } | 993 | } |
| 921 | const big_int_payload = try self.arena.allocator.create(Value.Payload.IntBigNegative); | 994 | const big_int_payload = try scope.arena().create(Value.Payload.IntBigNegative); |
| 922 | big_int_payload.* = .{ .limbs = big_int.limbs }; | 995 | big_int_payload.* = .{ .limbs = big_int.limbs }; |
| 923 | break :blk &big_int_payload.base; | 996 | break :blk &big_int_payload.base; |
| 924 | }; | 997 | }; |
| 925 | | 998 | |
| 926 | return self.constInst(src, .{ | 999 | return self.constInst(scope, src, .{ |
| 927 | .ty = ty, | 1000 | .ty = ty, |
| 928 | .val = Value.initPayload(val_payload), | 1001 | .val = Value.initPayload(val_payload), |
| 929 | }); | 1002 | }); |
| ... | @@ -958,11 +1031,10 @@ pub const Module = struct { | ... | @@ -958,11 +1031,10 @@ pub const Module = struct { |
| 958 | .@"asm" => return self.analyzeInstAsm(scope, old_inst.cast(text.Inst.Asm).?), | 1031 | .@"asm" => return self.analyzeInstAsm(scope, old_inst.cast(text.Inst.Asm).?), |
| 959 | .@"unreachable" => return self.analyzeInstUnreachable(scope, old_inst.cast(text.Inst.Unreachable).?), | 1032 | .@"unreachable" => return self.analyzeInstUnreachable(scope, old_inst.cast(text.Inst.Unreachable).?), |
| 960 | .@"return" => return self.analyzeInstRet(scope, old_inst.cast(text.Inst.Return).?), | 1033 | .@"return" => return self.analyzeInstRet(scope, old_inst.cast(text.Inst.Return).?), |
| 961 | // TODO postpone function analysis until later | | |
| 962 | .@"fn" => return self.analyzeInstFn(scope, old_inst.cast(text.Inst.Fn).?), | 1034 | .@"fn" => return self.analyzeInstFn(scope, old_inst.cast(text.Inst.Fn).?), |
| 963 | .@"export" => { | 1035 | .@"export" => { |
| 964 | try self.analyzeExport(scope, old_inst.cast(text.Inst.Export).?); | 1036 | try self.analyzeExport(scope, old_inst.cast(text.Inst.Export).?); |
| 965 | return self.constVoid(old_inst.src); | 1037 | return self.constVoid(scope, old_inst.src); |
| 966 | }, | 1038 | }, |
| 967 | .primitive => return self.analyzeInstPrimitive(old_inst.cast(text.Inst.Primitive).?), | 1039 | .primitive => return self.analyzeInstPrimitive(old_inst.cast(text.Inst.Primitive).?), |
| 968 | .fntype => return self.analyzeInstFnType(scope, old_inst.cast(text.Inst.FnType).?), | 1040 | .fntype => return self.analyzeInstFnType(scope, old_inst.cast(text.Inst.FnType).?), |
| ... | @@ -1033,7 +1105,7 @@ pub const Module = struct { | ... | @@ -1033,7 +1105,7 @@ pub const Module = struct { |
| 1033 | defer self.allocator.free(fn_param_types); | 1105 | defer self.allocator.free(fn_param_types); |
| 1034 | func.ty.fnParamTypes(fn_param_types); | 1106 | func.ty.fnParamTypes(fn_param_types); |
| 1035 | | 1107 | |
| 1036 | const casted_args = try self.arena.allocator.alloc(*Inst, fn_params_len); | 1108 | const casted_args = try scope.arena().alloc(*Inst, fn_params_len); |
| 1037 | for (inst.positionals.args) |src_arg, i| { | 1109 | for (inst.positionals.args) |src_arg, i| { |
| 1038 | const uncasted_arg = try self.resolveInst(scope, src_arg); | 1110 | const uncasted_arg = try self.resolveInst(scope, src_arg); |
| 1039 | casted_args[i] = try self.coerce(scope, fn_param_types[i], uncasted_arg); | 1111 | casted_args[i] = try self.coerce(scope, fn_param_types[i], uncasted_arg); |
| ... | @@ -1048,36 +1120,15 @@ pub const Module = struct { | ... | @@ -1048,36 +1120,15 @@ pub const Module = struct { |
| 1048 | | 1120 | |
| 1049 | fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *text.Inst.Fn) InnerError!*Inst { | 1121 | fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *text.Inst.Fn) InnerError!*Inst { |
| 1050 | const fn_type = try self.resolveType(scope, fn_inst.positionals.fn_type); | 1122 | const fn_type = try self.resolveType(scope, fn_inst.positionals.fn_type); |
| 1051 | | 1123 | const new_func = try scope.arena().create(Fn); |
| 1052 | var new_func: Fn = .{ | 1124 | new_func.* = .{ |
| 1053 | .fn_index = self.fns.items.len, | | |
| 1054 | .inner_block = .{ | | |
| 1055 | .func = undefined, | | |
| 1056 | .instructions = .{}, | | |
| 1057 | }, | | |
| 1058 | .inst_table = std.AutoHashMap(*text.Inst, ?*Inst).init(self.allocator), | | |
| 1059 | }; | | |
| 1060 | new_func.inner_block.func = &new_func; | | |
| 1061 | defer new_func.inner_block.instructions.deinit(); | | |
| 1062 | defer new_func.inst_table.deinit(); | | |
| 1063 | // Don't hang on to a reference to this when analyzing body instructions, since the memory | | |
| 1064 | // could become invalid. | | |
| 1065 | (try self.fns.addOne(self.allocator)).* = .{ | | |
| 1066 | .analysis_status = .in_progress, | | |
| 1067 | .fn_type = fn_type, | 1125 | .fn_type = fn_type, |
| 1068 | .body = undefined, | 1126 | .analysis = .{ .queued = fn_inst.positionals.body }, |
| | 1127 | .scope = scope.namespace(), |
| 1069 | }; | 1128 | }; |
| 1070 | | 1129 | const fn_payload = try scope.arena().create(Value.Payload.Function); |
| 1071 | try self.analyzeBody(&new_func.inner_block, fn_inst.positionals.body); | 1130 | fn_payload.* = .{ .func = new_func }; |
| 1072 | | 1131 | return self.constInst(scope, fn_inst.base.src, .{ |
| 1073 | const f = &self.fns.items[new_func.fn_index]; | | |
| 1074 | f.analysis_status = .success; | | |
| 1075 | f.body = .{ .instructions = new_func.inner_block.instructions.toOwnedSlice() }; | | |
| 1076 | | | |
| 1077 | const fn_payload = try self.arena.allocator.create(Value.Payload.Function); | | |
| 1078 | fn_payload.* = .{ .index = new_func.fn_index }; | | |
| 1079 | | | |
| 1080 | return self.constInst(fn_inst.base.src, .{ | | |
| 1081 | .ty = fn_type, | 1132 | .ty = fn_type, |
| 1082 | .val = Value.initPayload(&fn_payload.base), | 1133 | .val = Value.initPayload(&fn_payload.base), |
| 1083 | }); | 1134 | }); |
| ... | @@ -1142,13 +1193,13 @@ pub const Module = struct { | ... | @@ -1142,13 +1193,13 @@ pub const Module = struct { |
| 1142 | switch (elem_ty.zigTypeTag()) { | 1193 | switch (elem_ty.zigTypeTag()) { |
| 1143 | .Array => { | 1194 | .Array => { |
| 1144 | if (mem.eql(u8, field_name, "len")) { | 1195 | if (mem.eql(u8, field_name, "len")) { |
| 1145 | const len_payload = try self.arena.allocator.create(Value.Payload.Int_u64); | 1196 | const len_payload = try scope.arena().create(Value.Payload.Int_u64); |
| 1146 | len_payload.* = .{ .int = elem_ty.arrayLen() }; | 1197 | len_payload.* = .{ .int = elem_ty.arrayLen() }; |
| 1147 | | 1198 | |
| 1148 | const ref_payload = try self.arena.allocator.create(Value.Payload.RefVal); | 1199 | const ref_payload = try scope.arena().create(Value.Payload.RefVal); |
| 1149 | ref_payload.* = .{ .val = Value.initPayload(&len_payload.base) }; | 1200 | ref_payload.* = .{ .val = Value.initPayload(&len_payload.base) }; |
| 1150 | | 1201 | |
| 1151 | return self.constInst(fieldptr.base.src, .{ | 1202 | return self.constInst(scope, fieldptr.base.src, .{ |
| 1152 | .ty = Type.initTag(.single_const_pointer_to_comptime_int), | 1203 | .ty = Type.initTag(.single_const_pointer_to_comptime_int), |
| 1153 | .val = Value.initPayload(&ref_payload.base), | 1204 | .val = Value.initPayload(&ref_payload.base), |
| 1154 | }); | 1205 | }); |
| ... | @@ -1217,12 +1268,12 @@ pub const Module = struct { | ... | @@ -1217,12 +1268,12 @@ pub const Module = struct { |
| 1217 | const index_u64 = index_val.toUnsignedInt(); | 1268 | const index_u64 = index_val.toUnsignedInt(); |
| 1218 | // @intCast here because it would have been impossible to construct a value that | 1269 | // @intCast here because it would have been impossible to construct a value that |
| 1219 | // required a larger index. | 1270 | // required a larger index. |
| 1220 | const elem_ptr = try array_ptr_val.elemPtr(&self.arena.allocator, @intCast(usize, index_u64)); | 1271 | const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64)); |
| 1221 | | 1272 | |
| 1222 | const type_payload = try self.arena.allocator.create(Type.Payload.SingleConstPointer); | 1273 | const type_payload = try scope.arena().create(Type.Payload.SingleConstPointer); |
| 1223 | type_payload.* = .{ .pointee_type = array_ptr.ty.elemType().elemType() }; | 1274 | type_payload.* = .{ .pointee_type = array_ptr.ty.elemType().elemType() }; |
| 1224 | | 1275 | |
| 1225 | return self.constInst(inst.base.src, .{ | 1276 | return self.constInst(scope, inst.base.src, .{ |
| 1226 | .ty = Type.initPayload(&type_payload.base), | 1277 | .ty = Type.initPayload(&type_payload.base), |
| 1227 | .val = elem_ptr, | 1278 | .val = elem_ptr, |
| 1228 | }); | 1279 | }); |
| ... | @@ -1246,7 +1297,7 @@ pub const Module = struct { | ... | @@ -1246,7 +1297,7 @@ pub const Module = struct { |
| 1246 | var rhs_space: Value.BigIntSpace = undefined; | 1297 | var rhs_space: Value.BigIntSpace = undefined; |
| 1247 | const lhs_bigint = lhs_val.toBigInt(&lhs_space); | 1298 | const lhs_bigint = lhs_val.toBigInt(&lhs_space); |
| 1248 | const rhs_bigint = rhs_val.toBigInt(&rhs_space); | 1299 | const rhs_bigint = rhs_val.toBigInt(&rhs_space); |
| 1249 | const limbs = try self.arena.allocator.alloc( | 1300 | const limbs = try scope.arena().alloc( |
| 1250 | std.math.big.Limb, | 1301 | std.math.big.Limb, |
| 1251 | std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, | 1302 | std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, |
| 1252 | ); | 1303 | ); |
| ... | @@ -1259,16 +1310,16 @@ pub const Module = struct { | ... | @@ -1259,16 +1310,16 @@ pub const Module = struct { |
| 1259 | } | 1310 | } |
| 1260 | | 1311 | |
| 1261 | const val_payload = if (result_bigint.positive) blk: { | 1312 | const val_payload = if (result_bigint.positive) blk: { |
| 1262 | const val_payload = try self.arena.allocator.create(Value.Payload.IntBigPositive); | 1313 | const val_payload = try scope.arena().create(Value.Payload.IntBigPositive); |
| 1263 | val_payload.* = .{ .limbs = result_limbs }; | 1314 | val_payload.* = .{ .limbs = result_limbs }; |
| 1264 | break :blk &val_payload.base; | 1315 | break :blk &val_payload.base; |
| 1265 | } else blk: { | 1316 | } else blk: { |
| 1266 | const val_payload = try self.arena.allocator.create(Value.Payload.IntBigNegative); | 1317 | const val_payload = try scope.arena().create(Value.Payload.IntBigNegative); |
| 1267 | val_payload.* = .{ .limbs = result_limbs }; | 1318 | val_payload.* = .{ .limbs = result_limbs }; |
| 1268 | break :blk &val_payload.base; | 1319 | break :blk &val_payload.base; |
| 1269 | }; | 1320 | }; |
| 1270 | | 1321 | |
| 1271 | return self.constInst(inst.base.src, .{ | 1322 | return self.constInst(scope, inst.base.src, .{ |
| 1272 | .ty = lhs.ty, | 1323 | .ty = lhs.ty, |
| 1273 | .val = Value.initPayload(val_payload), | 1324 | .val = Value.initPayload(val_payload), |
| 1274 | }); | 1325 | }); |
| ... | @@ -1286,7 +1337,7 @@ pub const Module = struct { | ... | @@ -1286,7 +1337,7 @@ pub const Module = struct { |
| 1286 | else => return self.fail(scope, deref.positionals.ptr.src, "expected pointer, found '{}'", .{ptr.ty}), | 1337 | else => return self.fail(scope, deref.positionals.ptr.src, "expected pointer, found '{}'", .{ptr.ty}), |
| 1287 | }; | 1338 | }; |
| 1288 | if (ptr.value()) |val| { | 1339 | if (ptr.value()) |val| { |
| 1289 | return self.constInst(deref.base.src, .{ | 1340 | return self.constInst(scope, deref.base.src, .{ |
| 1290 | .ty = elem_ty, | 1341 | .ty = elem_ty, |
| 1291 | .val = val.pointerDeref(), | 1342 | .val = val.pointerDeref(), |
| 1292 | }); | 1343 | }); |
| ... | @@ -1300,9 +1351,9 @@ pub const Module = struct { | ... | @@ -1300,9 +1351,9 @@ pub const Module = struct { |
| 1300 | const asm_source = try self.resolveConstString(scope, assembly.positionals.asm_source); | 1351 | const asm_source = try self.resolveConstString(scope, assembly.positionals.asm_source); |
| 1301 | const output = if (assembly.kw_args.output) |o| try self.resolveConstString(scope, o) else null; | 1352 | const output = if (assembly.kw_args.output) |o| try self.resolveConstString(scope, o) else null; |
| 1302 | | 1353 | |
| 1303 | const inputs = try self.arena.allocator.alloc([]const u8, assembly.kw_args.inputs.len); | 1354 | const inputs = try scope.arena().alloc([]const u8, assembly.kw_args.inputs.len); |
| 1304 | const clobbers = try self.arena.allocator.alloc([]const u8, assembly.kw_args.clobbers.len); | 1355 | const clobbers = try scope.arena().alloc([]const u8, assembly.kw_args.clobbers.len); |
| 1305 | const args = try self.arena.allocator.alloc(*Inst, assembly.kw_args.args.len); | 1356 | const args = try scope.arena().alloc(*Inst, assembly.kw_args.args.len); |
| 1306 | | 1357 | |
| 1307 | for (inputs) |*elem, i| { | 1358 | for (inputs) |*elem, i| { |
| 1308 | elem.* = try self.resolveConstString(scope, assembly.kw_args.inputs[i]); | 1359 | elem.* = try self.resolveConstString(scope, assembly.kw_args.inputs[i]); |
| ... | @@ -1408,15 +1459,16 @@ pub const Module = struct { | ... | @@ -1408,15 +1459,16 @@ pub const Module = struct { |
| 1408 | const uncasted_cond = try self.resolveInst(scope, inst.positionals.condition); | 1459 | const uncasted_cond = try self.resolveInst(scope, inst.positionals.condition); |
| 1409 | const cond = try self.coerce(scope, Type.initTag(.bool), uncasted_cond); | 1460 | const cond = try self.coerce(scope, Type.initTag(.bool), uncasted_cond); |
| 1410 | | 1461 | |
| 1411 | if (try self.resolveDefinedValue(cond)) |cond_val| { | 1462 | if (try self.resolveDefinedValue(scope, cond)) |cond_val| { |
| 1412 | const body = if (cond_val.toBool()) &inst.positionals.true_body else &inst.positionals.false_body; | 1463 | const body = if (cond_val.toBool()) &inst.positionals.true_body else &inst.positionals.false_body; |
| 1413 | try self.analyzeBody(scope, body.*); | 1464 | try self.analyzeBody(scope, body.*); |
| 1414 | return self.constVoid(inst.base.src); | 1465 | return self.constVoid(scope, inst.base.src); |
| 1415 | } | 1466 | } |
| 1416 | | 1467 | |
| 1417 | const parent_block = try self.requireRuntimeBlock(scope, inst.base.src); | 1468 | const parent_block = try self.requireRuntimeBlock(scope, inst.base.src); |
| 1418 | | 1469 | |
| 1419 | var true_block: Scope.Block = .{ | 1470 | var true_block: Scope.Block = .{ |
| | 1471 | .base = .{ .parent = scope }, |
| 1420 | .func = parent_block.func, | 1472 | .func = parent_block.func, |
| 1421 | .instructions = .{}, | 1473 | .instructions = .{}, |
| 1422 | }; | 1474 | }; |
| ... | @@ -1424,6 +1476,7 @@ pub const Module = struct { | ... | @@ -1424,6 +1476,7 @@ pub const Module = struct { |
| 1424 | try self.analyzeBody(&true_block.base, inst.positionals.true_body); | 1476 | try self.analyzeBody(&true_block.base, inst.positionals.true_body); |
| 1425 | | 1477 | |
| 1426 | var false_block: Scope.Block = .{ | 1478 | var false_block: Scope.Block = .{ |
| | 1479 | .base = .{ .parent = scope }, |
| 1427 | .func = parent_block.func, | 1480 | .func = parent_block.func, |
| 1428 | .instructions = .{}, | 1481 | .instructions = .{}, |
| 1429 | }; | 1482 | }; |
| ... | @@ -1431,8 +1484,8 @@ pub const Module = struct { | ... | @@ -1431,8 +1484,8 @@ pub const Module = struct { |
| 1431 | try self.analyzeBody(&false_block.base, inst.positionals.false_body); | 1484 | try self.analyzeBody(&false_block.base, inst.positionals.false_body); |
| 1432 | | 1485 | |
| 1433 | // Copy the instruction pointers to the arena memory | 1486 | // Copy the instruction pointers to the arena memory |
| 1434 | const true_instructions = try self.arena.allocator.alloc(*Inst, true_block.instructions.items.len); | 1487 | const true_instructions = try scope.arena().alloc(*Inst, true_block.instructions.items.len); |
| 1435 | const false_instructions = try self.arena.allocator.alloc(*Inst, false_block.instructions.items.len); | 1488 | const false_instructions = try scope.arena().alloc(*Inst, false_block.instructions.items.len); |
| 1436 | | 1489 | |
| 1437 | mem.copy(*Inst, true_instructions, true_block.instructions.items); | 1490 | mem.copy(*Inst, true_instructions, true_block.instructions.items); |
| 1438 | mem.copy(*Inst, false_instructions, false_block.instructions.items); | 1491 | mem.copy(*Inst, false_instructions, false_block.instructions.items); |
| ... | @@ -1586,7 +1639,7 @@ pub const Module = struct { | ... | @@ -1586,7 +1639,7 @@ pub const Module = struct { |
| 1586 | var lhs_bits: usize = undefined; | 1639 | var lhs_bits: usize = undefined; |
| 1587 | if (lhs.value()) |lhs_val| { | 1640 | if (lhs.value()) |lhs_val| { |
| 1588 | if (lhs_val.isUndef()) | 1641 | if (lhs_val.isUndef()) |
| 1589 | return self.constUndef(src, Type.initTag(.bool)); | 1642 | return self.constUndef(scope, src, Type.initTag(.bool)); |
| 1590 | const is_unsigned = if (lhs_is_float) x: { | 1643 | const is_unsigned = if (lhs_is_float) x: { |
| 1591 | var bigint_space: Value.BigIntSpace = undefined; | 1644 | var bigint_space: Value.BigIntSpace = undefined; |
| 1592 | var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(self.allocator); | 1645 | var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(self.allocator); |
| ... | @@ -1621,7 +1674,7 @@ pub const Module = struct { | ... | @@ -1621,7 +1674,7 @@ pub const Module = struct { |
| 1621 | var rhs_bits: usize = undefined; | 1674 | var rhs_bits: usize = undefined; |
| 1622 | if (rhs.value()) |rhs_val| { | 1675 | if (rhs.value()) |rhs_val| { |
| 1623 | if (rhs_val.isUndef()) | 1676 | if (rhs_val.isUndef()) |
| 1624 | return self.constUndef(src, Type.initTag(.bool)); | 1677 | return self.constUndef(scope, src, Type.initTag(.bool)); |
| 1625 | const is_unsigned = if (rhs_is_float) x: { | 1678 | const is_unsigned = if (rhs_is_float) x: { |
| 1626 | var bigint_space: Value.BigIntSpace = undefined; | 1679 | var bigint_space: Value.BigIntSpace = undefined; |
| 1627 | var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(self.allocator); | 1680 | var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(self.allocator); |
| ... | @@ -1670,13 +1723,13 @@ pub const Module = struct { | ... | @@ -1670,13 +1723,13 @@ pub const Module = struct { |
| 1670 | }); | 1723 | }); |
| 1671 | } | 1724 | } |
| 1672 | | 1725 | |
| 1673 | fn makeIntType(self: *Module, signed: bool, bits: u16) !Type { | 1726 | fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type { |
| 1674 | if (signed) { | 1727 | if (signed) { |
| 1675 | const int_payload = try self.arena.allocator.create(Type.Payload.IntSigned); | 1728 | const int_payload = try scope.arena().create(Type.Payload.IntSigned); |
| 1676 | int_payload.* = .{ .bits = bits }; | 1729 | int_payload.* = .{ .bits = bits }; |
| 1677 | return Type.initPayload(&int_payload.base); | 1730 | return Type.initPayload(&int_payload.base); |
| 1678 | } else { | 1731 | } else { |
| 1679 | const int_payload = try self.arena.allocator.create(Type.Payload.IntUnsigned); | 1732 | const int_payload = try scope.arena().create(Type.Payload.IntUnsigned); |
| 1680 | int_payload.* = .{ .bits = bits }; | 1733 | int_payload.* = .{ .bits = bits }; |
| 1681 | return Type.initPayload(&int_payload.base); | 1734 | return Type.initPayload(&int_payload.base); |
| 1682 | } | 1735 | } |
| ... | @@ -1701,7 +1754,7 @@ pub const Module = struct { | ... | @@ -1701,7 +1754,7 @@ pub const Module = struct { |
| 1701 | if (array_type.zigTypeTag() == .Array and | 1754 | if (array_type.zigTypeTag() == .Array and |
| 1702 | coerceInMemoryAllowed(dst_elem_type, array_type.elemType()) == .ok) | 1755 | coerceInMemoryAllowed(dst_elem_type, array_type.elemType()) == .ok) |
| 1703 | { | 1756 | { |
| 1704 | return self.coerceArrayPtrToSlice(dest_type, inst); | 1757 | return self.coerceArrayPtrToSlice(scope, dest_type, inst); |
| 1705 | } | 1758 | } |
| 1706 | } | 1759 | } |
| 1707 | | 1760 | |
| ... | @@ -1712,7 +1765,7 @@ pub const Module = struct { | ... | @@ -1712,7 +1765,7 @@ pub const Module = struct { |
| 1712 | if (!val.intFitsInType(dest_type, self.target())) { | 1765 | if (!val.intFitsInType(dest_type, self.target())) { |
| 1713 | return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val }); | 1766 | return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val }); |
| 1714 | } | 1767 | } |
| 1715 | return self.constInst(inst.src, .{ .ty = dest_type, .val = val }); | 1768 | return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val }); |
| 1716 | } | 1769 | } |
| 1717 | | 1770 | |
| 1718 | // integer widening | 1771 | // integer widening |
| ... | @@ -1721,7 +1774,7 @@ pub const Module = struct { | ... | @@ -1721,7 +1774,7 @@ pub const Module = struct { |
| 1721 | const dst_info = dest_type.intInfo(self.target()); | 1774 | const dst_info = dest_type.intInfo(self.target()); |
| 1722 | if (src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) { | 1775 | if (src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) { |
| 1723 | if (inst.value()) |val| { | 1776 | if (inst.value()) |val| { |
| 1724 | return self.constInst(inst.src, .{ .ty = dest_type, .val = val }); | 1777 | return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val }); |
| 1725 | } else { | 1778 | } else { |
| 1726 | return self.fail(scope, inst.src, "TODO implement runtime integer widening", .{}); | 1779 | return self.fail(scope, inst.src, "TODO implement runtime integer widening", .{}); |
| 1727 | } | 1780 | } |
| ... | @@ -1736,33 +1789,41 @@ pub const Module = struct { | ... | @@ -1736,33 +1789,41 @@ pub const Module = struct { |
| 1736 | fn bitcast(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst { | 1789 | fn bitcast(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst { |
| 1737 | if (inst.value()) |val| { | 1790 | if (inst.value()) |val| { |
| 1738 | // Keep the comptime Value representation; take the new type. | 1791 | // Keep the comptime Value representation; take the new type. |
| 1739 | return self.constInst(inst.src, .{ .ty = dest_type, .val = val }); | 1792 | return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val }); |
| 1740 | } | 1793 | } |
| 1741 | // TODO validate the type size and other compile errors | 1794 | // TODO validate the type size and other compile errors |
| 1742 | const b = try self.requireRuntimeBlock(scope, inst.src); | 1795 | const b = try self.requireRuntimeBlock(scope, inst.src); |
| 1743 | return self.addNewInstArgs(b, inst.src, dest_type, Inst.BitCast, Inst.Args(Inst.BitCast){ .operand = inst }); | 1796 | return self.addNewInstArgs(b, inst.src, dest_type, Inst.BitCast, Inst.Args(Inst.BitCast){ .operand = inst }); |
| 1744 | } | 1797 | } |
| 1745 | | 1798 | |
| 1746 | fn coerceArrayPtrToSlice(self: *Module, dest_type: Type, inst: *Inst) !*Inst { | 1799 | fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst { |
| 1747 | if (inst.value()) |val| { | 1800 | if (inst.value()) |val| { |
| 1748 | // The comptime Value representation is compatible with both types. | 1801 | // The comptime Value representation is compatible with both types. |
| 1749 | return self.constInst(inst.src, .{ .ty = dest_type, .val = val }); | 1802 | return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val }); |
| 1750 | } | 1803 | } |
| 1751 | return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{}); | 1804 | return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{}); |
| 1752 | } | 1805 | } |
| 1753 | | 1806 | |
| 1754 | fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: var) InnerError { | 1807 | fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: var) InnerError { |
| 1755 | @setCold(true); | 1808 | @setCold(true); |
| 1756 | const err_msg = ErrorMsg{ | 1809 | try self.failed_decls.ensureCapacity(self.failed_decls.size + 1); |
| 1757 | .byte_offset = src, | 1810 | try self.failed_fns.ensureCapacity(self.failed_fns.size + 1); |
| 1758 | .msg = try std.fmt.allocPrint(self.allocator, format, args), | 1811 | const err_msg = try ErrorMsg.create(self.allocator, src, format, args); |
| 1759 | }; | 1812 | switch (scope.tag) { |
| 1760 | if (scope.cast(Scope.Block)) |block| { | 1813 | .decl => { |
| 1761 | block.func.analysis = .{ .failure = err_msg }; | 1814 | const decl = scope.cast(Scope.DeclAnalysis).?.decl; |
| 1762 | } else if (scope.cast(Scope.Decl)) |scope_decl| { | 1815 | switch (decl.analysis) { |
| 1763 | scope_decl.decl.analysis = .{ .failure = err_msg }; | 1816 | .initial_in_progress => decl.analysis = .initial_sema_failure, |
| 1764 | } else { | 1817 | .repeat_in_progress => decl.analysis = .repeat_sema_failure, |
| 1765 | unreachable; | 1818 | else => unreachable, |
| | 1819 | } |
| | 1820 | self.failed_decls.putAssumeCapacityNoClobber(decl, err_msg); |
| | 1821 | }, |
| | 1822 | .block => { |
| | 1823 | const func = scope.cast(Scope.Block).?.func; |
| | 1824 | func.analysis = .failure; |
| | 1825 | self.failed_fns.putAssumeCapacityNoClobber(func, err_msg); |
| | 1826 | }, |
| 1766 | } | 1827 | } |
| 1767 | return error.AnalysisFail; | 1828 | return error.AnalysisFail; |
| 1768 | } | 1829 | } |
| ... | @@ -1788,8 +1849,8 @@ pub const ErrorMsg = struct { | ... | @@ -1788,8 +1849,8 @@ pub const ErrorMsg = struct { |
| 1788 | | 1849 | |
| 1789 | pub fn create(allocator: *Allocator, byte_offset: usize, comptime format: []const u8, args: var) !*ErrorMsg { | 1850 | pub fn create(allocator: *Allocator, byte_offset: usize, comptime format: []const u8, args: var) !*ErrorMsg { |
| 1790 | const self = try allocator.create(ErrorMsg); | 1851 | const self = try allocator.create(ErrorMsg); |
| 1791 | errdefer allocator.destroy(ErrorMsg); | 1852 | errdefer allocator.destroy(self); |
| 1792 | self.* = init(allocator, byte_offset, format, args); | 1853 | self.* = try init(allocator, byte_offset, format, args); |
| 1793 | return self; | 1854 | return self; |
| 1794 | } | 1855 | } |
| 1795 | | 1856 | |