authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-11 01:22:07-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-18 17:12:56-04:00
logb4eac0414a01b1096e8dd7e89455db88f19789cf
tree288fe00b15970f15ca7ff7a0860c13646b582d15
parent4a387996311a025a021409f08a61bab9e9885987

stage2: hook up Zig AST to ZIR

* Introduce the concept of anonymous Decls * Primitive Hello, World with inline asm works * There is still an unsolved problem of how to manage ZIR instructions memory when generating from AST. Currently it leaks.

5 files changed, 981 insertions(+), 192 deletions(-)

lib/std/zig.zig+17
......@@ -1,4 +1,6 @@
1const std = @import("std.zig");
12const tokenizer = @import("zig/tokenizer.zig");
3
24pub const Token = tokenizer.Token;
35pub const Tokenizer = tokenizer.Tokenizer;
46pub const parse = @import("zig/parse.zig").parse;
......@@ -9,6 +11,21 @@ pub const ast = @import("zig/ast.zig");
911pub const system = @import("zig/system.zig");
1012pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
1113
14pub const SrcHash = [16]u8;
15
16/// If the source is small enough, it is used directly as the hash.
17/// If it is long, blake3 hash is computed.
18pub fn hashSrc(src: []const u8) SrcHash {
19 var out: SrcHash = undefined;
20 if (src.len <= SrcHash.len) {
21 std.mem.copy(u8, &out, src);
22 std.mem.set(u8, out[src.len..], 0);
23 } else {
24 std.crypto.Blake3.hash(src, &out);
25 }
26 return out;
27}
28
1229pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {
1330 var line: usize = 0;
1431 var column: usize = 0;
src-self-hosted/Module.zig+926-172
......@@ -15,13 +15,15 @@ const ir = @import("ir.zig");
1515const zir = @import("zir.zig");
1616const Module = @This();
1717const Inst = ir.Inst;
18const ast = std.zig.ast;
1819
1920/// General-purpose allocator.
2021allocator: *Allocator,
2122/// Pointer to externally managed resource.
2223root_pkg: *Package,
2324/// Module owns this resource.
24root_scope: *Scope.ZIRModule,
25/// The `Scope` is either a `Scope.ZIRModule` or `Scope.File`.
26root_scope: *Scope,
2527bin_file: link.ElfFile,
2628bin_file_dir: std.fs.Dir,
2729bin_file_path: []const u8,
......@@ -49,8 +51,8 @@ work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic),
4951/// a Decl can have a failed_decls entry but have analysis status of success.
5052failed_decls: std.AutoHashMap(*Decl, *ErrorMsg),
5153/// Using a map here for consistency with the other fields here.
52/// The ErrorMsg memory is owned by the `Scope.ZIRModule`, using Module's allocator.
53failed_files: std.AutoHashMap(*Scope.ZIRModule, *ErrorMsg),
54/// The ErrorMsg memory is owned by the `Scope`, using Module's allocator.
55failed_files: std.AutoHashMap(*Scope, *ErrorMsg),
5456/// Using a map here for consistency with the other fields here.
5557/// The ErrorMsg memory is owned by the `Export`, using Module's allocator.
5658failed_exports: std.AutoHashMap(*Export, *ErrorMsg),
......@@ -64,11 +66,18 @@ generation: u32 = 0,
6466/// contains Decls that need to be deleted if they end up having no references to them.
6567deletion_set: std.ArrayListUnmanaged(*Decl) = std.ArrayListUnmanaged(*Decl){},
6668
67pub const WorkItem = union(enum) {
69const WorkItem = union(enum) {
6870 /// Write the machine code for a Decl to the output file.
6971 codegen_decl: *Decl,
7072 /// Decl has been determined to be outdated; perform semantic analysis again.
7173 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 };
7281};
7382
7483pub const Export = struct {
......@@ -99,10 +108,9 @@ pub const Decl = struct {
99108 /// mapping them to an address in the output file.
100109 /// Memory owned by this decl, using Module's allocator.
101110 name: [*:0]const u8,
102 /// The direct parent container of the Decl. This field will need to get more fleshed out when
103 /// self-hosted supports proper struct types and Zig AST => ZIR.
111 /// The direct parent container of the Decl. This is either a `Scope.File` or `Scope.ZIRModule`.
104112 /// Reference to externally owned memory.
105 scope: *Scope.ZIRModule,
113 scope: *Scope,
106114 /// Byte offset into the source file that contains this declaration.
107115 /// This is the base offset that src offsets within this Decl are relative to.
108116 src: usize,
......@@ -171,17 +179,8 @@ pub const Decl = struct {
171179
172180 pub const Hash = [16]u8;
173181
174 /// If the name is small enough, it is used directly as the hash.
175 /// If it is long, blake3 hash is computed.
176182 pub fn hashSimpleName(name: []const u8) Hash {
177 var out: Hash = undefined;
178 if (name.len <= Hash.len) {
179 mem.copy(u8, &out, name);
180 mem.set(u8, out[name.len..], 0);
181 } else {
182 std.crypto.Blake3.hash(name, &out);
183 }
184 return out;
183 return std.zig.hashSrc(name);
185184 }
186185
187186 /// Must generate unique bytes with no collisions with other decls.
......@@ -290,6 +289,7 @@ pub const Scope = struct {
290289 .block => return self.cast(Block).?.arena,
291290 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
292291 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
292 .file => unreachable,
293293 }
294294 }
295295
......@@ -300,16 +300,27 @@ pub const Scope = struct {
300300 .block => self.cast(Block).?.decl,
301301 .decl => self.cast(DeclAnalysis).?.decl,
302302 .zir_module => null,
303 .file => null,
303304 };
304305 }
305306
306 /// Asserts the scope has a parent which is a ZIRModule and
307 /// Asserts the scope has a parent which is a ZIRModule or File and
307308 /// returns it.
308 pub fn namespace(self: *Scope) *ZIRModule {
309 pub fn namespace(self: *Scope) *Scope {
309310 switch (self.tag) {
310311 .block => return self.cast(Block).?.decl.scope,
311312 .decl => return self.cast(DeclAnalysis).?.decl.scope,
312 .zir_module => return self.cast(ZIRModule).?,
313 .zir_module, .file => return self,
314 }
315 }
316
317 /// Asserts the scope is a child of a File and has an AST tree and returns the tree.
318 pub fn tree(self: *Scope) *ast.Tree {
319 switch (self.tag) {
320 .file => return self.cast(File).?.contents.tree,
321 .zir_module => unreachable,
322 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(File).?.contents.tree,
323 .block => return self.cast(Block).?.decl.scope.cast(File).?.contents.tree,
313324 }
314325 }
315326
......@@ -325,12 +336,133 @@ pub const Scope = struct {
325336 });
326337 }
327338
339 /// Asserts the scope has a parent which is a ZIRModule or File and
340 /// returns the sub_file_path field.
341 pub fn subFilePath(base: *Scope) []const u8 {
342 switch (base.tag) {
343 .file => return @fieldParentPtr(File, "base", base).sub_file_path,
344 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,
345 .block => unreachable,
346 .decl => unreachable,
347 }
348 }
349
350 pub fn unload(base: *Scope, allocator: *Allocator) void {
351 switch (base.tag) {
352 .file => return @fieldParentPtr(File, "base", base).unload(allocator),
353 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).unload(allocator),
354 .block => unreachable,
355 .decl => unreachable,
356 }
357 }
358
359 pub fn getSource(base: *Scope, module: *Module) ![:0]const u8 {
360 switch (base.tag) {
361 .file => return @fieldParentPtr(File, "base", base).getSource(module),
362 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),
363 .block => unreachable,
364 .decl => unreachable,
365 }
366 }
367
368 /// Asserts the scope is a File or ZIRModule and deinitializes it, then deallocates it.
369 pub fn destroy(base: *Scope, allocator: *Allocator) void {
370 switch (base.tag) {
371 .file => {
372 const scope_file = @fieldParentPtr(File, "base", base);
373 scope_file.deinit(allocator);
374 allocator.destroy(scope_file);
375 },
376 .zir_module => {
377 const scope_zir_module = @fieldParentPtr(ZIRModule, "base", base);
378 scope_zir_module.deinit(allocator);
379 allocator.destroy(scope_zir_module);
380 },
381 .block => unreachable,
382 .decl => unreachable,
383 }
384 }
385
328386 pub const Tag = enum {
387 /// .zir source code.
329388 zir_module,
389 /// .zig source code.
390 file,
330391 block,
331392 decl,
332393 };
333394
395 pub const File = struct {
396 pub const base_tag: Tag = .file;
397 base: Scope = Scope{ .tag = base_tag },
398
399 /// Relative to the owning package's root_src_dir.
400 /// Reference to external memory, not owned by File.
401 sub_file_path: []const u8,
402 source: union(enum) {
403 unloaded: void,
404 bytes: [:0]const u8,
405 },
406 contents: union {
407 not_available: void,
408 tree: *ast.Tree,
409 },
410 status: enum {
411 never_loaded,
412 unloaded_success,
413 unloaded_parse_failure,
414 loaded_success,
415 },
416
417 pub fn unload(self: *File, allocator: *Allocator) void {
418 switch (self.status) {
419 .never_loaded,
420 .unloaded_parse_failure,
421 .unloaded_success,
422 => {},
423
424 .loaded_success => {
425 self.contents.tree.deinit();
426 self.status = .unloaded_success;
427 },
428 }
429 switch (self.source) {
430 .bytes => |bytes| {
431 allocator.free(bytes);
432 self.source = .{ .unloaded = {} };
433 },
434 .unloaded => {},
435 }
436 }
437
438 pub fn deinit(self: *File, allocator: *Allocator) void {
439 self.unload(allocator);
440 self.* = undefined;
441 }
442
443 pub fn dumpSrc(self: *File, src: usize) void {
444 const loc = std.zig.findLineColumn(self.source.bytes, src);
445 std.debug.warn("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
446 }
447
448 pub fn getSource(self: *File, module: *Module) ![:0]const u8 {
449 switch (self.source) {
450 .unloaded => {
451 const source = try module.root_pkg.root_src_dir.readFileAllocOptions(
452 module.allocator,
453 self.sub_file_path,
454 std.math.maxInt(u32),
455 1,
456 0,
457 );
458 self.source = .{ .bytes = source };
459 return source;
460 },
461 .bytes => |bytes| return bytes,
462 }
463 }
464 };
465
334466 pub const ZIRModule = struct {
335467 pub const base_tag: Tag = .zir_module;
336468 base: Scope = Scope{ .tag = base_tag },
......@@ -392,6 +524,23 @@ pub const Scope = struct {
392524 const loc = std.zig.findLineColumn(self.source.bytes, src);
393525 std.debug.warn("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
394526 }
527
528 pub fn getSource(self: *ZIRModule, module: *Module) ![:0]const u8 {
529 switch (self.source) {
530 .unloaded => {
531 const source = try module.root_pkg.root_src_dir.readFileAllocOptions(
532 module.allocator,
533 self.sub_file_path,
534 std.math.maxInt(u32),
535 1,
536 0,
537 );
538 self.source = .{ .bytes = source };
539 return source;
540 },
541 .bytes => |bytes| return bytes,
542 }
543 }
395544 };
396545
397546 /// This is a temporary structure, references to it are valid only
......@@ -466,16 +615,6 @@ pub const InitOptions = struct {
466615};
467616
468617pub fn init(gpa: *Allocator, options: InitOptions) !Module {
469 const root_scope = try gpa.create(Scope.ZIRModule);
470 errdefer gpa.destroy(root_scope);
471
472 root_scope.* = .{
473 .sub_file_path = options.root_pkg.root_src_path,
474 .source = .{ .unloaded = {} },
475 .contents = .{ .not_available = {} },
476 .status = .never_loaded,
477 };
478
479618 const bin_file_dir = options.bin_file_dir orelse std.fs.cwd();
480619 var bin_file = try link.openBinFilePath(gpa, bin_file_dir, options.bin_file_path, .{
481620 .target = options.target,
......@@ -485,6 +624,30 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
485624 });
486625 errdefer bin_file.deinit();
487626
627 const root_scope = blk: {
628 if (mem.endsWith(u8, options.root_pkg.root_src_path, ".zig")) {
629 const root_scope = try gpa.create(Scope.File);
630 root_scope.* = .{
631 .sub_file_path = options.root_pkg.root_src_path,
632 .source = .{ .unloaded = {} },
633 .contents = .{ .not_available = {} },
634 .status = .never_loaded,
635 };
636 break :blk &root_scope.base;
637 } else if (mem.endsWith(u8, options.root_pkg.root_src_path, ".zir")) {
638 const root_scope = try gpa.create(Scope.ZIRModule);
639 root_scope.* = .{
640 .sub_file_path = options.root_pkg.root_src_path,
641 .source = .{ .unloaded = {} },
642 .contents = .{ .not_available = {} },
643 .status = .never_loaded,
644 };
645 break :blk &root_scope.base;
646 } else {
647 unreachable;
648 }
649 };
650
488651 return Module{
489652 .allocator = gpa,
490653 .root_pkg = options.root_pkg,
......@@ -497,7 +660,7 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
497660 .decl_exports = std.AutoHashMap(*Decl, []*Export).init(gpa),
498661 .export_owners = std.AutoHashMap(*Decl, []*Export).init(gpa),
499662 .failed_decls = std.AutoHashMap(*Decl, *ErrorMsg).init(gpa),
500 .failed_files = std.AutoHashMap(*Scope.ZIRModule, *ErrorMsg).init(gpa),
663 .failed_files = std.AutoHashMap(*Scope, *ErrorMsg).init(gpa),
501664 .failed_exports = std.AutoHashMap(*Export, *ErrorMsg).init(gpa),
502665 .work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa),
503666 };
......@@ -551,10 +714,7 @@ pub fn deinit(self: *Module) void {
551714 }
552715 self.export_owners.deinit();
553716 }
554 {
555 self.root_scope.deinit(allocator);
556 allocator.destroy(self.root_scope);
557 }
717 self.root_scope.destroy(allocator);
558718 self.* = undefined;
559719}
560720
......@@ -574,16 +734,25 @@ pub fn update(self: *Module) !void {
574734 self.generation += 1;
575735
576736 // TODO Use the cache hash file system to detect which source files changed.
577 // Here we simulate a full cache miss.
578 // Analyze the root source file now.
579 // Source files could have been loaded for any reason; to force a refresh we unload now.
580 self.root_scope.unload(self.allocator);
581 self.analyzeRoot(self.root_scope) catch |err| switch (err) {
582 error.AnalysisFail => {
583 assert(self.totalErrorCount() != 0);
584 },
585 else => |e| return e,
586 };
737 // Until then we simulate a full cache miss. Source files could have been loaded for any reason;
738 // to force a refresh we unload now.
739 if (self.root_scope.cast(Scope.File)) |zig_file| {
740 zig_file.unload(self.allocator);
741 self.analyzeRootSrcFile(zig_file) catch |err| switch (err) {
742 error.AnalysisFail => {
743 assert(self.totalErrorCount() != 0);
744 },
745 else => |e| return e,
746 };
747 } else if (self.root_scope.cast(Scope.ZIRModule)) |zir_module| {
748 zir_module.unload(self.allocator);
749 self.analyzeRootZIRModule(zir_module) catch |err| switch (err) {
750 error.AnalysisFail => {
751 assert(self.totalErrorCount() != 0);
752 },
753 else => |e| return e,
754 };
755 }
587756
588757 try self.performAllTheWork();
589758
......@@ -619,10 +788,10 @@ pub fn makeBinFileWritable(self: *Module) !void {
619788}
620789
621790pub fn totalErrorCount(self: *Module) usize {
622 return self.failed_decls.size +
791 const total = self.failed_decls.size +
623792 self.failed_files.size +
624 self.failed_exports.size +
625 @boolToInt(self.link_error_flags.no_entry_point_found);
793 self.failed_exports.size;
794 return if (total == 0) @boolToInt(self.link_error_flags.no_entry_point_found) else total;
626795}
627796
628797pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
......@@ -637,8 +806,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
637806 while (it.next()) |kv| {
638807 const scope = kv.key;
639808 const err_msg = kv.value;
640 const source = try self.getSource(scope);
641 try AllErrors.add(&arena, &errors, scope.sub_file_path, source, err_msg.*);
809 const source = try scope.getSource(self);
810 try AllErrors.add(&arena, &errors, scope.subFilePath(), source, err_msg.*);
642811 }
643812 }
644813 {
......@@ -646,8 +815,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
646815 while (it.next()) |kv| {
647816 const decl = kv.key;
648817 const err_msg = kv.value;
649 const source = try self.getSource(decl.scope);
650 try AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg.*);
818 const source = try decl.scope.getSource(self);
819 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
651820 }
652821 }
653822 {
......@@ -655,12 +824,12 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
655824 while (it.next()) |kv| {
656825 const decl = kv.key.owner_decl;
657826 const err_msg = kv.value;
658 const source = try self.getSource(decl.scope);
659 try AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg.*);
827 const source = try decl.scope.getSource(self);
828 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
660829 }
661830 }
662831
663 if (self.link_error_flags.no_entry_point_found) {
832 if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) {
664833 try errors.append(.{
665834 .src_path = self.root_pkg.root_src_path,
666835 .line = 0,
......@@ -740,30 +909,491 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
740909 => continue,
741910
742911 .outdated => {
743 const zir_module = self.getSrcModule(decl.scope) catch |err| switch (err) {
744 error.OutOfMemory => return error.OutOfMemory,
745 else => {
746 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
747 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
748 self.allocator,
749 decl.src,
750 "unable to load source file '{}': {}",
751 .{ decl.scope.sub_file_path, @errorName(err) },
752 ));
753 decl.analysis = .codegen_failure_retryable;
754 continue;
755 },
756 };
757 const decl_name = mem.spanZ(decl.name);
758 // We already detected deletions, so we know this will be found.
759 const src_decl = zir_module.findDecl(decl_name).?;
760 self.reAnalyzeDecl(decl, src_decl) catch |err| switch (err) {
761 error.OutOfMemory => return error.OutOfMemory,
762 error.AnalysisFail => continue,
763 };
912 if (decl.scope.cast(Scope.File)) |file_scope| {
913 @panic("TODO re_analyze_decl for .zig files");
914 } else if (decl.scope.cast(Scope.ZIRModule)) |zir_scope| {
915 const zir_module = self.getSrcModule(zir_scope) catch |err| switch (err) {
916 error.OutOfMemory => return error.OutOfMemory,
917 else => {
918 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
919 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
920 self.allocator,
921 decl.src,
922 "unable to load source file '{}': {}",
923 .{ zir_scope.sub_file_path, @errorName(err) },
924 ));
925 decl.analysis = .codegen_failure_retryable;
926 continue;
927 },
928 };
929 const decl_name = mem.spanZ(decl.name);
930 // We already detected deletions, so we know this will be found.
931 const src_decl = zir_module.findDecl(decl_name).?;
932 self.reAnalyzeDecl(decl, src_decl) catch |err| switch (err) {
933 error.OutOfMemory => return error.OutOfMemory,
934 error.AnalysisFail => continue,
935 };
936 } else {
937 unreachable;
938 }
939 },
940 },
941 .ast_gen_decl => |item| {
942 self.astGenDecl(item.scope, item.ast_node) catch |err| switch (err) {
943 error.OutOfMemory => return error.OutOfMemory,
944 error.AnalysisFail => continue,
945 };
946 },
947 };
948}
949
950fn astGenDecl(self: *Module, parent_scope: *Scope, ast_node: *ast.Node) !void {
951 switch (ast_node.id) {
952 .FnProto => {
953 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", ast_node);
954
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,
968 .arena = std.heap.ArenaAllocator.init(self.allocator),
969 };
970 // TODO free this memory
971 //defer gen_scope.arena.deinit();
972
973 const body_node = fn_proto.body_node orelse
974 return self.failTok(&gen_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
975 if (fn_proto.params_len != 0) {
976 return self.failTok(
977 &gen_scope.base,
978 fn_proto.params()[0].name_token.?,
979 "TODO implement function parameters",
980 .{},
981 );
982 }
983 if (fn_proto.lib_name) |lib_name| {
984 return self.failNode(&gen_scope.base, lib_name, "TODO implement function library name", .{});
985 }
986 if (fn_proto.align_expr) |align_expr| {
987 return self.failNode(&gen_scope.base, align_expr, "TODO implement function align expression", .{});
988 }
989 if (fn_proto.section_expr) |sect_expr| {
990 return self.failNode(&gen_scope.base, sect_expr, "TODO implement function section expression", .{});
991 }
992 if (fn_proto.callconv_expr) |callconv_expr| {
993 return self.failNode(
994 &gen_scope.base,
995 callconv_expr,
996 "TODO implement function calling convention expression",
997 .{},
998 );
999 }
1000 const return_type_expr = switch (fn_proto.return_type) {
1001 .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", .{}),
1004 };
1005
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 = .{},
1021 };
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,
1033 },
1034 .kw_args = .{},
1035 };
1036 try self.analyzeNewDecl(new_decl, &fn_inst.base);
1037
1038 if (fn_proto.extern_export_inline_token) |maybe_export_token| {
1039 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);
1078 }
1079 }
1080 },
1081 .VarDecl => @panic("TODO var decl"),
1082 .Comptime => @panic("TODO comptime decl"),
1083 .Use => @panic("TODO usingnamespace decl"),
1084 else => unreachable,
1085 }
1086}
1087
1088fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir.Inst {
1089 switch (ast_node.id) {
1090 .Identifier => return self.astGenIdent(scope, @fieldParentPtr(ast.Node.Identifier, "base", ast_node)),
1091 .Asm => return self.astGenAsm(scope, @fieldParentPtr(ast.Node.Asm, "base", ast_node)),
1092 .StringLiteral => return self.astGenStringLiteral(scope, @fieldParentPtr(ast.Node.StringLiteral, "base", ast_node)),
1093 .IntegerLiteral => return self.astGenIntegerLiteral(scope, @fieldParentPtr(ast.Node.IntegerLiteral, "base", ast_node)),
1094 .BuiltinCall => return self.astGenBuiltinCall(scope, @fieldParentPtr(ast.Node.BuiltinCall, "base", ast_node)),
1095 .Unreachable => return self.astGenUnreachable(scope, @fieldParentPtr(ast.Node.Unreachable, "base", ast_node)),
1096 else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}),
1097 }
1098}
1099
1100fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst {
1101 const tree = scope.tree();
1102 const ident_name = tree.tokenSlice(ident.token);
1103 if (mem.eql(u8, ident_name, "_")) {
1104 return self.failNode(scope, &ident.base, "TODO implement '_' identifier", .{});
1105 }
1106
1107 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;
1121 }
1122
1123 if (ident_name.len >= 2) integer: {
1124 const first_c = ident_name[0];
1125 if (first_c == 'i' or first_c == 'u') {
1126 const is_signed = first_c == 'i';
1127 const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) {
1128 error.Overflow => return self.failNode(
1129 scope,
1130 &ident.base,
1131 "primitive integer type '{}' exceeds maximum bit width of 65535",
1132 .{ident_name},
1133 ),
1134 error.InvalidCharacter => break :integer,
1135 };
1136 return self.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{});
1137 }
1138 }
1139
1140 return self.failNode(scope, &ident.base, "TODO implement identifier lookup", .{});
1141}
1142
1143fn astGenStringLiteral(self: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral) InnerError!*zir.Inst {
1144 const tree = scope.tree();
1145 const unparsed_bytes = tree.tokenSlice(str_lit.token);
1146 const arena = scope.arena();
1147
1148 var bad_index: usize = undefined;
1149 const bytes = std.zig.parseStringLiteral(arena, unparsed_bytes, &bad_index) catch |err| switch (err) {
1150 error.InvalidCharacter => {
1151 const bad_byte = unparsed_bytes[bad_index];
1152 const src = tree.token_locs[str_lit.token].start;
1153 return self.fail(scope, src + bad_index, "invalid string literal character: '{c}'\n", .{bad_byte});
1154 },
1155 else => |e| return e,
1156 };
1157
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;
1183}
1184
1185fn astGenIntegerLiteral(self: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral) InnerError!*zir.Inst {
1186 const arena = scope.arena();
1187 const tree = scope.tree();
1188 const bytes = tree.tokenSlice(int_lit.token);
1189
1190 if (mem.startsWith(u8, bytes, "0x")) {
1191 return self.failTok(scope, int_lit.token, "TODO implement 0x int prefix", .{});
1192 } else if (mem.startsWith(u8, bytes, "0o")) {
1193 return self.failTok(scope, int_lit.token, "TODO implement 0o int prefix", .{});
1194 } else if (mem.startsWith(u8, bytes, "0b")) {
1195 return self.failTok(scope, int_lit.token, "TODO implement 0b int prefix", .{});
1196 }
1197 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,
7641208 },
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;
1218 } else |err| {
1219 return self.failTok(scope, int_lit.token, "TODO implement int literals that don't fit in a u64", .{});
1220 }
1221}
1222
1223fn astGenBlock(self: *Module, scope: *Scope, block_node: *ast.Node.Block) !zir.Module.Body {
1224 if (block_node.label) |label| {
1225 return self.failTok(scope, label, "TODO implement labeled blocks", .{});
1226 }
1227 const arena = scope.arena();
1228 var instructions = std.ArrayList(*zir.Inst).init(arena);
1229
1230 try instructions.ensureCapacity(block_node.statements_len);
1231
1232 for (block_node.statements()) |statement| {
1233 const inst = try self.astGenExpr(scope, statement);
1234 instructions.appendAssumeCapacity(inst);
1235 }
1236
1237 return zir.Module.Body{
1238 .instructions = instructions.items,
1239 };
1240}
1241
1242fn astGenAsm(self: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst {
1243 if (asm_node.outputs.len != 0) {
1244 return self.failNode(scope, &asm_node.base, "TODO implement asm with an output", .{});
1245 }
1246 const arena = scope.arena();
1247 const tree = scope.tree();
1248
1249 const inputs = try arena.alloc(*zir.Inst, asm_node.inputs.len);
1250 const args = try arena.alloc(*zir.Inst, asm_node.inputs.len);
1251
1252 for (asm_node.inputs) |input, i| {
1253 // TODO semantically analyze constraints
1254 inputs[i] = try self.astGenExpr(scope, input.constraint);
1255 args[i] = try self.astGenExpr(scope, input.expr);
1256 }
1257
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;
1293}
1294
1295fn astGenBuiltinCall(self: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
1296 const tree = scope.tree();
1297 const builtin_name = tree.tokenSlice(call.builtin_token);
1298 const arena = scope.arena();
1299
1300 if (mem.eql(u8, builtin_name, "@ptrToInt")) {
1301 if (call.params_len != 1) {
1302 return self.failTok(scope, call.builtin_token, "expected 1 parameter, found {}", .{call.params_len});
1303 }
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;
1317 } else {
1318 return self.failTok(scope, call.builtin_token, "TODO implement builtin call for '{}'", .{builtin_name});
1319 }
1320}
1321
1322fn astGenUnreachable(self: *Module, scope: *Scope, unreach_node: *ast.Node.Unreachable) InnerError!*zir.Inst {
1323 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,
7651331 },
1332 .positionals = .{},
1333 .kw_args = .{},
7661334 };
1335 return &unreach.base;
1336}
1337
1338fn getSimplePrimitiveValue(name: []const u8) ?TypedValue {
1339 const simple_types = std.ComptimeStringMap(Value.Tag, .{
1340 .{ "u8", .u8_type },
1341 .{ "i8", .i8_type },
1342 .{ "isize", .isize_type },
1343 .{ "usize", .usize_type },
1344 .{ "c_short", .c_short_type },
1345 .{ "c_ushort", .c_ushort_type },
1346 .{ "c_int", .c_int_type },
1347 .{ "c_uint", .c_uint_type },
1348 .{ "c_long", .c_long_type },
1349 .{ "c_ulong", .c_ulong_type },
1350 .{ "c_longlong", .c_longlong_type },
1351 .{ "c_ulonglong", .c_ulonglong_type },
1352 .{ "c_longdouble", .c_longdouble_type },
1353 .{ "f16", .f16_type },
1354 .{ "f32", .f32_type },
1355 .{ "f64", .f64_type },
1356 .{ "f128", .f128_type },
1357 .{ "c_void", .c_void_type },
1358 .{ "bool", .bool_type },
1359 .{ "void", .void_type },
1360 .{ "type", .type_type },
1361 .{ "anyerror", .anyerror_type },
1362 .{ "comptime_int", .comptime_int_type },
1363 .{ "comptime_float", .comptime_float_type },
1364 .{ "noreturn", .noreturn_type },
1365 });
1366 if (simple_types.get(name)) |tag| {
1367 return TypedValue{
1368 .ty = Type.initTag(.type),
1369 .val = Value.initTag(tag),
1370 };
1371 }
1372 if (mem.eql(u8, name, "null")) {
1373 return TypedValue{
1374 .ty = Type.initTag(.@"null"),
1375 .val = Value.initTag(.null_value),
1376 };
1377 }
1378 if (mem.eql(u8, name, "undefined")) {
1379 return TypedValue{
1380 .ty = Type.initTag(.@"undefined"),
1381 .val = Value.initTag(.undef),
1382 };
1383 }
1384 if (mem.eql(u8, name, "true")) {
1385 return TypedValue{
1386 .ty = Type.initTag(.bool),
1387 .val = Value.initTag(.bool_true),
1388 };
1389 }
1390 if (mem.eql(u8, name, "false")) {
1391 return TypedValue{
1392 .ty = Type.initTag(.bool),
1393 .val = Value.initTag(.bool_false),
1394 };
1395 }
1396 return null;
7671397}
7681398
7691399fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {
......@@ -783,29 +1413,12 @@ fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void
7831413 }
7841414}
7851415
786fn getSource(self: *Module, root_scope: *Scope.ZIRModule) ![:0]const u8 {
787 switch (root_scope.source) {
788 .unloaded => {
789 const source = try self.root_pkg.root_src_dir.readFileAllocOptions(
790 self.allocator,
791 root_scope.sub_file_path,
792 std.math.maxInt(u32),
793 1,
794 0,
795 );
796 root_scope.source = .{ .bytes = source };
797 return source;
798 },
799 .bytes => |bytes| return bytes,
800 }
801}
802
8031416fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
8041417 switch (root_scope.status) {
8051418 .never_loaded, .unloaded_success => {
8061419 try self.failed_files.ensureCapacity(self.failed_files.size + 1);
8071420
808 const source = try self.getSource(root_scope);
1421 const source = try root_scope.getSource(self);
8091422
8101423 var keep_zir_module = false;
8111424 const zir_module = try self.allocator.create(zir.Module);
......@@ -816,7 +1429,7 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
8161429
8171430 if (zir_module.error_msg) |src_err_msg| {
8181431 self.failed_files.putAssumeCapacityNoClobber(
819 root_scope,
1432 &root_scope.base,
8201433 try ErrorMsg.create(self.allocator, src_err_msg.byte_offset, "{}", .{src_err_msg.msg}),
8211434 );
8221435 root_scope.status = .unloaded_parse_failure;
......@@ -838,7 +1451,83 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
8381451 }
8391452}
8401453
841fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void {
1454fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {
1455 switch (root_scope.status) {
1456 .never_loaded, .unloaded_success => {
1457 try self.failed_files.ensureCapacity(self.failed_files.size + 1);
1458
1459 const source = try root_scope.getSource(self);
1460
1461 var keep_tree = false;
1462 const tree = try std.zig.parse(self.allocator, source);
1463 defer if (!keep_tree) tree.deinit();
1464
1465 if (tree.errors.len != 0) {
1466 const parse_err = tree.errors[0];
1467
1468 var msg = std.ArrayList(u8).init(self.allocator);
1469 defer msg.deinit();
1470
1471 try parse_err.render(tree.token_ids, msg.outStream());
1472 const err_msg = try self.allocator.create(ErrorMsg);
1473 err_msg.* = .{
1474 .msg = msg.toOwnedSlice(),
1475 .byte_offset = tree.token_locs[parse_err.loc()].start,
1476 };
1477
1478 self.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);
1479 root_scope.status = .unloaded_parse_failure;
1480 return error.AnalysisFail;
1481 }
1482
1483 root_scope.status = .loaded_success;
1484 root_scope.contents = .{ .tree = tree };
1485 keep_tree = true;
1486
1487 return tree;
1488 },
1489
1490 .unloaded_parse_failure => return error.AnalysisFail,
1491
1492 .loaded_success => return root_scope.contents.tree,
1493 }
1494}
1495
1496fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1497 switch (root_scope.status) {
1498 .never_loaded => {
1499 const tree = try self.getAstTree(root_scope);
1500 const decls = tree.root_node.decls();
1501
1502 try self.work_queue.ensureUnusedCapacity(decls.len);
1503
1504 for (decls) |decl| {
1505 if (decl.cast(ast.Node.FnProto)) |proto_decl| {
1506 if (proto_decl.extern_export_inline_token) |maybe_export_token| {
1507 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 });
1514 }
1515 }
1516 }
1517 // TODO also look for comptime blocks and exported globals
1518 }
1519 },
1520
1521 .unloaded_parse_failure,
1522 .unloaded_success,
1523 .loaded_success,
1524 => {
1525 @panic("TODO process update");
1526 },
1527 }
1528}
1529
1530fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
8421531 switch (root_scope.status) {
8431532 .never_loaded => {
8441533 const src_module = try self.getSrcModule(root_scope);
......@@ -882,12 +1571,10 @@ fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void {
8821571 if (self.decl_table.get(name_hash)) |kv| {
8831572 const decl = kv.value;
8841573 deleted_decls.removeAssertDiscard(decl);
885 const new_contents_hash = Decl.hashSimpleName(src_decl.contents);
8861574 //std.debug.warn("'{}' contents: '{}'\n", .{ src_decl.name, src_decl.contents });
887 if (!mem.eql(u8, &new_contents_hash, &decl.contents_hash)) {
888 //std.debug.warn("'{}' {x} => {x}\n", .{ src_decl.name, decl.contents_hash, new_contents_hash });
1575 if (!mem.eql(u8, &src_decl.contents_hash, &decl.contents_hash)) {
8891576 try self.markOutdatedDecl(decl);
890 decl.contents_hash = new_contents_hash;
1577 decl.contents_hash = src_decl.contents_hash;
8911578 }
8921579 } else if (src_decl.cast(zir.Inst.Export)) |export_inst| {
8931580 try exports_to_resolve.append(&export_inst.base);
......@@ -1038,7 +1725,7 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi
10381725 };
10391726 errdefer decl_scope.arena.deinit();
10401727
1041 const typed_value = self.analyzeInstConst(&decl_scope.base, old_inst) catch |err| switch (err) {
1728 const typed_value = self.analyzeConstInst(&decl_scope.base, old_inst) catch |err| switch (err) {
10421729 error.OutOfMemory => return error.OutOfMemory,
10431730 error.AnalysisFail => {
10441731 switch (decl.analysis) {
......@@ -1109,9 +1796,91 @@ fn markOutdatedDecl(self: *Module, decl: *Decl) !void {
11091796 decl.analysis = .outdated;
11101797}
11111798
1799fn allocateNewDecl(
1800 self: *Module,
1801 scope: *Scope,
1802 src: usize,
1803 contents_hash: std.zig.SrcHash,
1804) !*Decl {
1805 const new_decl = try self.allocator.create(Decl);
1806 new_decl.* = .{
1807 .name = "",
1808 .scope = scope.namespace(),
1809 .src = src,
1810 .typed_value = .{ .never_succeeded = {} },
1811 .analysis = .in_progress,
1812 .deletion_flag = false,
1813 .contents_hash = contents_hash,
1814 .link = link.ElfFile.TextBlock.empty,
1815 .generation = 0,
1816 };
1817 return new_decl;
1818}
1819
1820fn createNewDecl(
1821 self: *Module,
1822 scope: *Scope,
1823 decl_name: []const u8,
1824 src: usize,
1825 name_hash: Decl.Hash,
1826 contents_hash: std.zig.SrcHash,
1827) !*Decl {
1828 try self.decl_table.ensureCapacity(self.decl_table.size + 1);
1829 const new_decl = try self.allocateNewDecl(scope, src, contents_hash);
1830 errdefer self.allocator.destroy(new_decl);
1831 new_decl.name = try mem.dupeZ(self.allocator, u8, decl_name);
1832 self.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
1833 return new_decl;
1834}
1835
1836fn analyzeNewDecl(self: *Module, new_decl: *Decl, old_inst: *zir.Inst) InnerError!void {
1837 var decl_scope: Scope.DeclAnalysis = .{
1838 .decl = new_decl,
1839 .arena = std.heap.ArenaAllocator.init(self.allocator),
1840 };
1841 errdefer decl_scope.arena.deinit();
1842
1843 const typed_value = self.analyzeConstInst(&decl_scope.base, old_inst) catch |err| switch (err) {
1844 error.OutOfMemory => return error.OutOfMemory,
1845 error.AnalysisFail => {
1846 switch (new_decl.analysis) {
1847 .in_progress => new_decl.analysis = .dependency_failure,
1848 else => {},
1849 }
1850 new_decl.generation = self.generation;
1851 return error.AnalysisFail;
1852 },
1853 };
1854 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);
1855
1856 arena_state.* = decl_scope.arena.state;
1857
1858 new_decl.typed_value = .{
1859 .most_recent = .{
1860 .typed_value = typed_value,
1861 .arena = arena_state,
1862 },
1863 };
1864 new_decl.analysis = .complete;
1865 new_decl.generation = self.generation;
1866 if (typed_value.ty.hasCodeGenBits()) {
1867 // We don't fully codegen the decl until later, but we do need to reserve a global
1868 // offset table index for it. This allows us to codegen decls out of dependency order,
1869 // increasing how many computations can be done in parallel.
1870 try self.bin_file.allocateDeclIndexes(new_decl);
1871 try self.work_queue.writeItem(.{ .codegen_decl = new_decl });
1872 }
1873}
1874
11121875fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl {
1113 const hash = Decl.hashSimpleName(old_inst.name);
1114 if (self.decl_table.get(hash)) |kv| {
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| {
11151884 const decl = kv.value;
11161885 try self.reAnalyzeDecl(decl, old_inst);
11171886 return decl;
......@@ -1119,63 +1888,9 @@ fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*De
11191888 // This is just a named reference to another decl.
11201889 return self.analyzeDeclVal(scope, decl_val);
11211890 } else {
1122 const new_decl = blk: {
1123 try self.decl_table.ensureCapacity(self.decl_table.size + 1);
1124 const new_decl = try self.allocator.create(Decl);
1125 errdefer self.allocator.destroy(new_decl);
1126 const name = try mem.dupeZ(self.allocator, u8, old_inst.name);
1127 errdefer self.allocator.free(name);
1128 new_decl.* = .{
1129 .name = name,
1130 .scope = scope.namespace(),
1131 .src = old_inst.src,
1132 .typed_value = .{ .never_succeeded = {} },
1133 .analysis = .in_progress,
1134 .deletion_flag = false,
1135 .contents_hash = Decl.hashSimpleName(old_inst.contents),
1136 .link = link.ElfFile.TextBlock.empty,
1137 .generation = 0,
1138 };
1139 self.decl_table.putAssumeCapacityNoClobber(hash, new_decl);
1140 break :blk new_decl;
1141 };
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);
11421893
1143 var decl_scope: Scope.DeclAnalysis = .{
1144 .decl = new_decl,
1145 .arena = std.heap.ArenaAllocator.init(self.allocator),
1146 };
1147 errdefer decl_scope.arena.deinit();
1148
1149 const typed_value = self.analyzeInstConst(&decl_scope.base, old_inst) catch |err| switch (err) {
1150 error.OutOfMemory => return error.OutOfMemory,
1151 error.AnalysisFail => {
1152 switch (new_decl.analysis) {
1153 .in_progress => new_decl.analysis = .dependency_failure,
1154 else => {},
1155 }
1156 new_decl.generation = self.generation;
1157 return error.AnalysisFail;
1158 },
1159 };
1160 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);
1161
1162 arena_state.* = decl_scope.arena.state;
1163
1164 new_decl.typed_value = .{
1165 .most_recent = .{
1166 .typed_value = typed_value,
1167 .arena = arena_state,
1168 },
1169 };
1170 new_decl.analysis = .complete;
1171 new_decl.generation = self.generation;
1172 if (typed_value.ty.hasCodeGenBits()) {
1173 // We don't fully codegen the decl until later, but we do need to reserve a global
1174 // offset table index for it. This allows us to codegen decls out of dependency order,
1175 // increasing how many computations can be done in parallel.
1176 try self.bin_file.allocateDeclIndexes(new_decl);
1177 try self.work_queue.writeItem(.{ .codegen_decl = new_decl });
1178 }
11791894 return new_decl;
11801895 }
11811896}
......@@ -1208,9 +1923,13 @@ fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
12081923 }
12091924 }
12101925
1211 const decl = try self.resolveCompleteDecl(scope, old_inst);
1212 const decl_ref = try self.analyzeDeclRef(scope, old_inst.src, decl);
1213 return self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src);
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);
12141933}
12151934
12161935fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
......@@ -1451,7 +2170,7 @@ fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigI
14512170 });
14522171}
14532172
1454fn analyzeInstConst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue {
2173fn analyzeConstInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue {
14552174 const new_inst = try self.analyzeInst(scope, old_inst);
14562175 return TypedValue{
14572176 .ty = new_inst.ty,
......@@ -1459,11 +2178,16 @@ fn analyzeInstConst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerErro
14592178 };
14602179}
14612180
2181fn 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);
2183}
2184
14622185fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
14632186 switch (old_inst.tag) {
14642187 .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?),
14652188 .call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?),
14662189 .compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?),
2190 .@"const" => return self.analyzeInstConst(scope, old_inst.cast(zir.Inst.Const).?),
14672191 .declref => return self.analyzeInstDeclRef(scope, old_inst.cast(zir.Inst.DeclRef).?),
14682192 .declval => return self.analyzeInstDeclVal(scope, old_inst.cast(zir.Inst.DeclVal).?),
14692193 .str => {
......@@ -1520,18 +2244,23 @@ fn analyzeInstRef(self: *Module, scope: *Scope, inst: *zir.Inst.Ref) InnerError!
15202244fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst {
15212245 const decl_name = try self.resolveConstString(scope, inst.positionals.name);
15222246 // This will need to get more fleshed out when there are proper structs & namespaces.
1523 const zir_module = scope.namespace();
1524 const src_decl = zir_module.contents.module.findDecl(decl_name) orelse
1525 return self.fail(scope, inst.positionals.name.src, "use of undeclared identifier '{}'", .{decl_name});
1526
1527 const decl = try self.resolveCompleteDecl(scope, src_decl);
1528 return self.analyzeDeclRef(scope, inst.base.src, decl);
2247 const namespace = scope.namespace();
2248 if (namespace.cast(Scope.File)) |scope_file| {
2249 return self.fail(scope, inst.base.src, "TODO implement declref for zig source", .{});
2250 } else if (namespace.cast(Scope.ZIRModule)) |zir_module| {
2251 const src_decl = zir_module.contents.module.findDecl(decl_name) orelse
2252 return self.fail(scope, inst.positionals.name.src, "use of undeclared identifier '{}'", .{decl_name});
2253
2254 const decl = try self.resolveCompleteDecl(scope, src_decl);
2255 return self.analyzeDeclRef(scope, inst.base.src, decl);
2256 } else {
2257 unreachable;
2258 }
15292259}
15302260
15312261fn analyzeDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Decl {
15322262 const decl_name = inst.positionals.name;
1533 // This will need to get more fleshed out when there are proper structs & namespaces.
1534 const zir_module = scope.namespace();
2263 const zir_module = scope.namespace().cast(Scope.ZIRModule).?;
15352264 const src_decl = zir_module.contents.module.findDecl(decl_name) orelse
15362265 return self.fail(scope, inst.base.src, "use of undeclared identifier '{}'", .{decl_name});
15372266
......@@ -2316,6 +3045,30 @@ fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, a
23163045 return self.failWithOwnedErrorMsg(scope, src, err_msg);
23173046}
23183047
3048fn failTok(
3049 self: *Module,
3050 scope: *Scope,
3051 token_index: ast.TokenIndex,
3052 comptime format: []const u8,
3053 args: var,
3054) InnerError {
3055 @setCold(true);
3056 const src = scope.tree().token_locs[token_index].start;
3057 return self.fail(scope, src, format, args);
3058}
3059
3060fn failNode(
3061 self: *Module,
3062 scope: *Scope,
3063 ast_node: *ast.Node,
3064 comptime format: []const u8,
3065 args: var,
3066) InnerError {
3067 @setCold(true);
3068 const src = scope.tree().token_locs[ast_node.firstToken()].start;
3069 return self.fail(scope, src, format, args);
3070}
3071
23193072fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *ErrorMsg) InnerError {
23203073 {
23213074 errdefer err_msg.destroy(self.allocator);
......@@ -2336,8 +3089,9 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err
23363089 .zir_module => {
23373090 const zir_module = scope.cast(Scope.ZIRModule).?;
23383091 zir_module.status = .loaded_sema_failure;
2339 self.failed_files.putAssumeCapacityNoClobber(zir_module, err_msg);
3092 self.failed_files.putAssumeCapacityNoClobber(scope, err_msg);
23403093 },
3094 .file => unreachable,
23413095 }
23423096 return error.AnalysisFail;
23433097}
src-self-hosted/main.zig+1-1
......@@ -86,7 +86,7 @@ const usage_build_generic =
8686 \\ zig build-obj <options> [files]
8787 \\
8888 \\Supported file types:
89 \\ (planned) .zig Zig source code
89 \\ .zig Zig source code
9090 \\ .zir Zig Intermediate Representation code
9191 \\ (planned) .o ELF object file
9292 \\ (planned) .o MACH-O (macOS) object file
src-self-hosted/value.zig+2-2
......@@ -78,8 +78,8 @@ pub const Value = extern union {
7878 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
7979 };
8080
81 pub fn initTag(comptime small_tag: Tag) Value {
82 comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);
81 pub fn initTag(small_tag: Tag) Value {
82 assert(@enumToInt(small_tag) < Tag.no_payload_count);
8383 return .{ .tag_if_small_enough = @enumToInt(small_tag) };
8484 }
8585
src-self-hosted/zir.zig+35-17
......@@ -14,20 +14,24 @@ const IrModule = @import("Module.zig");
1414
1515/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for
1616/// in-memory, analyzed instructions with types and values.
17/// TODO Separate into Decl and Inst. Decl will have extra fields, and will make the
18/// undefined default field value of contents_hash no longer needed.
1719pub const Inst = struct {
1820 tag: Tag,
1921 /// Byte offset into the source.
2022 src: usize,
2123 name: []const u8,
2224
23 /// Slice into the source of the part after the = and before the next instruction.
24 contents: []const u8 = &[0]u8{},
25 /// Hash of slice into the source of the part after the = and before the next instruction.
26 contents_hash: std.zig.SrcHash = undefined,
2527
2628 /// These names are used directly as the instruction names in the text format.
2729 pub const Tag = enum {
2830 breakpoint,
2931 call,
3032 compileerror,
33 /// Special case, has no textual representation.
34 @"const",
3135 /// Represents a pointer to a global decl by name.
3236 declref,
3337 /// The syntax `@foo` is equivalent to `declval("foo")`.
......@@ -43,10 +47,10 @@ pub const Inst = struct {
4347 @"unreachable",
4448 @"return",
4549 @"fn",
50 fntype,
4651 @"export",
4752 primitive,
4853 ref,
49 fntype,
5054 intcast,
5155 bitcast,
5256 elemptr,
......@@ -64,6 +68,7 @@ pub const Inst = struct {
6468 .declref => DeclRef,
6569 .declval => DeclVal,
6670 .compileerror => CompileError,
71 .@"const" => Const,
6772 .str => Str,
6873 .int => Int,
6974 .ptrtoint => PtrToInt,
......@@ -147,6 +152,16 @@ pub const Inst = struct {
147152 kw_args: struct {},
148153 };
149154
155 pub const Const = struct {
156 pub const base_tag = Tag.@"const";
157 base: Inst,
158
159 positionals: struct {
160 typed_value: TypedValue,
161 },
162 kw_args: struct {},
163 };
164
150165 pub const Str = struct {
151166 pub const base_tag = Tag.str;
152167 base: Inst,
......@@ -253,6 +268,19 @@ pub const Inst = struct {
253268 kw_args: struct {},
254269 };
255270
271 pub const FnType = struct {
272 pub const base_tag = Tag.fntype;
273 base: Inst,
274
275 positionals: struct {
276 param_types: []*Inst,
277 return_type: *Inst,
278 },
279 kw_args: struct {
280 cc: std.builtin.CallingConvention = .Unspecified,
281 },
282 };
283
256284 pub const Export = struct {
257285 pub const base_tag = Tag.@"export";
258286 base: Inst,
......@@ -348,19 +376,6 @@ pub const Inst = struct {
348376 };
349377 };
350378
351 pub const FnType = struct {
352 pub const base_tag = Tag.fntype;
353 base: Inst,
354
355 positionals: struct {
356 param_types: []*Inst,
357 return_type: *Inst,
358 },
359 kw_args: struct {
360 cc: std.builtin.CallingConvention = .Unspecified,
361 },
362 };
363
364379 pub const IntCast = struct {
365380 pub const base_tag = Tag.intcast;
366381 base: Inst,
......@@ -526,6 +541,7 @@ pub const Module = struct {
526541 .declref => return self.writeInstToStreamGeneric(stream, .declref, decl, inst_table),
527542 .declval => return self.writeInstToStreamGeneric(stream, .declval, decl, inst_table),
528543 .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, decl, inst_table),
544 .@"const" => return self.writeInstToStreamGeneric(stream, .@"const", decl, inst_table),
529545 .str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table),
530546 .int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table),
531547 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table),
......@@ -619,6 +635,7 @@ pub const Module = struct {
619635 bool => return stream.writeByte("01"[@boolToInt(param)]),
620636 []u8, []const u8 => return std.zig.renderStringLiteral(param, stream),
621637 BigIntConst => return stream.print("{}", .{param}),
638 TypedValue => unreachable, // this is a special case
622639 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
623640 }
624641 }
......@@ -929,7 +946,7 @@ const Parser = struct {
929946 }
930947 try requireEatBytes(self, ")");
931948
932 inst_specific.base.contents = self.source[contents_start..self.i];
949 inst_specific.base.contents_hash = std.zig.hashSrc(self.source[contents_start..self.i]);
933950 //std.debug.warn("parsed {} = '{}'\n", .{ inst_specific.base.name, inst_specific.base.contents });
934951
935952 return &inst_specific.base;
......@@ -978,6 +995,7 @@ const Parser = struct {
978995 *Inst => return parseParameterInst(self, body_ctx),
979996 []u8, []const u8 => return self.parseStringLiteral(),
980997 BigIntConst => return self.parseIntegerLiteral(),
998 TypedValue => return self.fail("'const' is a special instruction; not legal in ZIR text", .{}),
981999 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
9821000 }
9831001 return self.fail("TODO parse parameter {}", .{@typeName(T)});