authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-17 04:29:54-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-18 17:12:56-04:00
log7e58c56ca72099f6e71752289be7165947bfaa04
treed4b5def4b5fd17caba14e88f5bdc3673449e8fdd
parentb4eac0414a01b1096e8dd7e89455db88f19789cf

self-hosted: implement Decl lookup

* Take advantage of coercing anonymous struct literals to struct types. * Reworks Module to favor Zig source as the primary use case. Breaks ZIR compilation, which will have to be restored in a future commit. * Decl uses src_index rather then src, pointing to an AST Decl node index, or ZIR Module Decl index, rather than a byte offset. * ZIR instructions have an `analyzed_inst` field instead of Module having a hash table. * Module.Fn loses the `fn_type` field since it is redundant with its `owner_decl` `TypedValue` type. * Implement Type and Value copying. A ZIR Const instruction's TypedValue is copied to the Decl arena during analysis, which allows freeing the ZIR text instructions post-analysis. * Don't flush the ELF file if there are compilation errors. * Function return types allow arbitrarily complex expressions. * AST->ZIR for function calls and return statements.

10 files changed, 867 insertions(+), 430 deletions(-)

lib/std/zig/ast.zig+2
......@@ -2260,6 +2260,8 @@ pub const Node = struct {
22602260 }
22612261 };
22622262
2263 /// TODO break this into separate Break, Continue, Return AST Nodes to save memory.
2264 /// Could be further broken into LabeledBreak, LabeledContinue, and ReturnVoid to save even more.
22632265 pub const ControlFlowExpression = struct {
22642266 base: Node = Node{ .id = .ControlFlowExpression },
22652267 ltoken: TokenIndex,
src-self-hosted/Module.zig+543-407
......@@ -37,10 +37,10 @@ decl_exports: std.AutoHashMap(*Decl, []*Export),
3737/// This table owns the Export memory.
3838export_owners: std.AutoHashMap(*Decl, []*Export),
3939/// Maps fully qualified namespaced names to the Decl struct for them.
40decl_table: std.AutoHashMap(Decl.Hash, *Decl),
40decl_table: std.AutoHashMap(Scope.NameHash, *Decl),
4141
4242optimize_mode: std.builtin.Mode,
43link_error_flags: link.ElfFile.ErrorFlags = link.ElfFile.ErrorFlags{},
43link_error_flags: link.ElfFile.ErrorFlags = .{},
4444
4545work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic),
4646
......@@ -64,20 +64,15 @@ generation: u32 = 0,
6464
6565/// Candidates for deletion. After a semantic analysis update completes, this list
6666/// contains Decls that need to be deleted if they end up having no references to them.
67deletion_set: std.ArrayListUnmanaged(*Decl) = std.ArrayListUnmanaged(*Decl){},
67deletion_set: std.ArrayListUnmanaged(*Decl) = .{},
6868
6969const WorkItem = union(enum) {
7070 /// Write the machine code for a Decl to the output file.
7171 codegen_decl: *Decl,
7272 /// Decl has been determined to be outdated; perform semantic analysis again.
7373 re_analyze_decl: *Decl,
74 /// This AST node needs to be converted to a Decl and then semantically analyzed.
75 ast_gen_decl: AstGenDecl,
76
77 const AstGenDecl = struct {
78 ast_node: *ast.Node,
79 scope: *Scope,
80 };
74 /// The Decl needs to be analyzed and possibly export itself.
75 analyze_decl: *Decl,
8176};
8277
8378pub const Export = struct {
......@@ -111,9 +106,9 @@ pub const Decl = struct {
111106 /// The direct parent container of the Decl. This is either a `Scope.File` or `Scope.ZIRModule`.
112107 /// Reference to externally owned memory.
113108 scope: *Scope,
114 /// Byte offset into the source file that contains this declaration.
115 /// This is the base offset that src offsets within this Decl are relative to.
116 src: usize,
109 /// The AST Node decl index or ZIR Inst index that contains this declaration.
110 /// Must be recomputed when the corresponding source file is modified.
111 src_index: usize,
117112 /// The most recent value of the Decl after a successful semantic analysis.
118113 typed_value: union(enum) {
119114 never_succeeded: void,
......@@ -124,6 +119,9 @@ pub const Decl = struct {
124119 /// analysis of the function body is performed with this value set to `success`. Functions
125120 /// have their own analysis status field.
126121 analysis: enum {
122 /// This Decl corresponds to an AST Node that has not been referenced yet, and therefore
123 /// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced.
124 unreferenced,
127125 /// Semantic analysis for this Decl is running right now. This state detects dependency loops.
128126 in_progress,
129127 /// This Decl might be OK but it depends on another one which did not successfully complete
......@@ -133,6 +131,10 @@ pub const Decl = struct {
133131 /// There will be a corresponding ErrorMsg in Module.failed_decls.
134132 sema_failure,
135133 /// There will be a corresponding ErrorMsg in Module.failed_decls.
134 /// This indicates the failure was something like running out of disk space,
135 /// and attempting semantic analysis again may succeed.
136 sema_failure_retryable,
137 /// There will be a corresponding ErrorMsg in Module.failed_decls.
136138 codegen_failure,
137139 /// There will be a corresponding ErrorMsg in Module.failed_decls.
138140 /// This indicates the failure was something like running out of disk space,
......@@ -158,7 +160,7 @@ pub const Decl = struct {
158160 /// This is populated regardless of semantic analysis and code generation.
159161 link: link.ElfFile.TextBlock = link.ElfFile.TextBlock.empty,
160162
161 contents_hash: Hash,
163 contents_hash: std.zig.SrcHash,
162164
163165 /// The shallow set of other decls whose typed_value could possibly change if this Decl's
164166 /// typed_value is modified.
......@@ -177,19 +179,28 @@ pub const Decl = struct {
177179 allocator.destroy(self);
178180 }
179181
180 pub const Hash = [16]u8;
181
182 pub fn hashSimpleName(name: []const u8) Hash {
183 return std.zig.hashSrc(name);
182 pub fn src(self: Decl) usize {
183 switch (self.scope.tag) {
184 .file => {
185 const file = @fieldParentPtr(Scope.File, "base", self.scope);
186 const tree = file.contents.tree;
187 const decl_node = tree.root_node.decls()[self.src_index];
188 return tree.token_locs[decl_node.firstToken()].start;
189 },
190 .zir_module => {
191 const zir_module = @fieldParentPtr(Scope.ZIRModule, "base", self.scope);
192 const module = zir_module.contents.module;
193 const decl_inst = module.decls[self.src_index];
194 return decl_inst.src;
195 },
196 .block => unreachable,
197 .gen_zir => unreachable,
198 .decl => unreachable,
199 }
184200 }
185201
186 /// Must generate unique bytes with no collisions with other decls.
187 /// The point of hashing here is only to limit the number of bytes of
188 /// the unique identifier to a fixed size (16 bytes).
189 pub fn fullyQualifiedNameHash(self: Decl) Hash {
190 // Right now we only have ZIRModule as the source. So this is simply the
191 // relative name of the decl.
192 return hashSimpleName(mem.spanZ(self.name));
202 pub fn fullyQualifiedNameHash(self: Decl) Scope.NameHash {
203 return self.scope.fullyQualifiedNameHash(mem.spanZ(self.name));
193204 }
194205
195206 pub fn typedValue(self: *Decl) error{AnalysisFail}!TypedValue {
......@@ -247,11 +258,9 @@ pub const Decl = struct {
247258/// Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
248259pub const Fn = struct {
249260 /// This memory owned by the Decl's TypedValue.Managed arena allocator.
250 fn_type: Type,
251261 analysis: union(enum) {
252 /// The value is the source instruction.
253 queued: *zir.Inst.Fn,
254 in_progress: *Analysis,
262 queued: *ZIR,
263 in_progress,
255264 /// There will be a corresponding ErrorMsg in Module.failed_decls
256265 sema_failure,
257266 /// This Fn might be OK but it depends on another Decl which did not successfully complete
......@@ -265,16 +274,20 @@ pub const Fn = struct {
265274 /// of Fn analysis.
266275 pub const Analysis = struct {
267276 inner_block: Scope.Block,
268 /// TODO Performance optimization idea: instead of this inst_table,
269 /// use a field in the zir.Inst instead to track corresponding instructions
270 inst_table: std.AutoHashMap(*zir.Inst, *Inst),
271 needed_inst_capacity: usize,
277 };
278
279 /// Contains un-analyzed ZIR instructions generated from Zig source AST.
280 pub const ZIR = struct {
281 body: zir.Module.Body,
282 arena: std.heap.ArenaAllocator.State,
272283 };
273284};
274285
275286pub const Scope = struct {
276287 tag: Tag,
277288
289 pub const NameHash = [16]u8;
290
278291 pub fn cast(base: *Scope, comptime T: type) ?*T {
279292 if (base.tag != T.base_tag)
280293 return null;
......@@ -288,6 +301,7 @@ pub const Scope = struct {
288301 switch (self.tag) {
289302 .block => return self.cast(Block).?.arena,
290303 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
304 .gen_zir => return &self.cast(GenZIR).?.arena.allocator,
291305 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
292306 .file => unreachable,
293307 }
......@@ -298,6 +312,7 @@ pub const Scope = struct {
298312 pub fn decl(self: *Scope) ?*Decl {
299313 return switch (self.tag) {
300314 .block => self.cast(Block).?.decl,
315 .gen_zir => self.cast(GenZIR).?.decl,
301316 .decl => self.cast(DeclAnalysis).?.decl,
302317 .zir_module => null,
303318 .file => null,
......@@ -309,11 +324,25 @@ pub const Scope = struct {
309324 pub fn namespace(self: *Scope) *Scope {
310325 switch (self.tag) {
311326 .block => return self.cast(Block).?.decl.scope,
327 .gen_zir => return self.cast(GenZIR).?.decl.scope,
312328 .decl => return self.cast(DeclAnalysis).?.decl.scope,
313329 .zir_module, .file => return self,
314330 }
315331 }
316332
333 /// Must generate unique bytes with no collisions with other decls.
334 /// The point of hashing here is only to limit the number of bytes of
335 /// the unique identifier to a fixed size (16 bytes).
336 pub fn fullyQualifiedNameHash(self: *Scope, name: []const u8) NameHash {
337 switch (self.tag) {
338 .block => unreachable,
339 .gen_zir => unreachable,
340 .decl => unreachable,
341 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),
342 .file => return self.cast(File).?.fullyQualifiedNameHash(name),
343 }
344 }
345
317346 /// Asserts the scope is a child of a File and has an AST tree and returns the tree.
318347 pub fn tree(self: *Scope) *ast.Tree {
319348 switch (self.tag) {
......@@ -321,6 +350,7 @@ pub const Scope = struct {
321350 .zir_module => unreachable,
322351 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(File).?.contents.tree,
323352 .block => return self.cast(Block).?.decl.scope.cast(File).?.contents.tree,
353 .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(File).?.contents.tree,
324354 }
325355 }
326356
......@@ -343,6 +373,7 @@ pub const Scope = struct {
343373 .file => return @fieldParentPtr(File, "base", base).sub_file_path,
344374 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,
345375 .block => unreachable,
376 .gen_zir => unreachable,
346377 .decl => unreachable,
347378 }
348379 }
......@@ -352,6 +383,7 @@ pub const Scope = struct {
352383 .file => return @fieldParentPtr(File, "base", base).unload(allocator),
353384 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).unload(allocator),
354385 .block => unreachable,
386 .gen_zir => unreachable,
355387 .decl => unreachable,
356388 }
357389 }
......@@ -360,6 +392,7 @@ pub const Scope = struct {
360392 switch (base.tag) {
361393 .file => return @fieldParentPtr(File, "base", base).getSource(module),
362394 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),
395 .gen_zir => unreachable,
363396 .block => unreachable,
364397 .decl => unreachable,
365398 }
......@@ -379,6 +412,7 @@ pub const Scope = struct {
379412 allocator.destroy(scope_zir_module);
380413 },
381414 .block => unreachable,
415 .gen_zir => unreachable,
382416 .decl => unreachable,
383417 }
384418 }
......@@ -390,6 +424,7 @@ pub const Scope = struct {
390424 file,
391425 block,
392426 decl,
427 gen_zir,
393428 };
394429
395430 pub const File = struct {
......@@ -461,6 +496,11 @@ pub const Scope = struct {
461496 .bytes => |bytes| return bytes,
462497 }
463498 }
499
500 pub fn fullyQualifiedNameHash(self: *File, name: []const u8) NameHash {
501 // We don't have struct scopes yet so this is currently just a simple name hash.
502 return std.zig.hashSrc(name);
503 }
464504 };
465505
466506 pub const ZIRModule = struct {
......@@ -541,6 +581,11 @@ pub const Scope = struct {
541581 .bytes => |bytes| return bytes,
542582 }
543583 }
584
585 pub fn fullyQualifiedNameHash(self: *ZIRModule, name: []const u8) NameHash {
586 // ZIR modules only have 1 file with all decls global in the same namespace.
587 return std.zig.hashSrc(name);
588 }
544589 };
545590
546591 /// This is a temporary structure, references to it are valid only
......@@ -548,7 +593,7 @@ pub const Scope = struct {
548593 pub const Block = struct {
549594 pub const base_tag: Tag = .block;
550595 base: Scope = Scope{ .tag = base_tag },
551 func: *Fn,
596 func: ?*Fn,
552597 decl: *Decl,
553598 instructions: ArrayListUnmanaged(*Inst),
554599 /// Points to the arena allocator of DeclAnalysis
......@@ -563,6 +608,16 @@ pub const Scope = struct {
563608 decl: *Decl,
564609 arena: std.heap.ArenaAllocator,
565610 };
611
612 /// This is a temporary structure, references to it are valid only
613 /// during semantic analysis of the decl.
614 pub const GenZIR = struct {
615 pub const base_tag: Tag = .gen_zir;
616 base: Scope = Scope{ .tag = base_tag },
617 decl: *Decl,
618 arena: std.heap.ArenaAllocator,
619 instructions: std.ArrayList(*zir.Inst),
620 };
566621};
567622
568623pub const Body = struct {
......@@ -656,7 +711,7 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
656711 .bin_file_path = options.bin_file_path,
657712 .bin_file = bin_file,
658713 .optimize_mode = options.optimize_mode,
659 .decl_table = std.AutoHashMap(Decl.Hash, *Decl).init(gpa),
714 .decl_table = std.AutoHashMap(Scope.NameHash, *Decl).init(gpa),
660715 .decl_exports = std.AutoHashMap(*Decl, []*Export).init(gpa),
661716 .export_owners = std.AutoHashMap(*Decl, []*Export).init(gpa),
662717 .failed_decls = std.AutoHashMap(*Decl, *ErrorMsg).init(gpa),
......@@ -765,14 +820,14 @@ pub fn update(self: *Module) !void {
765820 try self.deleteDecl(decl);
766821 }
767822
823 self.link_error_flags = self.bin_file.error_flags;
824
768825 // If there are any errors, we anticipate the source files being loaded
769826 // to report error messages. Otherwise we unload all source files to save memory.
770827 if (self.totalErrorCount() == 0) {
771828 self.root_scope.unload(self.allocator);
829 try self.bin_file.flush();
772830 }
773
774 try self.bin_file.flush();
775 self.link_error_flags = self.bin_file.error_flags;
776831}
777832
778833/// Having the file open for writing is problematic as far as executing the
......@@ -852,12 +907,14 @@ const InnerError = error{ OutOfMemory, AnalysisFail };
852907pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
853908 while (self.work_queue.readItem()) |work_item| switch (work_item) {
854909 .codegen_decl => |decl| switch (decl.analysis) {
910 .unreferenced => unreachable,
855911 .in_progress => unreachable,
856912 .outdated => unreachable,
857913
858914 .sema_failure,
859915 .codegen_failure,
860916 .dependency_failure,
917 .sema_failure_retryable,
861918 => continue,
862919
863920 .complete, .codegen_failure_retryable => {
......@@ -865,12 +922,10 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
865922 switch (payload.func.analysis) {
866923 .queued => self.analyzeFnBody(decl, payload.func) catch |err| switch (err) {
867924 error.AnalysisFail => {
868 if (payload.func.analysis == .queued) {
869 payload.func.analysis = .dependency_failure;
870 }
925 assert(payload.func.analysis != .in_progress);
871926 continue;
872927 },
873 else => |e| return e,
928 error.OutOfMemory => return error.OutOfMemory,
874929 },
875930 .in_progress => unreachable,
876931 .sema_failure, .dependency_failure => continue,
......@@ -889,7 +944,7 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
889944 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
890945 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
891946 self.allocator,
892 decl.src,
947 decl.src(),
893948 "unable to codegen: {}",
894949 .{@errorName(err)},
895950 ));
......@@ -899,6 +954,7 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
899954 },
900955 },
901956 .re_analyze_decl => |decl| switch (decl.analysis) {
957 .unreferenced => unreachable,
902958 .in_progress => unreachable,
903959
904960 .sema_failure,
......@@ -906,6 +962,7 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
906962 .dependency_failure,
907963 .complete,
908964 .codegen_failure_retryable,
965 .sema_failure_retryable,
909966 => continue,
910967
911968 .outdated => {
......@@ -918,7 +975,7 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
918975 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
919976 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
920977 self.allocator,
921 decl.src,
978 decl.src(),
922979 "unable to load source file '{}': {}",
923980 .{ zir_scope.sub_file_path, @errorName(err) },
924981 ));
......@@ -929,7 +986,8 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
929986 const decl_name = mem.spanZ(decl.name);
930987 // We already detected deletions, so we know this will be found.
931988 const src_decl = zir_module.findDecl(decl_name).?;
932 self.reAnalyzeDecl(decl, src_decl) catch |err| switch (err) {
989 decl.src_index = src_decl.index;
990 self.reAnalyzeDecl(decl, src_decl.decl) catch |err| switch (err) {
933991 error.OutOfMemory => return error.OutOfMemory,
934992 error.AnalysisFail => continue,
935993 };
......@@ -938,8 +996,8 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
938996 }
939997 },
940998 },
941 .ast_gen_decl => |item| {
942 self.astGenDecl(item.scope, item.ast_node) catch |err| switch (err) {
999 .analyze_decl => |decl| {
1000 self.ensureDeclAnalyzed(decl) catch |err| switch (err) {
9431001 error.OutOfMemory => return error.OutOfMemory,
9441002 error.AnalysisFail => continue,
9451003 };
......@@ -947,51 +1005,83 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
9471005 };
9481006}
9491007
950fn astGenDecl(self: *Module, parent_scope: *Scope, ast_node: *ast.Node) !void {
1008fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
1009 switch (decl.analysis) {
1010 .in_progress => unreachable,
1011 .outdated => unreachable,
1012
1013 .sema_failure,
1014 .sema_failure_retryable,
1015 .codegen_failure,
1016 .dependency_failure,
1017 .codegen_failure_retryable,
1018 => return error.AnalysisFail,
1019
1020 .complete => return,
1021
1022 .unreferenced => {
1023 self.astGenAndAnalyzeDecl(decl) catch |err| switch (err) {
1024 error.OutOfMemory => return error.OutOfMemory,
1025 error.AnalysisFail => return error.AnalysisFail,
1026 else => {
1027 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
1028 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
1029 self.allocator,
1030 decl.src(),
1031 "unable to analyze: {}",
1032 .{@errorName(err)},
1033 ));
1034 decl.analysis = .sema_failure_retryable;
1035 return error.AnalysisFail;
1036 },
1037 };
1038 },
1039 }
1040}
1041
1042fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !void {
1043 const file_scope = decl.scope.cast(Scope.File).?;
1044 const tree = try self.getAstTree(file_scope);
1045 const ast_node = tree.root_node.decls()[decl.src_index];
9511046 switch (ast_node.id) {
9521047 .FnProto => {
9531048 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", ast_node);
9541049
955 const name_tok = fn_proto.name_token orelse
956 return self.failTok(parent_scope, fn_proto.fn_token, "missing function name", .{});
957 const tree = parent_scope.tree();
958 const name_loc = tree.token_locs[name_tok];
959 const name = tree.tokenSliceLoc(name_loc);
960 const name_hash = Decl.hashSimpleName(name);
961 const contents_hash = std.zig.hashSrc(tree.getNodeSource(ast_node));
962 const new_decl = try self.createNewDecl(parent_scope, name, name_loc.start, name_hash, contents_hash);
963
964 // This DeclAnalysis scope's arena memory is discarded after the ZIR generation
965 // pass completes, and semantic analysis of it completes.
966 var gen_scope: Scope.DeclAnalysis = .{
967 .decl = new_decl,
1050 decl.analysis = .in_progress;
1051
1052 // This arena allocator's memory is discarded at the end of this function. It is used
1053 // to determine the type of the function, and hence the type of the decl, which is needed
1054 // to complete the Decl analysis.
1055 var fn_type_scope: Scope.GenZIR = .{
1056 .decl = decl,
9681057 .arena = std.heap.ArenaAllocator.init(self.allocator),
1058 .instructions = std.ArrayList(*zir.Inst).init(self.allocator),
9691059 };
970 // TODO free this memory
971 //defer gen_scope.arena.deinit();
1060 defer fn_type_scope.arena.deinit();
1061 defer fn_type_scope.instructions.deinit();
9721062
9731063 const body_node = fn_proto.body_node orelse
974 return self.failTok(&gen_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
1064 return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
9751065 if (fn_proto.params_len != 0) {
9761066 return self.failTok(
977 &gen_scope.base,
1067 &fn_type_scope.base,
9781068 fn_proto.params()[0].name_token.?,
9791069 "TODO implement function parameters",
9801070 .{},
9811071 );
9821072 }
9831073 if (fn_proto.lib_name) |lib_name| {
984 return self.failNode(&gen_scope.base, lib_name, "TODO implement function library name", .{});
1074 return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{});
9851075 }
9861076 if (fn_proto.align_expr) |align_expr| {
987 return self.failNode(&gen_scope.base, align_expr, "TODO implement function align expression", .{});
1077 return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{});
9881078 }
9891079 if (fn_proto.section_expr) |sect_expr| {
990 return self.failNode(&gen_scope.base, sect_expr, "TODO implement function section expression", .{});
1080 return self.failNode(&fn_type_scope.base, sect_expr, "TODO implement function section expression", .{});
9911081 }
9921082 if (fn_proto.callconv_expr) |callconv_expr| {
9931083 return self.failNode(
994 &gen_scope.base,
1084 &fn_type_scope.base,
9951085 callconv_expr,
9961086 "TODO implement function calling convention expression",
9971087 .{},
......@@ -999,82 +1089,94 @@ fn astGenDecl(self: *Module, parent_scope: *Scope, ast_node: *ast.Node) !void {
9991089 }
10001090 const return_type_expr = switch (fn_proto.return_type) {
10011091 .Explicit => |node| node,
1002 .InferErrorSet => |node| return self.failNode(&gen_scope.base, node, "TODO implement inferred error sets", .{}),
1003 .Invalid => |tok| return self.failTok(&gen_scope.base, tok, "unable to parse return type", .{}),
1092 .InferErrorSet => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement inferred error sets", .{}),
1093 .Invalid => |tok| return self.failTok(&fn_type_scope.base, tok, "unable to parse return type", .{}),
10041094 };
10051095
1006 const return_type_inst = try self.astGenExpr(&gen_scope.base, return_type_expr);
1007 const body_block = body_node.cast(ast.Node.Block).?;
1008 const body = try self.astGenBlock(&gen_scope.base, body_block);
1009 const fn_type_inst = try gen_scope.arena.allocator.create(zir.Inst.FnType);
1010 fn_type_inst.* = .{
1011 .base = .{
1012 .tag = zir.Inst.FnType.base_tag,
1013 .name = "",
1014 .src = name_loc.start,
1015 },
1016 .positionals = .{
1017 .return_type = return_type_inst,
1018 .param_types = &[0]*zir.Inst{},
1019 },
1020 .kw_args = .{},
1096 const return_type_inst = try self.astGenExpr(&fn_type_scope.base, return_type_expr);
1097 const fn_src = tree.token_locs[fn_proto.fn_token].start;
1098 const fn_type_inst = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.FnType, .{
1099 .return_type = return_type_inst,
1100 .param_types = &[0]*zir.Inst{},
1101 }, .{});
1102 _ = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.Return, .{ .operand = fn_type_inst }, .{});
1103
1104 // We need the memory for the Type to go into the arena for the Decl
1105 var decl_arena = std.heap.ArenaAllocator.init(self.allocator);
1106 errdefer decl_arena.deinit();
1107 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
1108
1109 var block_scope: Scope.Block = .{
1110 .func = null,
1111 .decl = decl,
1112 .instructions = .{},
1113 .arena = &decl_arena.allocator,
10211114 };
1022 const fn_inst = try gen_scope.arena.allocator.create(zir.Inst.Fn);
1023 fn_inst.* = .{
1024 .base = .{
1025 .tag = zir.Inst.Fn.base_tag,
1026 .name = name,
1027 .src = name_loc.start,
1028 .contents_hash = contents_hash,
1029 },
1030 .positionals = .{
1031 .fn_type = &fn_type_inst.base,
1032 .body = body,
1115 defer block_scope.instructions.deinit(self.allocator);
1116
1117 const fn_type = try self.analyzeBodyValueAsType(&block_scope, .{
1118 .instructions = fn_type_scope.instructions.items,
1119 });
1120 const new_func = try decl_arena.allocator.create(Fn);
1121 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
1122
1123 const fn_zir = blk: {
1124 // This scope's arena memory is discarded after the ZIR generation
1125 // pass completes, and semantic analysis of it completes.
1126 var gen_scope: Scope.GenZIR = .{
1127 .decl = decl,
1128 .arena = std.heap.ArenaAllocator.init(self.allocator),
1129 .instructions = std.ArrayList(*zir.Inst).init(self.allocator),
1130 };
1131 errdefer gen_scope.arena.deinit();
1132 defer gen_scope.instructions.deinit();
1133
1134 const body_block = body_node.cast(ast.Node.Block).?;
1135
1136 try self.astGenBlock(&gen_scope.base, body_block);
1137
1138 const fn_zir = try gen_scope.arena.allocator.create(Fn.ZIR);
1139 fn_zir.* = .{
1140 .body = .{
1141 .instructions = try gen_scope.arena.allocator.dupe(*zir.Inst, gen_scope.instructions.items),
1142 },
1143 .arena = gen_scope.arena.state,
1144 };
1145 break :blk fn_zir;
1146 };
1147
1148 new_func.* = .{
1149 .analysis = .{ .queued = fn_zir },
1150 .owner_decl = decl,
1151 };
1152 fn_payload.* = .{ .func = new_func };
1153
1154 decl_arena_state.* = decl_arena.state;
1155 decl.typed_value = .{
1156 .most_recent = .{
1157 .typed_value = .{
1158 .ty = fn_type,
1159 .val = Value.initPayload(&fn_payload.base),
1160 },
1161 .arena = decl_arena_state,
10331162 },
1034 .kw_args = .{},
10351163 };
1036 try self.analyzeNewDecl(new_decl, &fn_inst.base);
1164 decl.analysis = .complete;
1165 decl.generation = self.generation;
1166
1167 // We don't fully codegen the decl until later, but we do need to reserve a global
1168 // offset table index for it. This allows us to codegen decls out of dependency order,
1169 // increasing how many computations can be done in parallel.
1170 try self.bin_file.allocateDeclIndexes(decl);
1171 try self.work_queue.writeItem(.{ .codegen_decl = decl });
10371172
10381173 if (fn_proto.extern_export_inline_token) |maybe_export_token| {
10391174 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1040 var str_inst = zir.Inst.Str{
1041 .base = .{
1042 .tag = zir.Inst.Str.base_tag,
1043 .name = "",
1044 .src = name_loc.start,
1045 },
1046 .positionals = .{
1047 .bytes = name,
1048 },
1049 .kw_args = .{},
1050 };
1051 var ref_inst = zir.Inst.Ref{
1052 .base = .{
1053 .tag = zir.Inst.Ref.base_tag,
1054 .name = "",
1055 .src = name_loc.start,
1056 },
1057 .positionals = .{
1058 .operand = &str_inst.base,
1059 },
1060 .kw_args = .{},
1061 };
1062 var export_inst = zir.Inst.Export{
1063 .base = .{
1064 .tag = zir.Inst.Export.base_tag,
1065 .name = "",
1066 .src = name_loc.start,
1067 .contents_hash = contents_hash,
1068 },
1069 .positionals = .{
1070 .symbol_name = &ref_inst.base,
1071 .value = &fn_inst.base,
1072 },
1073 .kw_args = .{},
1074 };
1075 // Here we analyze the export using the arena that expires at the end of this
1076 // function call.
1077 try self.analyzeExport(&gen_scope.base, &export_inst);
1175 const export_src = tree.token_locs[maybe_export_token].start;
1176 const name_loc = tree.token_locs[fn_proto.name_token.?];
1177 const name = tree.tokenSliceLoc(name_loc);
1178 // The scope needs to have the decl in it.
1179 try self.analyzeExport(&block_scope.base, export_src, name, decl);
10781180 }
10791181 }
10801182 },
......@@ -1085,6 +1187,19 @@ fn astGenDecl(self: *Module, parent_scope: *Scope, ast_node: *ast.Node) !void {
10851187 }
10861188}
10871189
1190fn analyzeBodyValueAsType(self: *Module, block_scope: *Scope.Block, body: zir.Module.Body) !Type {
1191 try self.analyzeBody(&block_scope.base, body);
1192 for (block_scope.instructions.items) |inst| {
1193 if (inst.cast(Inst.Ret)) |ret| {
1194 const val = try self.resolveConstValue(&block_scope.base, ret.args.operand);
1195 return val.toType();
1196 } else {
1197 return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{});
1198 }
1199 }
1200 unreachable;
1201}
1202
10881203fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir.Inst {
10891204 switch (ast_node.id) {
10901205 .Identifier => return self.astGenIdent(scope, @fieldParentPtr(ast.Node.Identifier, "base", ast_node)),
......@@ -1092,11 +1207,33 @@ fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir
10921207 .StringLiteral => return self.astGenStringLiteral(scope, @fieldParentPtr(ast.Node.StringLiteral, "base", ast_node)),
10931208 .IntegerLiteral => return self.astGenIntegerLiteral(scope, @fieldParentPtr(ast.Node.IntegerLiteral, "base", ast_node)),
10941209 .BuiltinCall => return self.astGenBuiltinCall(scope, @fieldParentPtr(ast.Node.BuiltinCall, "base", ast_node)),
1210 .Call => return self.astGenCall(scope, @fieldParentPtr(ast.Node.Call, "base", ast_node)),
10951211 .Unreachable => return self.astGenUnreachable(scope, @fieldParentPtr(ast.Node.Unreachable, "base", ast_node)),
1212 .ControlFlowExpression => return self.astGenControlFlowExpression(scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)),
10961213 else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}),
10971214 }
10981215}
10991216
1217fn astGenControlFlowExpression(
1218 self: *Module,
1219 scope: *Scope,
1220 cfe: *ast.Node.ControlFlowExpression,
1221) InnerError!*zir.Inst {
1222 switch (cfe.kind) {
1223 .Break => return self.failNode(scope, &cfe.base, "TODO implement astGenExpr for Break", .{}),
1224 .Continue => return self.failNode(scope, &cfe.base, "TODO implement astGenExpr for Continue", .{}),
1225 .Return => {},
1226 }
1227 const tree = scope.tree();
1228 const src = tree.token_locs[cfe.ltoken].start;
1229 if (cfe.rhs) |rhs_node| {
1230 const operand = try self.astGenExpr(scope, rhs_node);
1231 return self.addZIRInst(scope, src, zir.Inst.Return, .{ .operand = operand }, .{});
1232 } else {
1233 return self.addZIRInst(scope, src, zir.Inst.ReturnVoid, .{}, .{});
1234 }
1235}
1236
11001237fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst {
11011238 const tree = scope.tree();
11021239 const ident_name = tree.tokenSlice(ident.token);
......@@ -1105,19 +1242,8 @@ fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerE
11051242 }
11061243
11071244 if (getSimplePrimitiveValue(ident_name)) |typed_value| {
1108 const const_inst = try scope.arena().create(zir.Inst.Const);
1109 const_inst.* = .{
1110 .base = .{
1111 .tag = zir.Inst.Const.base_tag,
1112 .name = "",
1113 .src = tree.token_locs[ident.token].start,
1114 },
1115 .positionals = .{
1116 .typed_value = typed_value,
1117 },
1118 .kw_args = .{},
1119 };
1120 return &const_inst.base;
1245 const src = tree.token_locs[ident.token].start;
1246 return self.addZIRInstConst(scope, src, typed_value);
11211247 }
11221248
11231249 if (ident_name.len >= 2) integer: {
......@@ -1137,7 +1263,15 @@ fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerE
11371263 }
11381264 }
11391265
1140 return self.failNode(scope, &ident.base, "TODO implement identifier lookup", .{});
1266 // Decl lookup
1267 const namespace = scope.namespace();
1268 const name_hash = namespace.fullyQualifiedNameHash(ident_name);
1269 if (self.decl_table.getValue(name_hash)) |decl| {
1270 const src = tree.token_locs[ident.token].start;
1271 return try self.addZIRInst(scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});
1272 }
1273
1274 return self.failNode(scope, &ident.base, "TODO implement local variable identifier lookup", .{});
11411275}
11421276
11431277fn astGenStringLiteral(self: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral) InnerError!*zir.Inst {
......@@ -1155,31 +1289,9 @@ fn astGenStringLiteral(self: *Module, scope: *Scope, str_lit: *ast.Node.StringLi
11551289 else => |e| return e,
11561290 };
11571291
1158 var str_inst = try arena.create(zir.Inst.Str);
1159 str_inst.* = .{
1160 .base = .{
1161 .tag = zir.Inst.Str.base_tag,
1162 .name = "",
1163 .src = tree.token_locs[str_lit.token].start,
1164 },
1165 .positionals = .{
1166 .bytes = bytes,
1167 },
1168 .kw_args = .{},
1169 };
1170 var ref_inst = try arena.create(zir.Inst.Ref);
1171 ref_inst.* = .{
1172 .base = .{
1173 .tag = zir.Inst.Ref.base_tag,
1174 .name = "",
1175 .src = tree.token_locs[str_lit.token].start,
1176 },
1177 .positionals = .{
1178 .operand = &str_inst.base,
1179 },
1180 .kw_args = .{},
1181 };
1182 return &ref_inst.base;
1292 const src = tree.token_locs[str_lit.token].start;
1293 const str_inst = try self.addZIRInst(scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
1294 return self.addZIRInst(scope, src, zir.Inst.Ref, .{ .operand = str_inst }, .{});
11831295}
11841296
11851297fn astGenIntegerLiteral(self: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral) InnerError!*zir.Inst {
......@@ -1195,48 +1307,25 @@ fn astGenIntegerLiteral(self: *Module, scope: *Scope, int_lit: *ast.Node.Integer
11951307 return self.failTok(scope, int_lit.token, "TODO implement 0b int prefix", .{});
11961308 }
11971309 if (std.fmt.parseInt(u64, bytes, 10)) |small_int| {
1198 var int_payload = try arena.create(Value.Payload.Int_u64);
1199 int_payload.* = .{
1200 .int = small_int,
1201 };
1202 var const_inst = try arena.create(zir.Inst.Const);
1203 const_inst.* = .{
1204 .base = .{
1205 .tag = zir.Inst.Const.base_tag,
1206 .name = "",
1207 .src = tree.token_locs[int_lit.token].start,
1208 },
1209 .positionals = .{
1210 .typed_value = .{
1211 .ty = Type.initTag(.comptime_int),
1212 .val = Value.initPayload(&int_payload.base),
1213 },
1214 },
1215 .kw_args = .{},
1216 };
1217 return &const_inst.base;
1310 const int_payload = try arena.create(Value.Payload.Int_u64);
1311 int_payload.* = .{ .int = small_int };
1312 const src = tree.token_locs[int_lit.token].start;
1313 return self.addZIRInstConst(scope, src, .{
1314 .ty = Type.initTag(.comptime_int),
1315 .val = Value.initPayload(&int_payload.base),
1316 });
12181317 } else |err| {
12191318 return self.failTok(scope, int_lit.token, "TODO implement int literals that don't fit in a u64", .{});
12201319 }
12211320}
12221321
1223fn astGenBlock(self: *Module, scope: *Scope, block_node: *ast.Node.Block) !zir.Module.Body {
1322fn astGenBlock(self: *Module, scope: *Scope, block_node: *ast.Node.Block) !void {
12241323 if (block_node.label) |label| {
12251324 return self.failTok(scope, label, "TODO implement labeled blocks", .{});
12261325 }
1227 const arena = scope.arena();
1228 var instructions = std.ArrayList(*zir.Inst).init(arena);
1229
1230 try instructions.ensureCapacity(block_node.statements_len);
1231
12321326 for (block_node.statements()) |statement| {
1233 const inst = try self.astGenExpr(scope, statement);
1234 instructions.appendAssumeCapacity(inst);
1327 _ = try self.astGenExpr(scope, statement);
12351328 }
1236
1237 return zir.Module.Body{
1238 .instructions = instructions.items,
1239 };
12401329}
12411330
12421331fn astGenAsm(self: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst {
......@@ -1255,84 +1344,59 @@ fn astGenAsm(self: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*
12551344 args[i] = try self.astGenExpr(scope, input.expr);
12561345 }
12571346
1258 const return_type = try arena.create(zir.Inst.Const);
1259 return_type.* = .{
1260 .base = .{
1261 .tag = zir.Inst.Const.base_tag,
1262 .name = "",
1263 .src = tree.token_locs[asm_node.asm_token].start,
1264 },
1265 .positionals = .{
1266 .typed_value = .{
1267 .ty = Type.initTag(.type),
1268 .val = Value.initTag(.void_type),
1269 },
1270 },
1271 .kw_args = .{},
1272 };
1273
1274 const asm_inst = try arena.create(zir.Inst.Asm);
1275 asm_inst.* = .{
1276 .base = .{
1277 .tag = zir.Inst.Asm.base_tag,
1278 .name = "",
1279 .src = tree.token_locs[asm_node.asm_token].start,
1280 },
1281 .positionals = .{
1282 .asm_source = try self.astGenExpr(scope, asm_node.template),
1283 .return_type = &return_type.base,
1284 },
1285 .kw_args = .{
1286 .@"volatile" = asm_node.volatile_token != null,
1287 //.clobbers = TODO handle clobbers
1288 .inputs = inputs,
1289 .args = args,
1290 },
1291 };
1292 return &asm_inst.base;
1347 const src = tree.token_locs[asm_node.asm_token].start;
1348 const return_type = try self.addZIRInstConst(scope, src, .{
1349 .ty = Type.initTag(.type),
1350 .val = Value.initTag(.void_type),
1351 });
1352 const asm_inst = try self.addZIRInst(scope, src, zir.Inst.Asm, .{
1353 .asm_source = try self.astGenExpr(scope, asm_node.template),
1354 .return_type = return_type,
1355 }, .{
1356 .@"volatile" = asm_node.volatile_token != null,
1357 //.clobbers = TODO handle clobbers
1358 .inputs = inputs,
1359 .args = args,
1360 });
1361 return asm_inst;
12931362}
12941363
12951364fn astGenBuiltinCall(self: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
12961365 const tree = scope.tree();
12971366 const builtin_name = tree.tokenSlice(call.builtin_token);
1298 const arena = scope.arena();
12991367
13001368 if (mem.eql(u8, builtin_name, "@ptrToInt")) {
13011369 if (call.params_len != 1) {
13021370 return self.failTok(scope, call.builtin_token, "expected 1 parameter, found {}", .{call.params_len});
13031371 }
1304 const ptrtoint = try arena.create(zir.Inst.PtrToInt);
1305 ptrtoint.* = .{
1306 .base = .{
1307 .tag = zir.Inst.PtrToInt.base_tag,
1308 .name = "",
1309 .src = tree.token_locs[call.builtin_token].start,
1310 },
1311 .positionals = .{
1312 .ptr = try self.astGenExpr(scope, call.params()[0]),
1313 },
1314 .kw_args = .{},
1315 };
1316 return &ptrtoint.base;
1372 const src = tree.token_locs[call.builtin_token].start;
1373 return self.addZIRInst(scope, src, zir.Inst.PtrToInt, .{
1374 .ptr = try self.astGenExpr(scope, call.params()[0]),
1375 }, .{});
13171376 } else {
13181377 return self.failTok(scope, call.builtin_token, "TODO implement builtin call for '{}'", .{builtin_name});
13191378 }
13201379}
13211380
1381fn astGenCall(self: *Module, scope: *Scope, call: *ast.Node.Call) InnerError!*zir.Inst {
1382 const tree = scope.tree();
1383
1384 if (call.params_len != 0) {
1385 return self.failNode(scope, &call.base, "TODO implement fn calls with parameters", .{});
1386 }
1387 const lhs = try self.astGenExpr(scope, call.lhs);
1388
1389 const src = tree.token_locs[call.lhs.firstToken()].start;
1390 return self.addZIRInst(scope, src, zir.Inst.Call, .{
1391 .func = lhs,
1392 .args = &[0]*zir.Inst{},
1393 }, .{});
1394}
1395
13221396fn astGenUnreachable(self: *Module, scope: *Scope, unreach_node: *ast.Node.Unreachable) InnerError!*zir.Inst {
13231397 const tree = scope.tree();
1324 const arena = scope.arena();
1325 const unreach = try arena.create(zir.Inst.Unreachable);
1326 unreach.* = .{
1327 .base = .{
1328 .tag = zir.Inst.Unreachable.base_tag,
1329 .name = "",
1330 .src = tree.token_locs[unreach_node.token].start,
1331 },
1332 .positionals = .{},
1333 .kw_args = .{},
1334 };
1335 return &unreach.base;
1398 const src = tree.token_locs[unreach_node.token].start;
1399 return self.addZIRInst(scope, src, zir.Inst.Unreachable, .{}, .{});
13361400}
13371401
13381402fn getSimplePrimitiveValue(name: []const u8) ?TypedValue {
......@@ -1501,19 +1565,23 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
15011565
15021566 try self.work_queue.ensureUnusedCapacity(decls.len);
15031567
1504 for (decls) |decl| {
1505 if (decl.cast(ast.Node.FnProto)) |proto_decl| {
1506 if (proto_decl.extern_export_inline_token) |maybe_export_token| {
1568 for (decls) |src_decl, decl_i| {
1569 if (src_decl.cast(ast.Node.FnProto)) |fn_proto| {
1570 // We will create a Decl for it regardless of analysis status.
1571 const name_tok = fn_proto.name_token orelse
1572 @panic("TODO handle missing function name in the parser");
1573 const name_loc = tree.token_locs[name_tok];
1574 const name = tree.tokenSliceLoc(name_loc);
1575 const name_hash = root_scope.fullyQualifiedNameHash(name);
1576 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1577 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
1578 if (fn_proto.extern_export_inline_token) |maybe_export_token| {
15071579 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1508 self.work_queue.writeItemAssumeCapacity(.{
1509 .ast_gen_decl = .{
1510 .ast_node = decl,
1511 .scope = &root_scope.base,
1512 },
1513 });
1580 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
15141581 }
15151582 }
15161583 }
1584 // TODO also look for global variable declarations
15171585 // TODO also look for comptime blocks and exported globals
15181586 }
15191587 },
......@@ -1567,7 +1635,7 @@ fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
15671635 }
15681636
15691637 for (src_module.decls) |src_decl| {
1570 const name_hash = Decl.hashSimpleName(src_decl.name);
1638 const name_hash = root_scope.fullyQualifiedNameHash(src_decl.name);
15711639 if (self.decl_table.get(name_hash)) |kv| {
15721640 const decl = kv.value;
15731641 deleted_decls.removeAssertDiscard(decl);
......@@ -1664,36 +1732,33 @@ fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {
16641732 // Use the Decl's arena for function memory.
16651733 var arena = decl.typed_value.most_recent.arena.?.promote(self.allocator);
16661734 defer decl.typed_value.most_recent.arena.?.* = arena.state;
1667 var analysis: Fn.Analysis = .{
1668 .inner_block = .{
1669 .func = func,
1670 .decl = decl,
1671 .instructions = .{},
1672 .arena = &arena.allocator,
1673 },
1674 .needed_inst_capacity = 0,
1675 .inst_table = std.AutoHashMap(*zir.Inst, *Inst).init(self.allocator),
1735 var inner_block: Scope.Block = .{
1736 .func = func,
1737 .decl = decl,
1738 .instructions = .{},
1739 .arena = &arena.allocator,
16761740 };
1677 defer analysis.inner_block.instructions.deinit(self.allocator);
1678 defer analysis.inst_table.deinit();
1741 defer inner_block.instructions.deinit(self.allocator);
16791742
1680 const fn_inst = func.analysis.queued;
1681 func.analysis = .{ .in_progress = &analysis };
1743 const fn_zir = func.analysis.queued;
1744 defer fn_zir.arena.promote(self.allocator).deinit();
1745 func.analysis = .{ .in_progress = {} };
1746 std.debug.warn("set {} to in_progress\n", .{decl.name});
16821747
1683 try self.analyzeBody(&analysis.inner_block.base, fn_inst.positionals.body);
1748 try self.analyzeBody(&inner_block.base, fn_zir.body);
16841749
1685 func.analysis = .{
1686 .success = .{
1687 .instructions = try arena.allocator.dupe(*Inst, analysis.inner_block.instructions.items),
1688 },
1689 };
1750 const instructions = try arena.allocator.dupe(*Inst, inner_block.instructions.items);
1751 func.analysis = .{ .success = .{ .instructions = instructions } };
1752 std.debug.warn("set {} to success\n", .{decl.name});
16901753}
16911754
16921755fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!void {
16931756 switch (decl.analysis) {
1757 .unreferenced => unreachable,
16941758 .in_progress => unreachable,
16951759 .dependency_failure,
16961760 .sema_failure,
1761 .sema_failure_retryable,
16971762 .codegen_failure,
16981763 .codegen_failure_retryable,
16991764 .complete,
......@@ -1702,7 +1767,6 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi
17021767 .outdated => {}, // Decl re-analysis
17031768 }
17041769 //std.debug.warn("re-analyzing {}\n", .{decl.name});
1705 decl.src = old_inst.src;
17061770
17071771 // The exports this Decl performs will be re-discovered, so we remove them here
17081772 // prior to re-analysis.
......@@ -1771,11 +1835,13 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi
17711835 if (type_changed or typed_value.val.tag() != .function) {
17721836 for (decl.dependants.items) |dep| {
17731837 switch (dep.analysis) {
1838 .unreferenced => unreachable,
17741839 .in_progress => unreachable,
17751840 .outdated => continue, // already queued for update
17761841
17771842 .dependency_failure,
17781843 .sema_failure,
1844 .sema_failure_retryable,
17791845 .codegen_failure,
17801846 .codegen_failure_retryable,
17811847 .complete,
......@@ -1799,16 +1865,16 @@ fn markOutdatedDecl(self: *Module, decl: *Decl) !void {
17991865fn allocateNewDecl(
18001866 self: *Module,
18011867 scope: *Scope,
1802 src: usize,
1868 src_index: usize,
18031869 contents_hash: std.zig.SrcHash,
18041870) !*Decl {
18051871 const new_decl = try self.allocator.create(Decl);
18061872 new_decl.* = .{
18071873 .name = "",
18081874 .scope = scope.namespace(),
1809 .src = src,
1875 .src_index = src_index,
18101876 .typed_value = .{ .never_succeeded = {} },
1811 .analysis = .in_progress,
1877 .analysis = .unreferenced,
18121878 .deletion_flag = false,
18131879 .contents_hash = contents_hash,
18141880 .link = link.ElfFile.TextBlock.empty,
......@@ -1821,12 +1887,12 @@ fn createNewDecl(
18211887 self: *Module,
18221888 scope: *Scope,
18231889 decl_name: []const u8,
1824 src: usize,
1825 name_hash: Decl.Hash,
1890 src_index: usize,
1891 name_hash: Scope.NameHash,
18261892 contents_hash: std.zig.SrcHash,
18271893) !*Decl {
18281894 try self.decl_table.ensureCapacity(self.decl_table.size + 1);
1829 const new_decl = try self.allocateNewDecl(scope, src, contents_hash);
1895 const new_decl = try self.allocateNewDecl(scope, src_index, contents_hash);
18301896 errdefer self.allocator.destroy(new_decl);
18311897 new_decl.name = try mem.dupeZ(self.allocator, u8, decl_name);
18321898 self.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
......@@ -1840,6 +1906,8 @@ fn analyzeNewDecl(self: *Module, new_decl: *Decl, old_inst: *zir.Inst) InnerErro
18401906 };
18411907 errdefer decl_scope.arena.deinit();
18421908
1909 new_decl.analysis = .in_progress;
1910
18431911 const typed_value = self.analyzeConstInst(&decl_scope.base, old_inst) catch |err| switch (err) {
18441912 error.OutOfMemory => return error.OutOfMemory,
18451913 error.AnalysisFail => {
......@@ -1873,37 +1941,40 @@ fn analyzeNewDecl(self: *Module, new_decl: *Decl, old_inst: *zir.Inst) InnerErro
18731941}
18741942
18751943fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl {
1876 if (old_inst.name.len == 0) {
1877 // If the name is empty, then we make this an anonymous Decl.
1878 const new_decl = try self.allocateNewDecl(scope, old_inst.src, old_inst.contents_hash);
1879 try self.analyzeNewDecl(new_decl, old_inst);
1880 return new_decl;
1881 }
1882 const name_hash = Decl.hashSimpleName(old_inst.name);
1883 if (self.decl_table.get(name_hash)) |kv| {
1884 const decl = kv.value;
1885 try self.reAnalyzeDecl(decl, old_inst);
1886 return decl;
1887 } else if (old_inst.cast(zir.Inst.DeclVal)) |decl_val| {
1888 // This is just a named reference to another decl.
1889 return self.analyzeDeclVal(scope, decl_val);
1890 } else {
1891 const new_decl = try self.createNewDecl(scope, old_inst.name, old_inst.src, name_hash, old_inst.contents_hash);
1892 try self.analyzeNewDecl(new_decl, old_inst);
1893
1894 return new_decl;
1895 }
1944 assert(old_inst.name.len == 0);
1945 // If the name is empty, then we make this an anonymous Decl.
1946 const scope_decl = scope.decl().?;
1947 const new_decl = try self.allocateNewDecl(scope, scope_decl.src_index, old_inst.contents_hash);
1948 try self.analyzeNewDecl(new_decl, old_inst);
1949 return new_decl;
1950 //const name_hash = Decl.hashSimpleName(old_inst.name);
1951 //if (self.decl_table.get(name_hash)) |kv| {
1952 // const decl = kv.value;
1953 // decl.src = old_inst.src;
1954 // try self.reAnalyzeDecl(decl, old_inst);
1955 // return decl;
1956 //} else if (old_inst.cast(zir.Inst.DeclVal)) |decl_val| {
1957 // // This is just a named reference to another decl.
1958 // return self.analyzeDeclVal(scope, decl_val);
1959 //} else {
1960 // const new_decl = try self.createNewDecl(scope, old_inst.name, old_inst.src, name_hash, old_inst.contents_hash);
1961 // try self.analyzeNewDecl(new_decl, old_inst);
1962
1963 // return new_decl;
1964 //}
18961965}
18971966
18981967/// Declares a dependency on the decl.
18991968fn resolveCompleteDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl {
19001969 const decl = try self.resolveDecl(scope, old_inst);
19011970 switch (decl.analysis) {
1971 .unreferenced => unreachable,
19021972 .in_progress => unreachable,
19031973 .outdated => unreachable,
19041974
19051975 .dependency_failure,
19061976 .sema_failure,
1977 .sema_failure_retryable,
19071978 .codegen_failure,
19081979 .codegen_failure_retryable,
19091980 => return error.AnalysisFail,
......@@ -1916,20 +1987,9 @@ fn resolveCompleteDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerE
19161987 return decl;
19171988}
19181989
1990/// TODO look into removing this function
19191991fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
1920 if (scope.cast(Scope.Block)) |block| {
1921 if (block.func.analysis.in_progress.inst_table.get(old_inst)) |kv| {
1922 return kv.value;
1923 }
1924 }
1925
1926 if (scope.namespace().tag == .zir_module) {
1927 const decl = try self.resolveCompleteDecl(scope, old_inst);
1928 const decl_ref = try self.analyzeDeclRef(scope, old_inst.src, decl);
1929 return self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src);
1930 }
1931
1932 return self.analyzeInst(scope, old_inst);
1992 return old_inst.analyzed_inst;
19331993}
19341994
19351995fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
......@@ -1977,21 +2037,15 @@ fn resolveType(self: *Module, scope: *Scope, old_inst: *zir.Inst) !Type {
19772037 return val.toType();
19782038}
19792039
1980fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) InnerError!void {
1981 try self.decl_exports.ensureCapacity(self.decl_exports.size + 1);
1982 try self.export_owners.ensureCapacity(self.export_owners.size + 1);
1983 const symbol_name = try self.resolveConstString(scope, export_inst.positionals.symbol_name);
1984 const exported_decl = try self.resolveCompleteDecl(scope, export_inst.positionals.value);
2040fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const u8, exported_decl: *Decl) !void {
19852041 const typed_value = exported_decl.typed_value.most_recent.typed_value;
19862042 switch (typed_value.ty.zigTypeTag()) {
19872043 .Fn => {},
1988 else => return self.fail(
1989 scope,
1990 export_inst.positionals.value.src,
1991 "unable to export type '{}'",
1992 .{typed_value.ty},
1993 ),
2044 else => return self.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}),
19942045 }
2046 try self.decl_exports.ensureCapacity(self.decl_exports.size + 1);
2047 try self.export_owners.ensureCapacity(self.export_owners.size + 1);
2048
19952049 const new_export = try self.allocator.create(Export);
19962050 errdefer self.allocator.destroy(new_export);
19972051
......@@ -1999,7 +2053,7 @@ fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) In
19992053
20002054 new_export.* = .{
20012055 .options = .{ .name = symbol_name },
2002 .src = export_inst.base.src,
2056 .src = src,
20032057 .link = .{},
20042058 .owner_decl = owner_decl,
20052059 .exported_decl = exported_decl,
......@@ -2030,7 +2084,7 @@ fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) In
20302084 try self.failed_exports.ensureCapacity(self.failed_exports.size + 1);
20312085 self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create(
20322086 self.allocator,
2033 export_inst.base.src,
2087 src,
20342088 "unable to export: {}",
20352089 .{@errorName(err)},
20362090 ));
......@@ -2039,7 +2093,6 @@ fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) In
20392093 };
20402094}
20412095
2042/// TODO should not need the cast on the last parameter at the callsites
20432096fn addNewInstArgs(
20442097 self: *Module,
20452098 block: *Scope.Block,
......@@ -2053,6 +2106,47 @@ fn addNewInstArgs(
20532106 return &inst.base;
20542107}
20552108
2109fn newZIRInst(
2110 allocator: *Allocator,
2111 src: usize,
2112 comptime T: type,
2113 positionals: std.meta.fieldInfo(T, "positionals").field_type,
2114 kw_args: std.meta.fieldInfo(T, "kw_args").field_type,
2115) !*zir.Inst {
2116 const inst = try allocator.create(T);
2117 inst.* = .{
2118 .base = .{
2119 .tag = T.base_tag,
2120 .name = "",
2121 .src = src,
2122 },
2123 .positionals = positionals,
2124 .kw_args = kw_args,
2125 };
2126 return &inst.base;
2127}
2128
2129fn addZIRInst(
2130 self: *Module,
2131 scope: *Scope,
2132 src: usize,
2133 comptime T: type,
2134 positionals: std.meta.fieldInfo(T, "positionals").field_type,
2135 kw_args: std.meta.fieldInfo(T, "kw_args").field_type,
2136) !*zir.Inst {
2137 const gen_zir = scope.cast(Scope.GenZIR).?;
2138 try gen_zir.instructions.ensureCapacity(gen_zir.instructions.items.len + 1);
2139 const inst = try newZIRInst(&gen_zir.arena.allocator, src, T, positionals, kw_args);
2140 gen_zir.instructions.appendAssumeCapacity(inst);
2141 return inst;
2142}
2143
2144/// TODO The existence of this function is a workaround for a bug in stage1.
2145fn addZIRInstConst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*zir.Inst {
2146 const P = std.meta.fieldInfo(zir.Inst.Const, "positionals").field_type;
2147 return self.addZIRInst(scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{});
2148}
2149
20562150fn addNewInst(self: *Module, block: *Scope.Block, src: usize, ty: Type, comptime T: type) !*T {
20572151 const inst = try block.arena.create(T);
20582152 inst.* = .{
......@@ -2107,6 +2201,13 @@ fn constVoid(self: *Module, scope: *Scope, src: usize) !*Inst {
21072201 });
21082202}
21092203
2204fn constNoReturn(self: *Module, scope: *Scope, src: usize) !*Inst {
2205 return self.constInst(scope, src, .{
2206 .ty = Type.initTag(.noreturn),
2207 .val = Value.initTag(.the_one_possible_value),
2208 });
2209}
2210
21102211fn constUndef(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {
21112212 return self.constInst(scope, src, .{
21122213 .ty = ty,
......@@ -2179,7 +2280,10 @@ fn analyzeConstInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerErro
21792280}
21802281
21812282fn analyzeInstConst(self: *Module, scope: *Scope, const_inst: *zir.Inst.Const) InnerError!*Inst {
2182 return self.constInst(scope, const_inst.base.src, const_inst.positionals.typed_value);
2283 // Move the TypedValue from old memory to new memory. This allows freeing the ZIR instructions
2284 // after analysis.
2285 const typed_value_copy = try const_inst.positionals.typed_value.copy(scope.arena());
2286 return self.constInst(scope, const_inst.base.src, typed_value_copy);
21832287}
21842288
21852289fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
......@@ -2190,6 +2294,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
21902294 .@"const" => return self.analyzeInstConst(scope, old_inst.cast(zir.Inst.Const).?),
21912295 .declref => return self.analyzeInstDeclRef(scope, old_inst.cast(zir.Inst.DeclRef).?),
21922296 .declval => return self.analyzeInstDeclVal(scope, old_inst.cast(zir.Inst.DeclVal).?),
2297 .declval_in_module => return self.analyzeInstDeclValInModule(scope, old_inst.cast(zir.Inst.DeclValInModule).?),
21932298 .str => {
21942299 const bytes = old_inst.cast(zir.Inst.Str).?.positionals.bytes;
21952300 // The bytes references memory inside the ZIR module, which can get deallocated
......@@ -2208,11 +2313,9 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
22082313 .@"asm" => return self.analyzeInstAsm(scope, old_inst.cast(zir.Inst.Asm).?),
22092314 .@"unreachable" => return self.analyzeInstUnreachable(scope, old_inst.cast(zir.Inst.Unreachable).?),
22102315 .@"return" => return self.analyzeInstRet(scope, old_inst.cast(zir.Inst.Return).?),
2316 .returnvoid => return self.analyzeInstRetVoid(scope, old_inst.cast(zir.Inst.ReturnVoid).?),
22112317 .@"fn" => return self.analyzeInstFn(scope, old_inst.cast(zir.Inst.Fn).?),
2212 .@"export" => {
2213 try self.analyzeExport(scope, old_inst.cast(zir.Inst.Export).?);
2214 return self.constVoid(scope, old_inst.src);
2215 },
2318 .@"export" => return self.analyzeInstExport(scope, old_inst.cast(zir.Inst.Export).?),
22162319 .primitive => return self.analyzeInstPrimitive(scope, old_inst.cast(zir.Inst.Primitive).?),
22172320 .ref => return self.analyzeInstRef(scope, old_inst.cast(zir.Inst.Ref).?),
22182321 .fntype => return self.analyzeInstFnType(scope, old_inst.cast(zir.Inst.FnType).?),
......@@ -2227,13 +2330,20 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
22272330 }
22282331}
22292332
2333fn analyzeInstExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) InnerError!*Inst {
2334 const symbol_name = try self.resolveConstString(scope, export_inst.positionals.symbol_name);
2335 const exported_decl = try self.resolveCompleteDecl(scope, export_inst.positionals.value);
2336 try self.analyzeExport(scope, export_inst.base.src, symbol_name, exported_decl);
2337 return self.constVoid(scope, export_inst.base.src);
2338}
2339
22302340fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.CompileError) InnerError!*Inst {
22312341 return self.fail(scope, inst.base.src, "{}", .{inst.positionals.msg});
22322342}
22332343
22342344fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoint) InnerError!*Inst {
22352345 const b = try self.requireRuntimeBlock(scope, inst.base.src);
2236 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){});
2346 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, {});
22372347}
22382348
22392349fn analyzeInstRef(self: *Module, scope: *Scope, inst: *zir.Inst.Ref) InnerError!*Inst {
......@@ -2251,7 +2361,7 @@ fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) Inn
22512361 const src_decl = zir_module.contents.module.findDecl(decl_name) orelse
22522362 return self.fail(scope, inst.positionals.name.src, "use of undeclared identifier '{}'", .{decl_name});
22532363
2254 const decl = try self.resolveCompleteDecl(scope, src_decl);
2364 const decl = try self.resolveCompleteDecl(scope, src_decl.decl);
22552365 return self.analyzeDeclRef(scope, inst.base.src, decl);
22562366 } else {
22572367 unreachable;
......@@ -2264,7 +2374,7 @@ fn analyzeDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerEr
22642374 const src_decl = zir_module.contents.module.findDecl(decl_name) orelse
22652375 return self.fail(scope, inst.base.src, "use of undeclared identifier '{}'", .{decl_name});
22662376
2267 const decl = try self.resolveCompleteDecl(scope, src_decl);
2377 const decl = try self.resolveCompleteDecl(scope, src_decl.decl);
22682378
22692379 return decl;
22702380}
......@@ -2275,12 +2385,34 @@ fn analyzeInstDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) Inn
22752385 return self.analyzeDeref(scope, inst.base.src, ptr, inst.base.src);
22762386}
22772387
2388fn analyzeInstDeclValInModule(self: *Module, scope: *Scope, inst: *zir.Inst.DeclValInModule) InnerError!*Inst {
2389 const decl = inst.positionals.decl;
2390 const ptr = try self.analyzeDeclRef(scope, inst.base.src, decl);
2391 return self.analyzeDeref(scope, inst.base.src, ptr, inst.base.src);
2392}
2393
22782394fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {
2395 const scope_decl = scope.decl().?;
2396 try self.declareDeclDependency(scope_decl, decl);
2397 self.ensureDeclAnalyzed(decl) catch |err| {
2398 if (scope.cast(Scope.Block)) |block| {
2399 if (block.func) |func| {
2400 func.analysis = .dependency_failure;
2401 } else {
2402 block.decl.analysis = .dependency_failure;
2403 }
2404 } else {
2405 scope_decl.analysis = .dependency_failure;
2406 }
2407 return err;
2408 };
2409
22792410 const decl_tv = try decl.typedValue();
22802411 const ty_payload = try scope.arena().create(Type.Payload.SingleConstPointer);
22812412 ty_payload.* = .{ .pointee_type = decl_tv.ty };
22822413 const val_payload = try scope.arena().create(Value.Payload.DeclRef);
22832414 val_payload.* = .{ .decl = decl };
2415
22842416 return self.constInst(scope, src, .{
22852417 .ty = Type.initPayload(&ty_payload.base),
22862418 .val = Value.initPayload(&val_payload.base),
......@@ -2345,26 +2477,26 @@ fn analyzeInstCall(self: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerErro
23452477 }
23462478
23472479 const b = try self.requireRuntimeBlock(scope, inst.base.src);
2348 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Call, Inst.Args(Inst.Call){
2480 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Call, .{
23492481 .func = func,
23502482 .args = casted_args,
23512483 });
23522484}
23532485
23542486fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst {
2355 const fn_type = try self.resolveType(scope, fn_inst.positionals.fn_type);
2356 const new_func = try scope.arena().create(Fn);
2357 new_func.* = .{
2358 .fn_type = fn_type,
2359 .analysis = .{ .queued = fn_inst },
2360 .owner_decl = scope.decl().?,
2361 };
2362 const fn_payload = try scope.arena().create(Value.Payload.Function);
2363 fn_payload.* = .{ .func = new_func };
2364 return self.constInst(scope, fn_inst.base.src, .{
2365 .ty = fn_type,
2366 .val = Value.initPayload(&fn_payload.base),
2367 });
2487 return self.fail(scope, fn_inst.base.src, "TODO implement ZIR fn inst", .{});
2488 //const fn_type = try self.resolveType(scope, fn_inst.positionals.fn_type);
2489 //const new_func = try scope.arena().create(Fn);
2490 //new_func.* = .{
2491 // .analysis = .{ .queued = fn_inst },
2492 // .owner_decl = scope.decl().?,
2493 //};
2494 //const fn_payload = try scope.arena().create(Value.Payload.Function);
2495 //fn_payload.* = .{ .func = new_func };
2496 //return self.constInst(scope, fn_inst.base.src, .{
2497 // .ty = fn_type,
2498 // .val = Value.initPayload(&fn_payload.base),
2499 //});
23682500}
23692501
23702502fn analyzeInstFnType(self: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
......@@ -2377,6 +2509,13 @@ fn analyzeInstFnType(self: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inn
23772509 return self.constType(scope, fntype.base.src, Type.initTag(.fn_noreturn_no_args));
23782510 }
23792511
2512 if (return_type.zigTypeTag() == .Void and
2513 fntype.positionals.param_types.len == 0 and
2514 fntype.kw_args.cc == .Unspecified)
2515 {
2516 return self.constType(scope, fntype.base.src, Type.initTag(.fn_void_no_args));
2517 }
2518
23802519 if (return_type.zigTypeTag() == .NoReturn and
23812520 fntype.positionals.param_types.len == 0 and
23822521 fntype.kw_args.cc == .Naked)
......@@ -2412,7 +2551,7 @@ fn analyzeInstPtrToInt(self: *Module, scope: *Scope, ptrtoint: *zir.Inst.PtrToIn
24122551 // TODO handle known-pointer-address
24132552 const b = try self.requireRuntimeBlock(scope, ptrtoint.base.src);
24142553 const ty = Type.initTag(.usize);
2415 return self.addNewInstArgs(b, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr });
2554 return self.addNewInstArgs(b, ptrtoint.base.src, ty, Inst.PtrToInt, .{ .ptr = ptr });
24162555}
24172556
24182557fn analyzeInstFieldPtr(self: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr) InnerError!*Inst {
......@@ -2604,7 +2743,7 @@ fn analyzeInstAsm(self: *Module, scope: *Scope, assembly: *zir.Inst.Asm) InnerEr
26042743 }
26052744
26062745 const b = try self.requireRuntimeBlock(scope, assembly.base.src);
2607 return self.addNewInstArgs(b, assembly.base.src, return_type, Inst.Assembly, Inst.Args(Inst.Assembly){
2746 return self.addNewInstArgs(b, assembly.base.src, return_type, Inst.Assembly, .{
26082747 .asm_source = asm_source,
26092748 .is_volatile = assembly.kw_args.@"volatile",
26102749 .output = output,
......@@ -2640,20 +2779,12 @@ fn analyzeInstCmp(self: *Module, scope: *Scope, inst: *zir.Inst.Cmp) InnerError!
26402779 }
26412780 const b = try self.requireRuntimeBlock(scope, inst.base.src);
26422781 switch (op) {
2643 .eq => return self.addNewInstArgs(
2644 b,
2645 inst.base.src,
2646 Type.initTag(.bool),
2647 Inst.IsNull,
2648 Inst.Args(Inst.IsNull){ .operand = opt_operand },
2649 ),
2650 .neq => return self.addNewInstArgs(
2651 b,
2652 inst.base.src,
2653 Type.initTag(.bool),
2654 Inst.IsNonNull,
2655 Inst.Args(Inst.IsNonNull){ .operand = opt_operand },
2656 ),
2782 .eq => return self.addNewInstArgs(b, inst.base.src, Type.initTag(.bool), Inst.IsNull, .{
2783 .operand = opt_operand,
2784 }),
2785 .neq => return self.addNewInstArgs(b, inst.base.src, Type.initTag(.bool), Inst.IsNonNull, .{
2786 .operand = opt_operand,
2787 }),
26572788 else => unreachable,
26582789 }
26592790 } else if (is_equality_cmp and
......@@ -2748,23 +2879,19 @@ fn analyzeInstUnreachable(self: *Module, scope: *Scope, unreach: *zir.Inst.Unrea
27482879}
27492880
27502881fn analyzeInstRet(self: *Module, scope: *Scope, inst: *zir.Inst.Return) InnerError!*Inst {
2882 const operand = try self.resolveInst(scope, inst.positionals.operand);
27512883 const b = try self.requireRuntimeBlock(scope, inst.base.src);
2752 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.Ret, {});
2884 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.Ret, .{ .operand = operand });
2885}
2886
2887fn analyzeInstRetVoid(self: *Module, scope: *Scope, inst: *zir.Inst.ReturnVoid) InnerError!*Inst {
2888 const b = try self.requireRuntimeBlock(scope, inst.base.src);
2889 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.RetVoid, {});
27532890}
27542891
27552892fn analyzeBody(self: *Module, scope: *Scope, body: zir.Module.Body) !void {
2756 if (scope.cast(Scope.Block)) |b| {
2757 const analysis = b.func.analysis.in_progress;
2758 analysis.needed_inst_capacity += body.instructions.len;
2759 try analysis.inst_table.ensureCapacity(analysis.needed_inst_capacity);
2760 for (body.instructions) |src_inst| {
2761 const new_inst = try self.analyzeInst(scope, src_inst);
2762 analysis.inst_table.putAssumeCapacityNoClobber(src_inst, new_inst);
2763 }
2764 } else {
2765 for (body.instructions) |src_inst| {
2766 _ = try self.analyzeInst(scope, src_inst);
2767 }
2893 for (body.instructions) |src_inst| {
2894 src_inst.analyzed_inst = try self.analyzeInst(scope, src_inst);
27682895 }
27692896}
27702897
......@@ -2847,7 +2974,7 @@ fn cmpNumeric(
28472974 };
28482975 const casted_lhs = try self.coerce(scope, dest_type, lhs);
28492976 const casted_rhs = try self.coerce(scope, dest_type, rhs);
2850 return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, Inst.Args(Inst.Cmp){
2977 return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, .{
28512978 .lhs = casted_lhs,
28522979 .rhs = casted_rhs,
28532980 .op = op,
......@@ -2951,7 +3078,7 @@ fn cmpNumeric(
29513078 const casted_lhs = try self.coerce(scope, dest_type, lhs);
29523079 const casted_rhs = try self.coerce(scope, dest_type, lhs);
29533080
2954 return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, Inst.Args(Inst.Cmp){
3081 return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, .{
29553082 .lhs = casted_lhs,
29563083 .rhs = casted_rhs,
29573084 .op = op,
......@@ -3028,7 +3155,7 @@ fn bitcast(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
30283155 }
30293156 // TODO validate the type size and other compile errors
30303157 const b = try self.requireRuntimeBlock(scope, inst.src);
3031 return self.addNewInstArgs(b, inst.src, dest_type, Inst.BitCast, Inst.Args(Inst.BitCast){ .operand = inst });
3158 return self.addNewInstArgs(b, inst.src, dest_type, Inst.BitCast, .{ .operand = inst });
30323159}
30333160
30343161fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
......@@ -3083,9 +3210,18 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err
30833210 },
30843211 .block => {
30853212 const block = scope.cast(Scope.Block).?;
3086 block.func.analysis = .sema_failure;
3213 if (block.func) |func| {
3214 func.analysis = .sema_failure;
3215 } else {
3216 block.decl.analysis = .sema_failure;
3217 }
30873218 self.failed_decls.putAssumeCapacityNoClobber(block.decl, err_msg);
30883219 },
3220 .gen_zir => {
3221 const gen_zir = scope.cast(Scope.GenZIR).?;
3222 gen_zir.decl.analysis = .sema_failure;
3223 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3224 },
30893225 .zir_module => {
30903226 const zir_module = scope.cast(Scope.ZIRModule).?;
30913227 zir_module.status = .loaded_sema_failure;
src-self-hosted/TypedValue.zig+8
......@@ -21,3 +21,11 @@ pub const Managed = struct {
2121 self.* = undefined;
2222 }
2323};
24
25/// Assumes arena allocation. Does a recursive copy.
26pub fn copy(self: TypedValue, allocator: *Allocator) error{OutOfMemory}!TypedValue {
27 return TypedValue{
28 .ty = try self.ty.copy(allocator),
29 .val = try self.val.copy(allocator),
30 };
31}
src-self-hosted/codegen.zig+16-3
......@@ -178,6 +178,7 @@ const Function = struct {
178178 .ptrtoint => return self.genPtrToInt(inst.cast(ir.Inst.PtrToInt).?),
179179 .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?),
180180 .ret => return self.genRet(inst.cast(ir.Inst.Ret).?),
181 .retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?),
181182 .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?),
182183 .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?),
183184 .isnull => return self.genIsNull(inst.cast(ir.Inst.IsNull).?),
......@@ -213,7 +214,7 @@ const Function = struct {
213214 try self.code.resize(self.code.items.len + 7);
214215 self.code.items[self.code.items.len - 7 ..][0..3].* = [3]u8{ 0xff, 0x14, 0x25 };
215216 mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], got_addr);
216 const return_type = func.fn_type.fnReturnType();
217 const return_type = func.owner_decl.typed_value.most_recent.typed_value.ty.fnReturnType();
217218 switch (return_type.zigTypeTag()) {
218219 .Void => return MCValue{ .none = {} },
219220 .NoReturn => return MCValue{ .unreach = {} },
......@@ -230,16 +231,28 @@ const Function = struct {
230231 }
231232 }
232233
233 fn genRet(self: *Function, inst: *ir.Inst.Ret) !MCValue {
234 fn ret(self: *Function, src: usize, mcv: MCValue) !MCValue {
235 if (mcv != .none) {
236 return self.fail(src, "TODO implement return with non-void operand", .{});
237 }
234238 switch (self.target.cpu.arch) {
235239 .i386, .x86_64 => {
236240 try self.code.append(0xc3); // ret
237241 },
238 else => return self.fail(inst.base.src, "TODO implement return for {}", .{self.target.cpu.arch}),
242 else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}),
239243 }
240244 return .unreach;
241245 }
242246
247 fn genRet(self: *Function, inst: *ir.Inst.Ret) !MCValue {
248 const operand = try self.resolveInst(inst.args.operand);
249 return self.ret(inst.base.src, operand);
250 }
251
252 fn genRetVoid(self: *Function, inst: *ir.Inst.RetVoid) !MCValue {
253 return self.ret(inst.base.src, .none);
254 }
255
243256 fn genCmp(self: *Function, inst: *ir.Inst.Cmp) !MCValue {
244257 switch (self.target.cpu.arch) {
245258 else => return self.fail(inst.base.src, "TODO implement cmp for {}", .{self.target.cpu.arch}),
src-self-hosted/ir.zig+9
......@@ -26,6 +26,7 @@ pub const Inst = struct {
2626 isnull,
2727 ptrtoint,
2828 ret,
29 retvoid,
2930 unreach,
3031 };
3132
......@@ -146,6 +147,14 @@ pub const Inst = struct {
146147 pub const Ret = struct {
147148 pub const base_tag = Tag.ret;
148149 base: Inst,
150 args: struct {
151 operand: *Inst,
152 },
153 };
154
155 pub const RetVoid = struct {
156 pub const base_tag = Tag.retvoid;
157 base: Inst,
149158 args: void,
150159 };
151160
src-self-hosted/link.zig+6-6
......@@ -956,10 +956,10 @@ pub const ElfFile = struct {
956956 try self.offset_table_free_list.ensureCapacity(self.allocator, self.local_symbols.items.len);
957957
958958 if (self.local_symbol_free_list.popOrNull()) |i| {
959 //std.debug.warn("reusing symbol index {} for {}\n", .{i, decl.name});
959 std.debug.warn("reusing symbol index {} for {}\n", .{i, decl.name});
960960 decl.link.local_sym_index = i;
961961 } else {
962 //std.debug.warn("allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name});
962 std.debug.warn("allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name});
963963 decl.link.local_sym_index = @intCast(u32, self.local_symbols.items.len);
964964 _ = self.local_symbols.addOneAssumeCapacity();
965965 }
......@@ -1002,7 +1002,7 @@ pub const ElfFile = struct {
10021002 defer code_buffer.deinit();
10031003
10041004 const typed_value = decl.typed_value.most_recent.typed_value;
1005 const code = switch (try codegen.generateSymbol(self, decl.src, typed_value, &code_buffer)) {
1005 const code = switch (try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer)) {
10061006 .externally_managed => |x| x,
10071007 .appended => code_buffer.items,
10081008 .fail => |em| {
......@@ -1027,11 +1027,11 @@ pub const ElfFile = struct {
10271027 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
10281028 if (need_realloc) {
10291029 const vaddr = try self.growTextBlock(&decl.link, code.len, required_alignment);
1030 //std.debug.warn("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
1030 std.debug.warn("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
10311031 if (vaddr != local_sym.st_value) {
10321032 local_sym.st_value = vaddr;
10331033
1034 //std.debug.warn(" (writing new offset table entry)\n", .{});
1034 std.debug.warn(" (writing new offset table entry)\n", .{});
10351035 self.offset_table.items[decl.link.offset_table_index] = vaddr;
10361036 try self.writeOffsetTableEntry(decl.link.offset_table_index);
10371037 }
......@@ -1049,7 +1049,7 @@ pub const ElfFile = struct {
10491049 const decl_name = mem.spanZ(decl.name);
10501050 const name_str_index = try self.makeString(decl_name);
10511051 const vaddr = try self.allocateTextBlock(&decl.link, code.len, required_alignment);
1052 //std.debug.warn("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
1052 std.debug.warn("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
10531053 errdefer self.freeTextBlock(&decl.link);
10541054
10551055 local_sym.* = .{
src-self-hosted/type.zig+96-1
......@@ -54,6 +54,7 @@ pub const Type = extern union {
5454 .@"undefined" => return .Undefined,
5555
5656 .fn_noreturn_no_args => return .Fn,
57 .fn_void_no_args => return .Fn,
5758 .fn_naked_noreturn_no_args => return .Fn,
5859 .fn_ccc_void_no_args => return .Fn,
5960
......@@ -163,6 +164,77 @@ pub const Type = extern union {
163164 }
164165 }
165166
167 pub fn copy(self: Type, allocator: *Allocator) error{OutOfMemory}!Type {
168 if (self.tag_if_small_enough < Tag.no_payload_count) {
169 return Type{ .tag_if_small_enough = self.tag_if_small_enough };
170 } else switch (self.ptr_otherwise.tag) {
171 .u8,
172 .i8,
173 .isize,
174 .usize,
175 .c_short,
176 .c_ushort,
177 .c_int,
178 .c_uint,
179 .c_long,
180 .c_ulong,
181 .c_longlong,
182 .c_ulonglong,
183 .c_longdouble,
184 .c_void,
185 .f16,
186 .f32,
187 .f64,
188 .f128,
189 .bool,
190 .void,
191 .type,
192 .anyerror,
193 .comptime_int,
194 .comptime_float,
195 .noreturn,
196 .@"null",
197 .@"undefined",
198 .fn_noreturn_no_args,
199 .fn_void_no_args,
200 .fn_naked_noreturn_no_args,
201 .fn_ccc_void_no_args,
202 .single_const_pointer_to_comptime_int,
203 .const_slice_u8,
204 => unreachable,
205
206 .array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0),
207 .array => {
208 const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
209 const new_payload = try allocator.create(Payload.Array);
210 new_payload.* = .{
211 .base = payload.base,
212 .len = payload.len,
213 .elem_type = try payload.elem_type.copy(allocator),
214 };
215 return Type{ .ptr_otherwise = &new_payload.base };
216 },
217 .single_const_pointer => {
218 const payload = @fieldParentPtr(Payload.SingleConstPointer, "base", self.ptr_otherwise);
219 const new_payload = try allocator.create(Payload.SingleConstPointer);
220 new_payload.* = .{
221 .base = payload.base,
222 .pointee_type = try payload.pointee_type.copy(allocator),
223 };
224 return Type{ .ptr_otherwise = &new_payload.base };
225 },
226 .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
227 .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
228 }
229 }
230
231 fn copyPayloadShallow(self: Type, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Type {
232 const payload = @fieldParentPtr(T, "base", self.ptr_otherwise);
233 const new_payload = try allocator.create(T);
234 new_payload.* = payload.*;
235 return Type{ .ptr_otherwise = &new_payload.base };
236 }
237
166238 pub fn format(
167239 self: Type,
168240 comptime fmt: []const u8,
......@@ -206,6 +278,7 @@ pub const Type = extern union {
206278
207279 .const_slice_u8 => return out_stream.writeAll("[]const u8"),
208280 .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),
281 .fn_void_no_args => return out_stream.writeAll("fn() void"),
209282 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
210283 .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),
211284 .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
......@@ -269,6 +342,7 @@ pub const Type = extern union {
269342 .@"null" => return Value.initTag(.null_type),
270343 .@"undefined" => return Value.initTag(.undefined_type),
271344 .fn_noreturn_no_args => return Value.initTag(.fn_noreturn_no_args_type),
345 .fn_void_no_args => return Value.initTag(.fn_void_no_args_type),
272346 .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type),
273347 .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),
274348 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
......@@ -303,6 +377,7 @@ pub const Type = extern union {
303377 .bool,
304378 .anyerror,
305379 .fn_noreturn_no_args,
380 .fn_void_no_args,
306381 .fn_naked_noreturn_no_args,
307382 .fn_ccc_void_no_args,
308383 .single_const_pointer_to_comptime_int,
......@@ -333,6 +408,7 @@ pub const Type = extern union {
333408 .i8,
334409 .bool,
335410 .fn_noreturn_no_args, // represents machine code; not a pointer
411 .fn_void_no_args, // represents machine code; not a pointer
336412 .fn_naked_noreturn_no_args, // represents machine code; not a pointer
337413 .fn_ccc_void_no_args, // represents machine code; not a pointer
338414 .array_u8_sentinel_0,
......@@ -420,6 +496,7 @@ pub const Type = extern union {
420496 .array_u8_sentinel_0,
421497 .const_slice_u8,
422498 .fn_noreturn_no_args,
499 .fn_void_no_args,
423500 .fn_naked_noreturn_no_args,
424501 .fn_ccc_void_no_args,
425502 .int_unsigned,
......@@ -466,6 +543,7 @@ pub const Type = extern union {
466543 .single_const_pointer,
467544 .single_const_pointer_to_comptime_int,
468545 .fn_noreturn_no_args,
546 .fn_void_no_args,
469547 .fn_naked_noreturn_no_args,
470548 .fn_ccc_void_no_args,
471549 .int_unsigned,
......@@ -509,6 +587,7 @@ pub const Type = extern union {
509587 .array,
510588 .array_u8_sentinel_0,
511589 .fn_noreturn_no_args,
590 .fn_void_no_args,
512591 .fn_naked_noreturn_no_args,
513592 .fn_ccc_void_no_args,
514593 .int_unsigned,
......@@ -553,6 +632,7 @@ pub const Type = extern union {
553632 .@"null",
554633 .@"undefined",
555634 .fn_noreturn_no_args,
635 .fn_void_no_args,
556636 .fn_naked_noreturn_no_args,
557637 .fn_ccc_void_no_args,
558638 .int_unsigned,
......@@ -597,6 +677,7 @@ pub const Type = extern union {
597677 .@"null",
598678 .@"undefined",
599679 .fn_noreturn_no_args,
680 .fn_void_no_args,
600681 .fn_naked_noreturn_no_args,
601682 .fn_ccc_void_no_args,
602683 .single_const_pointer,
......@@ -642,6 +723,7 @@ pub const Type = extern union {
642723 .@"null",
643724 .@"undefined",
644725 .fn_noreturn_no_args,
726 .fn_void_no_args,
645727 .fn_naked_noreturn_no_args,
646728 .fn_ccc_void_no_args,
647729 .single_const_pointer,
......@@ -675,6 +757,7 @@ pub const Type = extern union {
675757 .@"null",
676758 .@"undefined",
677759 .fn_noreturn_no_args,
760 .fn_void_no_args,
678761 .fn_naked_noreturn_no_args,
679762 .fn_ccc_void_no_args,
680763 .array,
......@@ -721,6 +804,7 @@ pub const Type = extern union {
721804 .@"null",
722805 .@"undefined",
723806 .fn_noreturn_no_args,
807 .fn_void_no_args,
724808 .fn_naked_noreturn_no_args,
725809 .fn_ccc_void_no_args,
726810 .array,
......@@ -777,6 +861,7 @@ pub const Type = extern union {
777861 pub fn fnParamLen(self: Type) usize {
778862 return switch (self.tag()) {
779863 .fn_noreturn_no_args => 0,
864 .fn_void_no_args => 0,
780865 .fn_naked_noreturn_no_args => 0,
781866 .fn_ccc_void_no_args => 0,
782867
......@@ -823,6 +908,7 @@ pub const Type = extern union {
823908 pub fn fnParamTypes(self: Type, types: []Type) void {
824909 switch (self.tag()) {
825910 .fn_noreturn_no_args => return,
911 .fn_void_no_args => return,
826912 .fn_naked_noreturn_no_args => return,
827913 .fn_ccc_void_no_args => return,
828914
......@@ -869,7 +955,10 @@ pub const Type = extern union {
869955 return switch (self.tag()) {
870956 .fn_noreturn_no_args => Type.initTag(.noreturn),
871957 .fn_naked_noreturn_no_args => Type.initTag(.noreturn),
872 .fn_ccc_void_no_args => Type.initTag(.void),
958
959 .fn_void_no_args,
960 .fn_ccc_void_no_args,
961 => Type.initTag(.void),
873962
874963 .f16,
875964 .f32,
......@@ -913,6 +1002,7 @@ pub const Type = extern union {
9131002 pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {
9141003 return switch (self.tag()) {
9151004 .fn_noreturn_no_args => .Unspecified,
1005 .fn_void_no_args => .Unspecified,
9161006 .fn_naked_noreturn_no_args => .Naked,
9171007 .fn_ccc_void_no_args => .C,
9181008
......@@ -958,6 +1048,7 @@ pub const Type = extern union {
9581048 pub fn fnIsVarArgs(self: Type) bool {
9591049 return switch (self.tag()) {
9601050 .fn_noreturn_no_args => false,
1051 .fn_void_no_args => false,
9611052 .fn_naked_noreturn_no_args => false,
9621053 .fn_ccc_void_no_args => false,
9631054
......@@ -1033,6 +1124,7 @@ pub const Type = extern union {
10331124 .@"null",
10341125 .@"undefined",
10351126 .fn_noreturn_no_args,
1127 .fn_void_no_args,
10361128 .fn_naked_noreturn_no_args,
10371129 .fn_ccc_void_no_args,
10381130 .array,
......@@ -1070,6 +1162,7 @@ pub const Type = extern union {
10701162 .type,
10711163 .anyerror,
10721164 .fn_noreturn_no_args,
1165 .fn_void_no_args,
10731166 .fn_naked_noreturn_no_args,
10741167 .fn_ccc_void_no_args,
10751168 .single_const_pointer_to_comptime_int,
......@@ -1126,6 +1219,7 @@ pub const Type = extern union {
11261219 .type,
11271220 .anyerror,
11281221 .fn_noreturn_no_args,
1222 .fn_void_no_args,
11291223 .fn_naked_noreturn_no_args,
11301224 .fn_ccc_void_no_args,
11311225 .single_const_pointer_to_comptime_int,
......@@ -1180,6 +1274,7 @@ pub const Type = extern union {
11801274 @"null",
11811275 @"undefined",
11821276 fn_noreturn_no_args,
1277 fn_void_no_args,
11831278 fn_naked_noreturn_no_args,
11841279 fn_ccc_void_no_args,
11851280 single_const_pointer_to_comptime_int,
src-self-hosted/value.zig+115-5
......@@ -49,6 +49,7 @@ pub const Value = extern union {
4949 null_type,
5050 undefined_type,
5151 fn_noreturn_no_args_type,
52 fn_void_no_args_type,
5253 fn_naked_noreturn_no_args_type,
5354 fn_ccc_void_no_args_type,
5455 single_const_pointer_to_comptime_int_type,
......@@ -107,6 +108,109 @@ pub const Value = extern union {
107108 return @fieldParentPtr(T, "base", self.ptr_otherwise);
108109 }
109110
111 pub fn copy(self: Value, allocator: *Allocator) error{OutOfMemory}!Value {
112 if (self.tag_if_small_enough < Tag.no_payload_count) {
113 return Value{ .tag_if_small_enough = self.tag_if_small_enough };
114 } else switch (self.ptr_otherwise.tag) {
115 .u8_type,
116 .i8_type,
117 .isize_type,
118 .usize_type,
119 .c_short_type,
120 .c_ushort_type,
121 .c_int_type,
122 .c_uint_type,
123 .c_long_type,
124 .c_ulong_type,
125 .c_longlong_type,
126 .c_ulonglong_type,
127 .c_longdouble_type,
128 .f16_type,
129 .f32_type,
130 .f64_type,
131 .f128_type,
132 .c_void_type,
133 .bool_type,
134 .void_type,
135 .type_type,
136 .anyerror_type,
137 .comptime_int_type,
138 .comptime_float_type,
139 .noreturn_type,
140 .null_type,
141 .undefined_type,
142 .fn_noreturn_no_args_type,
143 .fn_void_no_args_type,
144 .fn_naked_noreturn_no_args_type,
145 .fn_ccc_void_no_args_type,
146 .single_const_pointer_to_comptime_int_type,
147 .const_slice_u8_type,
148 .undef,
149 .zero,
150 .the_one_possible_value,
151 .null_value,
152 .bool_true,
153 .bool_false,
154 => unreachable,
155
156 .ty => {
157 const payload = @fieldParentPtr(Payload.Ty, "base", self.ptr_otherwise);
158 const new_payload = try allocator.create(Payload.Ty);
159 new_payload.* = .{
160 .base = payload.base,
161 .ty = try payload.ty.copy(allocator),
162 };
163 return Value{ .ptr_otherwise = &new_payload.base };
164 },
165 .int_u64 => return self.copyPayloadShallow(allocator, Payload.Int_u64),
166 .int_i64 => return self.copyPayloadShallow(allocator, Payload.Int_i64),
167 .int_big_positive => {
168 @panic("TODO implement copying of big ints");
169 },
170 .int_big_negative => {
171 @panic("TODO implement copying of big ints");
172 },
173 .function => return self.copyPayloadShallow(allocator, Payload.Function),
174 .ref_val => {
175 const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
176 const new_payload = try allocator.create(Payload.RefVal);
177 new_payload.* = .{
178 .base = payload.base,
179 .val = try payload.val.copy(allocator),
180 };
181 return Value{ .ptr_otherwise = &new_payload.base };
182 },
183 .decl_ref => return self.copyPayloadShallow(allocator, Payload.DeclRef),
184 .elem_ptr => {
185 const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise);
186 const new_payload = try allocator.create(Payload.ElemPtr);
187 new_payload.* = .{
188 .base = payload.base,
189 .array_ptr = try payload.array_ptr.copy(allocator),
190 .index = payload.index,
191 };
192 return Value{ .ptr_otherwise = &new_payload.base };
193 },
194 .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
195 .repeated => {
196 const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
197 const new_payload = try allocator.create(Payload.Repeated);
198 new_payload.* = .{
199 .base = payload.base,
200 .val = try payload.val.copy(allocator),
201 };
202 return Value{ .ptr_otherwise = &new_payload.base };
203 },
204 }
205 }
206
207 fn copyPayloadShallow(self: Value, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Value {
208 const payload = @fieldParentPtr(T, "base", self.ptr_otherwise);
209 const new_payload = try allocator.create(T);
210 new_payload.* = payload.*;
211 return Value{ .ptr_otherwise = &new_payload.base };
212 }
213
110214 pub fn format(
111215 self: Value,
112216 comptime fmt: []const u8,
......@@ -144,6 +248,7 @@ pub const Value = extern union {
144248 .null_type => return out_stream.writeAll("@TypeOf(null)"),
145249 .undefined_type => return out_stream.writeAll("@TypeOf(undefined)"),
146250 .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"),
251 .fn_void_no_args_type => return out_stream.writeAll("fn() void"),
147252 .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
148253 .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
149254 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
......@@ -229,6 +334,7 @@ pub const Value = extern union {
229334 .null_type => Type.initTag(.@"null"),
230335 .undefined_type => Type.initTag(.@"undefined"),
231336 .fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args),
337 .fn_void_no_args_type => Type.initTag(.fn_void_no_args),
232338 .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),
233339 .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),
234340 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
......@@ -286,6 +392,7 @@ pub const Value = extern union {
286392 .null_type,
287393 .undefined_type,
288394 .fn_noreturn_no_args_type,
395 .fn_void_no_args_type,
289396 .fn_naked_noreturn_no_args_type,
290397 .fn_ccc_void_no_args_type,
291398 .single_const_pointer_to_comptime_int_type,
......@@ -345,6 +452,7 @@ pub const Value = extern union {
345452 .null_type,
346453 .undefined_type,
347454 .fn_noreturn_no_args_type,
455 .fn_void_no_args_type,
348456 .fn_naked_noreturn_no_args_type,
349457 .fn_ccc_void_no_args_type,
350458 .single_const_pointer_to_comptime_int_type,
......@@ -405,6 +513,7 @@ pub const Value = extern union {
405513 .null_type,
406514 .undefined_type,
407515 .fn_noreturn_no_args_type,
516 .fn_void_no_args_type,
408517 .fn_naked_noreturn_no_args_type,
409518 .fn_ccc_void_no_args_type,
410519 .single_const_pointer_to_comptime_int_type,
......@@ -470,6 +579,7 @@ pub const Value = extern union {
470579 .null_type,
471580 .undefined_type,
472581 .fn_noreturn_no_args_type,
582 .fn_void_no_args_type,
473583 .fn_naked_noreturn_no_args_type,
474584 .fn_ccc_void_no_args_type,
475585 .single_const_pointer_to_comptime_int_type,
......@@ -564,6 +674,7 @@ pub const Value = extern union {
564674 .null_type,
565675 .undefined_type,
566676 .fn_noreturn_no_args_type,
677 .fn_void_no_args_type,
567678 .fn_naked_noreturn_no_args_type,
568679 .fn_ccc_void_no_args_type,
569680 .single_const_pointer_to_comptime_int_type,
......@@ -620,6 +731,7 @@ pub const Value = extern union {
620731 .null_type,
621732 .undefined_type,
622733 .fn_noreturn_no_args_type,
734 .fn_void_no_args_type,
623735 .fn_naked_noreturn_no_args_type,
624736 .fn_ccc_void_no_args_type,
625737 .single_const_pointer_to_comptime_int_type,
......@@ -721,6 +833,7 @@ pub const Value = extern union {
721833 .null_type,
722834 .undefined_type,
723835 .fn_noreturn_no_args_type,
836 .fn_void_no_args_type,
724837 .fn_naked_noreturn_no_args_type,
725838 .fn_ccc_void_no_args_type,
726839 .single_const_pointer_to_comptime_int_type,
......@@ -783,6 +896,7 @@ pub const Value = extern union {
783896 .null_type,
784897 .undefined_type,
785898 .fn_noreturn_no_args_type,
899 .fn_void_no_args_type,
786900 .fn_naked_noreturn_no_args_type,
787901 .fn_ccc_void_no_args_type,
788902 .single_const_pointer_to_comptime_int_type,
......@@ -862,6 +976,7 @@ pub const Value = extern union {
862976 .null_type,
863977 .undefined_type,
864978 .fn_noreturn_no_args_type,
979 .fn_void_no_args_type,
865980 .fn_naked_noreturn_no_args_type,
866981 .fn_ccc_void_no_args_type,
867982 .single_const_pointer_to_comptime_int_type,
......@@ -929,11 +1044,6 @@ pub const Value = extern union {
9291044 len: u64,
9301045 };
9311046
932 pub const SingleConstPtrType = struct {
933 base: Payload = Payload{ .tag = .single_const_ptr_type },
934 elem_type: *Type,
935 };
936
9371047 /// Represents a pointer to another immutable value.
9381048 pub const RefVal = struct {
9391049 base: Payload = Payload{ .tag = .ref_val },
src-self-hosted/zir.zig+66-8
......@@ -25,6 +25,9 @@ pub const Inst = struct {
2525 /// Hash of slice into the source of the part after the = and before the next instruction.
2626 contents_hash: std.zig.SrcHash = undefined,
2727
28 /// Pre-allocated field for mapping ZIR text instructions to post-analysis instructions.
29 analyzed_inst: *ir.Inst = undefined,
30
2831 /// These names are used directly as the instruction names in the text format.
2932 pub const Tag = enum {
3033 breakpoint,
......@@ -37,6 +40,8 @@ pub const Inst = struct {
3740 /// The syntax `@foo` is equivalent to `declval("foo")`.
3841 /// declval is equivalent to declref followed by deref.
3942 declval,
43 /// Same as declval but the parameter is a `*Module.Decl` rather than a name.
44 declval_in_module,
4045 str,
4146 int,
4247 ptrtoint,
......@@ -46,6 +51,7 @@ pub const Inst = struct {
4651 @"asm",
4752 @"unreachable",
4853 @"return",
54 returnvoid,
4955 @"fn",
5056 fntype,
5157 @"export",
......@@ -67,6 +73,7 @@ pub const Inst = struct {
6773 .call => Call,
6874 .declref => DeclRef,
6975 .declval => DeclVal,
76 .declval_in_module => DeclValInModule,
7077 .compileerror => CompileError,
7178 .@"const" => Const,
7279 .str => Str,
......@@ -78,6 +85,7 @@ pub const Inst = struct {
7885 .@"asm" => Asm,
7986 .@"unreachable" => Unreachable,
8087 .@"return" => Return,
88 .returnvoid => ReturnVoid,
8189 .@"fn" => Fn,
8290 .@"export" => Export,
8391 .primitive => Primitive,
......@@ -142,6 +150,16 @@ pub const Inst = struct {
142150 kw_args: struct {},
143151 };
144152
153 pub const DeclValInModule = struct {
154 pub const base_tag = Tag.declval_in_module;
155 base: Inst,
156
157 positionals: struct {
158 decl: *IrModule.Decl,
159 },
160 kw_args: struct {},
161 };
162
145163 pub const CompileError = struct {
146164 pub const base_tag = Tag.compileerror;
147165 base: Inst,
......@@ -253,6 +271,16 @@ pub const Inst = struct {
253271 pub const base_tag = Tag.@"return";
254272 base: Inst,
255273
274 positionals: struct {
275 operand: *Inst,
276 },
277 kw_args: struct {},
278 };
279
280 pub const ReturnVoid = struct {
281 pub const base_tag = Tag.returnvoid;
282 base: Inst,
283
256284 positionals: struct {},
257285 kw_args: struct {},
258286 };
......@@ -492,11 +520,19 @@ pub const Module = struct {
492520
493521 const InstPtrTable = std.AutoHashMap(*Inst, struct { inst: *Inst, index: ?usize });
494522
523 const DeclAndIndex = struct {
524 decl: *Inst,
525 index: usize,
526 };
527
495528 /// TODO Look into making a table to speed this up.
496 pub fn findDecl(self: Module, name: []const u8) ?*Inst {
497 for (self.decls) |decl| {
529 pub fn findDecl(self: Module, name: []const u8) ?DeclAndIndex {
530 for (self.decls) |decl, i| {
498531 if (mem.eql(u8, decl.name, name)) {
499 return decl;
532 return DeclAndIndex{
533 .decl = decl,
534 .index = i,
535 };
500536 }
501537 }
502538 return null;
......@@ -540,6 +576,7 @@ pub const Module = struct {
540576 .call => return self.writeInstToStreamGeneric(stream, .call, decl, inst_table),
541577 .declref => return self.writeInstToStreamGeneric(stream, .declref, decl, inst_table),
542578 .declval => return self.writeInstToStreamGeneric(stream, .declval, decl, inst_table),
579 .declval_in_module => return self.writeInstToStreamGeneric(stream, .declval_in_module, decl, inst_table),
543580 .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, decl, inst_table),
544581 .@"const" => return self.writeInstToStreamGeneric(stream, .@"const", decl, inst_table),
545582 .str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table),
......@@ -551,6 +588,7 @@ pub const Module = struct {
551588 .@"asm" => return self.writeInstToStreamGeneric(stream, .@"asm", decl, inst_table),
552589 .@"unreachable" => return self.writeInstToStreamGeneric(stream, .@"unreachable", decl, inst_table),
553590 .@"return" => return self.writeInstToStreamGeneric(stream, .@"return", decl, inst_table),
591 .returnvoid => return self.writeInstToStreamGeneric(stream, .returnvoid, decl, inst_table),
554592 .@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", decl, inst_table),
555593 .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", decl, inst_table),
556594 .ref => return self.writeInstToStreamGeneric(stream, .ref, decl, inst_table),
......@@ -636,6 +674,7 @@ pub const Module = struct {
636674 []u8, []const u8 => return std.zig.renderStringLiteral(param, stream),
637675 BigIntConst => return stream.print("{}", .{param}),
638676 TypedValue => unreachable, // this is a special case
677 *IrModule.Decl => unreachable, // this is a special case
639678 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
640679 }
641680 }
......@@ -649,6 +688,8 @@ pub const Module = struct {
649688 }
650689 } else if (inst.cast(Inst.DeclVal)) |decl_val| {
651690 try stream.print("@{}", .{decl_val.positionals.name});
691 } else if (inst.cast(Inst.DeclValInModule)) |decl_val| {
692 try stream.print("@{}", .{decl_val.positionals.decl.name});
652693 } else {
653694 //try stream.print("?", .{});
654695 unreachable;
......@@ -996,6 +1037,7 @@ const Parser = struct {
9961037 []u8, []const u8 => return self.parseStringLiteral(),
9971038 BigIntConst => return self.parseIntegerLiteral(),
9981039 TypedValue => return self.fail("'const' is a special instruction; not legal in ZIR text", .{}),
1040 *IrModule.Decl => return self.fail("'declval_in_module' is a special instruction; not legal in ZIR text", .{}),
9991041 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
10001042 }
10011043 return self.fail("TODO parse parameter {}", .{@typeName(T)});
......@@ -1105,7 +1147,7 @@ const EmitZIR = struct {
11051147 }
11061148 std.sort.sort(*IrModule.Decl, src_decls.items, {}, (struct {
11071149 fn lessThan(context: void, a: *IrModule.Decl, b: *IrModule.Decl) bool {
1108 return a.src < b.src;
1150 return a.src_index < b.src_index;
11091151 }
11101152 }).lessThan);
11111153
......@@ -1113,7 +1155,7 @@ const EmitZIR = struct {
11131155 for (src_decls.items) |ir_decl| {
11141156 if (self.old_module.export_owners.getValue(ir_decl)) |exports| {
11151157 for (exports) |module_export| {
1116 const declval = try self.emitDeclVal(ir_decl.src, mem.spanZ(module_export.exported_decl.name));
1158 const declval = try self.emitDeclVal(ir_decl.src(), mem.spanZ(module_export.exported_decl.name));
11171159 const symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name);
11181160 const export_inst = try self.arena.allocator.create(Inst.Export);
11191161 export_inst.* = .{
......@@ -1131,7 +1173,7 @@ const EmitZIR = struct {
11311173 try self.decls.append(self.allocator, &export_inst.base);
11321174 }
11331175 } else {
1134 const new_decl = try self.emitTypedValue(ir_decl.src, ir_decl.typed_value.most_recent.typed_value);
1176 const new_decl = try self.emitTypedValue(ir_decl.src(), ir_decl.typed_value.most_recent.typed_value);
11351177 new_decl.name = try self.arena.allocator.dupe(u8, mem.spanZ(ir_decl.name));
11361178 }
11371179 }
......@@ -1301,7 +1343,7 @@ const EmitZIR = struct {
13011343 },
13021344 }
13031345
1304 const fn_type = try self.emitType(src, module_fn.fn_type);
1346 const fn_type = try self.emitType(src, typed_value.ty);
13051347
13061348 const arena_instrs = try self.arena.allocator.alloc(*Inst, instructions.items.len);
13071349 mem.copy(*Inst, arena_instrs, instructions.items);
......@@ -1399,7 +1441,23 @@ const EmitZIR = struct {
13991441 break :blk &new_inst.base;
14001442 },
14011443 .unreach => try self.emitTrivial(inst.src, Inst.Unreachable),
1402 .ret => try self.emitTrivial(inst.src, Inst.Return),
1444 .ret => blk: {
1445 const old_inst = inst.cast(ir.Inst.Ret).?;
1446 const new_inst = try self.arena.allocator.create(Inst.Return);
1447 new_inst.* = .{
1448 .base = .{
1449 .name = try self.autoName(),
1450 .src = inst.src,
1451 .tag = Inst.Return.base_tag,
1452 },
1453 .positionals = .{
1454 .operand = try self.resolveInst(inst_table, old_inst.args.operand),
1455 },
1456 .kw_args = .{},
1457 };
1458 break :blk &new_inst.base;
1459 },
1460 .retvoid => try self.emitTrivial(inst.src, Inst.ReturnVoid),
14031461 .constant => unreachable, // excluded from function bodies
14041462 .assembly => blk: {
14051463 const old_inst = inst.cast(ir.Inst.Assembly).?;
src/codegen.cpp+6
......@@ -7473,6 +7473,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n
74737473 continue;
74747474 }
74757475 ZigValue *field_val = const_val->data.x_struct.fields[i];
7476 if (field_val == nullptr) {
7477 add_node_error(g, type_struct_field->decl_node,
7478 buf_sprintf("compiler bug: generating const value for struct field '%s'",
7479 buf_ptr(type_struct_field->name)));
7480 codegen_report_errors_and_exit(g);
7481 }
74767482 ZigType *field_type = field_val->type;
74777483 assert(field_type != nullptr);
74787484 if ((err = ensure_const_val_repr(nullptr, g, nullptr, field_val, field_type))) {