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 @@...@@ -1,4 +1,6 @@
1const std = @import("std.zig");
1const tokenizer = @import("zig/tokenizer.zig");2const tokenizer = @import("zig/tokenizer.zig");
3
2pub const Token = tokenizer.Token;4pub const Token = tokenizer.Token;
3pub const Tokenizer = tokenizer.Tokenizer;5pub const Tokenizer = tokenizer.Tokenizer;
4pub const parse = @import("zig/parse.zig").parse;6pub const parse = @import("zig/parse.zig").parse;
...@@ -9,6 +11,21 @@ pub const ast = @import("zig/ast.zig");...@@ -9,6 +11,21 @@ pub const ast = @import("zig/ast.zig");
9pub const system = @import("zig/system.zig");11pub const system = @import("zig/system.zig");
10pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;12pub 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
12pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {29pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {
13 var line: usize = 0;30 var line: usize = 0;
14 var column: usize = 0;31 var column: usize = 0;
src-self-hosted/Module.zig+926-172
...@@ -15,13 +15,15 @@ const ir = @import("ir.zig");...@@ -15,13 +15,15 @@ const ir = @import("ir.zig");
15const zir = @import("zir.zig");15const zir = @import("zir.zig");
16const Module = @This();16const Module = @This();
17const Inst = ir.Inst;17const Inst = ir.Inst;
18const ast = std.zig.ast;
1819
19/// General-purpose allocator.20/// General-purpose allocator.
20allocator: *Allocator,21allocator: *Allocator,
21/// Pointer to externally managed resource.22/// Pointer to externally managed resource.
22root_pkg: *Package,23root_pkg: *Package,
23/// Module owns this resource.24/// Module owns this resource.
24root_scope: *Scope.ZIRModule,25/// The `Scope` is either a `Scope.ZIRModule` or `Scope.File`.
26root_scope: *Scope,
25bin_file: link.ElfFile,27bin_file: link.ElfFile,
26bin_file_dir: std.fs.Dir,28bin_file_dir: std.fs.Dir,
27bin_file_path: []const u8,29bin_file_path: []const u8,
...@@ -49,8 +51,8 @@ work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic),...@@ -49,8 +51,8 @@ work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic),
49/// a Decl can have a failed_decls entry but have analysis status of success.51/// a Decl can have a failed_decls entry but have analysis status of success.
50failed_decls: std.AutoHashMap(*Decl, *ErrorMsg),52failed_decls: std.AutoHashMap(*Decl, *ErrorMsg),
51/// Using a map here for consistency with the other fields here.53/// 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.54/// The ErrorMsg memory is owned by the `Scope`, using Module's allocator.
53failed_files: std.AutoHashMap(*Scope.ZIRModule, *ErrorMsg),55failed_files: std.AutoHashMap(*Scope, *ErrorMsg),
54/// Using a map here for consistency with the other fields here.56/// Using a map here for consistency with the other fields here.
55/// The ErrorMsg memory is owned by the `Export`, using Module's allocator.57/// The ErrorMsg memory is owned by the `Export`, using Module's allocator.
56failed_exports: std.AutoHashMap(*Export, *ErrorMsg),58failed_exports: std.AutoHashMap(*Export, *ErrorMsg),
...@@ -64,11 +66,18 @@ generation: u32 = 0,...@@ -64,11 +66,18 @@ generation: u32 = 0,
64/// contains Decls that need to be deleted if they end up having no references to them.66/// contains Decls that need to be deleted if they end up having no references to them.
65deletion_set: std.ArrayListUnmanaged(*Decl) = std.ArrayListUnmanaged(*Decl){},67deletion_set: std.ArrayListUnmanaged(*Decl) = std.ArrayListUnmanaged(*Decl){},
6668
67pub const WorkItem = union(enum) {69const WorkItem = union(enum) {
68 /// Write the machine code for a Decl to the output file.70 /// Write the machine code for a Decl to the output file.
69 codegen_decl: *Decl,71 codegen_decl: *Decl,
70 /// Decl has been determined to be outdated; perform semantic analysis again.72 /// Decl has been determined to be outdated; perform semantic analysis again.
71 re_analyze_decl: *Decl,73 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 };
72};81};
7382
74pub const Export = struct {83pub const Export = struct {
...@@ -99,10 +108,9 @@ pub const Decl = struct {...@@ -99,10 +108,9 @@ pub const Decl = struct {
99 /// mapping them to an address in the output file.108 /// mapping them to an address in the output file.
100 /// Memory owned by this decl, using Module's allocator.109 /// Memory owned by this decl, using Module's allocator.
101 name: [*:0]const u8,110 name: [*:0]const u8,
102 /// The direct parent container of the Decl. This field will need to get more fleshed out when111 /// The direct parent container of the Decl. This is either a `Scope.File` or `Scope.ZIRModule`.
103 /// self-hosted supports proper struct types and Zig AST => ZIR.
104 /// Reference to externally owned memory.112 /// Reference to externally owned memory.
105 scope: *Scope.ZIRModule,113 scope: *Scope,
106 /// Byte offset into the source file that contains this declaration.114 /// Byte offset into the source file that contains this declaration.
107 /// This is the base offset that src offsets within this Decl are relative to.115 /// This is the base offset that src offsets within this Decl are relative to.
108 src: usize,116 src: usize,
...@@ -171,17 +179,8 @@ pub const Decl = struct {...@@ -171,17 +179,8 @@ pub const Decl = struct {
171179
172 pub const Hash = [16]u8;180 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.
176 pub fn hashSimpleName(name: []const u8) Hash {182 pub fn hashSimpleName(name: []const u8) Hash {
177 var out: Hash = undefined;183 return std.zig.hashSrc(name);
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;
185 }184 }
186185
187 /// Must generate unique bytes with no collisions with other decls.186 /// Must generate unique bytes with no collisions with other decls.
...@@ -290,6 +289,7 @@ pub const Scope = struct {...@@ -290,6 +289,7 @@ pub const Scope = struct {
290 .block => return self.cast(Block).?.arena,289 .block => return self.cast(Block).?.arena,
291 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,290 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
292 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,291 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
292 .file => unreachable,
293 }293 }
294 }294 }
295295
...@@ -300,16 +300,27 @@ pub const Scope = struct {...@@ -300,16 +300,27 @@ pub const Scope = struct {
300 .block => self.cast(Block).?.decl,300 .block => self.cast(Block).?.decl,
301 .decl => self.cast(DeclAnalysis).?.decl,301 .decl => self.cast(DeclAnalysis).?.decl,
302 .zir_module => null,302 .zir_module => null,
303 .file => null,
303 };304 };
304 }305 }
305306
306 /// Asserts the scope has a parent which is a ZIRModule and307 /// Asserts the scope has a parent which is a ZIRModule or File and
307 /// returns it.308 /// returns it.
308 pub fn namespace(self: *Scope) *ZIRModule {309 pub fn namespace(self: *Scope) *Scope {
309 switch (self.tag) {310 switch (self.tag) {
310 .block => return self.cast(Block).?.decl.scope,311 .block => return self.cast(Block).?.decl.scope,
311 .decl => return self.cast(DeclAnalysis).?.decl.scope,312 .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,
313 }324 }
314 }325 }
315326
...@@ -325,12 +336,133 @@ pub const Scope = struct {...@@ -325,12 +336,133 @@ pub const Scope = struct {
325 });336 });
326 }337 }
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
328 pub const Tag = enum {386 pub const Tag = enum {
387 /// .zir source code.
329 zir_module,388 zir_module,
389 /// .zig source code.
390 file,
330 block,391 block,
331 decl,392 decl,
332 };393 };
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
334 pub const ZIRModule = struct {466 pub const ZIRModule = struct {
335 pub const base_tag: Tag = .zir_module;467 pub const base_tag: Tag = .zir_module;
336 base: Scope = Scope{ .tag = base_tag },468 base: Scope = Scope{ .tag = base_tag },
...@@ -392,6 +524,23 @@ pub const Scope = struct {...@@ -392,6 +524,23 @@ pub const Scope = struct {
392 const loc = std.zig.findLineColumn(self.source.bytes, src);524 const loc = std.zig.findLineColumn(self.source.bytes, src);
393 std.debug.warn("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });525 std.debug.warn("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
394 }526 }
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 }
395 };544 };
396545
397 /// This is a temporary structure, references to it are valid only546 /// This is a temporary structure, references to it are valid only
...@@ -466,16 +615,6 @@ pub const InitOptions = struct {...@@ -466,16 +615,6 @@ pub const InitOptions = struct {
466};615};
467616
468pub fn init(gpa: *Allocator, options: InitOptions) !Module {617pub 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
479 const bin_file_dir = options.bin_file_dir orelse std.fs.cwd();618 const bin_file_dir = options.bin_file_dir orelse std.fs.cwd();
480 var bin_file = try link.openBinFilePath(gpa, bin_file_dir, options.bin_file_path, .{619 var bin_file = try link.openBinFilePath(gpa, bin_file_dir, options.bin_file_path, .{
481 .target = options.target,620 .target = options.target,
...@@ -485,6 +624,30 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {...@@ -485,6 +624,30 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
485 });624 });
486 errdefer bin_file.deinit();625 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
488 return Module{651 return Module{
489 .allocator = gpa,652 .allocator = gpa,
490 .root_pkg = options.root_pkg,653 .root_pkg = options.root_pkg,
...@@ -497,7 +660,7 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {...@@ -497,7 +660,7 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
497 .decl_exports = std.AutoHashMap(*Decl, []*Export).init(gpa),660 .decl_exports = std.AutoHashMap(*Decl, []*Export).init(gpa),
498 .export_owners = std.AutoHashMap(*Decl, []*Export).init(gpa),661 .export_owners = std.AutoHashMap(*Decl, []*Export).init(gpa),
499 .failed_decls = std.AutoHashMap(*Decl, *ErrorMsg).init(gpa),662 .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),
501 .failed_exports = std.AutoHashMap(*Export, *ErrorMsg).init(gpa),664 .failed_exports = std.AutoHashMap(*Export, *ErrorMsg).init(gpa),
502 .work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa),665 .work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa),
503 };666 };
...@@ -551,10 +714,7 @@ pub fn deinit(self: *Module) void {...@@ -551,10 +714,7 @@ pub fn deinit(self: *Module) void {
551 }714 }
552 self.export_owners.deinit();715 self.export_owners.deinit();
553 }716 }
554 {717 self.root_scope.destroy(allocator);
555 self.root_scope.deinit(allocator);
556 allocator.destroy(self.root_scope);
557 }
558 self.* = undefined;718 self.* = undefined;
559}719}
560720
...@@ -574,16 +734,25 @@ pub fn update(self: *Module) !void {...@@ -574,16 +734,25 @@ pub fn update(self: *Module) !void {
574 self.generation += 1;734 self.generation += 1;
575735
576 // TODO Use the cache hash file system to detect which source files changed.736 // TODO Use the cache hash file system to detect which source files changed.
577 // Here we simulate a full cache miss.737 // Until then we simulate a full cache miss. Source files could have been loaded for any reason;
578 // Analyze the root source file now.738 // to force a refresh we unload now.
579 // Source files could have been loaded for any reason; to force a refresh we unload now.739 if (self.root_scope.cast(Scope.File)) |zig_file| {
580 self.root_scope.unload(self.allocator);740 zig_file.unload(self.allocator);
581 self.analyzeRoot(self.root_scope) catch |err| switch (err) {741 self.analyzeRootSrcFile(zig_file) catch |err| switch (err) {
582 error.AnalysisFail => {742 error.AnalysisFail => {
583 assert(self.totalErrorCount() != 0);743 assert(self.totalErrorCount() != 0);
584 },744 },
585 else => |e| return e,745 else => |e| return e,
586 };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
588 try self.performAllTheWork();757 try self.performAllTheWork();
589758
...@@ -619,10 +788,10 @@ pub fn makeBinFileWritable(self: *Module) !void {...@@ -619,10 +788,10 @@ pub fn makeBinFileWritable(self: *Module) !void {
619}788}
620789
621pub fn totalErrorCount(self: *Module) usize {790pub fn totalErrorCount(self: *Module) usize {
622 return self.failed_decls.size +791 const total = self.failed_decls.size +
623 self.failed_files.size +792 self.failed_files.size +
624 self.failed_exports.size +793 self.failed_exports.size;
625 @boolToInt(self.link_error_flags.no_entry_point_found);794 return if (total == 0) @boolToInt(self.link_error_flags.no_entry_point_found) else total;
626}795}
627796
628pub fn getAllErrorsAlloc(self: *Module) !AllErrors {797pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
...@@ -637,8 +806,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {...@@ -637,8 +806,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
637 while (it.next()) |kv| {806 while (it.next()) |kv| {
638 const scope = kv.key;807 const scope = kv.key;
639 const err_msg = kv.value;808 const err_msg = kv.value;
640 const source = try self.getSource(scope);809 const source = try scope.getSource(self);
641 try AllErrors.add(&arena, &errors, scope.sub_file_path, source, err_msg.*);810 try AllErrors.add(&arena, &errors, scope.subFilePath(), source, err_msg.*);
642 }811 }
643 }812 }
644 {813 {
...@@ -646,8 +815,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {...@@ -646,8 +815,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
646 while (it.next()) |kv| {815 while (it.next()) |kv| {
647 const decl = kv.key;816 const decl = kv.key;
648 const err_msg = kv.value;817 const err_msg = kv.value;
649 const source = try self.getSource(decl.scope);818 const source = try decl.scope.getSource(self);
650 try AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg.*);819 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
651 }820 }
652 }821 }
653 {822 {
...@@ -655,12 +824,12 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {...@@ -655,12 +824,12 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
655 while (it.next()) |kv| {824 while (it.next()) |kv| {
656 const decl = kv.key.owner_decl;825 const decl = kv.key.owner_decl;
657 const err_msg = kv.value;826 const err_msg = kv.value;
658 const source = try self.getSource(decl.scope);827 const source = try decl.scope.getSource(self);
659 try AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg.*);828 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
660 }829 }
661 }830 }
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) {
664 try errors.append(.{833 try errors.append(.{
665 .src_path = self.root_pkg.root_src_path,834 .src_path = self.root_pkg.root_src_path,
666 .line = 0,835 .line = 0,
...@@ -740,30 +909,491 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {...@@ -740,30 +909,491 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
740 => continue,909 => continue,
741910
742 .outdated => {911 .outdated => {
743 const zir_module = self.getSrcModule(decl.scope) catch |err| switch (err) {912 if (decl.scope.cast(Scope.File)) |file_scope| {
744 error.OutOfMemory => return error.OutOfMemory,913 @panic("TODO re_analyze_decl for .zig files");
745 else => {914 } else if (decl.scope.cast(Scope.ZIRModule)) |zir_scope| {
746 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);915 const zir_module = self.getSrcModule(zir_scope) catch |err| switch (err) {
747 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(916 error.OutOfMemory => return error.OutOfMemory,
748 self.allocator,917 else => {
749 decl.src,918 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
750 "unable to load source file '{}': {}",919 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
751 .{ decl.scope.sub_file_path, @errorName(err) },920 self.allocator,
752 ));921 decl.src,
753 decl.analysis = .codegen_failure_retryable;922 "unable to load source file '{}': {}",
754 continue;923 .{ zir_scope.sub_file_path, @errorName(err) },
755 },924 ));
756 };925 decl.analysis = .codegen_failure_retryable;
757 const decl_name = mem.spanZ(decl.name);926 continue;
758 // We already detected deletions, so we know this will be found.927 },
759 const src_decl = zir_module.findDecl(decl_name).?;928 };
760 self.reAnalyzeDecl(decl, src_decl) catch |err| switch (err) {929 const decl_name = mem.spanZ(decl.name);
761 error.OutOfMemory => return error.OutOfMemory,930 // We already detected deletions, so we know this will be found.
762 error.AnalysisFail => continue,931 const src_decl = zir_module.findDecl(decl_name).?;
763 };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,
764 },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;
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,
765 },1331 },
1332 .positionals = .{},
1333 .kw_args = .{},
766 };1334 };
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;
767}1397}
7681398
769fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {1399fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {
...@@ -783,29 +1413,12 @@ fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void...@@ -783,29 +1413,12 @@ fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void
783 }1413 }
784}1414}
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
803fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {1416fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
804 switch (root_scope.status) {1417 switch (root_scope.status) {
805 .never_loaded, .unloaded_success => {1418 .never_loaded, .unloaded_success => {
806 try self.failed_files.ensureCapacity(self.failed_files.size + 1);1419 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
810 var keep_zir_module = false;1423 var keep_zir_module = false;
811 const zir_module = try self.allocator.create(zir.Module);1424 const zir_module = try self.allocator.create(zir.Module);
...@@ -816,7 +1429,7 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {...@@ -816,7 +1429,7 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
8161429
817 if (zir_module.error_msg) |src_err_msg| {1430 if (zir_module.error_msg) |src_err_msg| {
818 self.failed_files.putAssumeCapacityNoClobber(1431 self.failed_files.putAssumeCapacityNoClobber(
819 root_scope,1432 &root_scope.base,
820 try ErrorMsg.create(self.allocator, src_err_msg.byte_offset, "{}", .{src_err_msg.msg}),1433 try ErrorMsg.create(self.allocator, src_err_msg.byte_offset, "{}", .{src_err_msg.msg}),
821 );1434 );
822 root_scope.status = .unloaded_parse_failure;1435 root_scope.status = .unloaded_parse_failure;
...@@ -838,7 +1451,83 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {...@@ -838,7 +1451,83 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
838 }1451 }
839}1452}
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 {
842 switch (root_scope.status) {1531 switch (root_scope.status) {
843 .never_loaded => {1532 .never_loaded => {
844 const src_module = try self.getSrcModule(root_scope);1533 const src_module = try self.getSrcModule(root_scope);
...@@ -882,12 +1571,10 @@ fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void {...@@ -882,12 +1571,10 @@ fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void {
882 if (self.decl_table.get(name_hash)) |kv| {1571 if (self.decl_table.get(name_hash)) |kv| {
883 const decl = kv.value;1572 const decl = kv.value;
884 deleted_decls.removeAssertDiscard(decl);1573 deleted_decls.removeAssertDiscard(decl);
885 const new_contents_hash = Decl.hashSimpleName(src_decl.contents);
886 //std.debug.warn("'{}' contents: '{}'\n", .{ src_decl.name, src_decl.contents });1574 //std.debug.warn("'{}' contents: '{}'\n", .{ src_decl.name, src_decl.contents });
887 if (!mem.eql(u8, &new_contents_hash, &decl.contents_hash)) {1575 if (!mem.eql(u8, &src_decl.contents_hash, &decl.contents_hash)) {
888 //std.debug.warn("'{}' {x} => {x}\n", .{ src_decl.name, decl.contents_hash, new_contents_hash });
889 try self.markOutdatedDecl(decl);1576 try self.markOutdatedDecl(decl);
890 decl.contents_hash = new_contents_hash;1577 decl.contents_hash = src_decl.contents_hash;
891 }1578 }
892 } else if (src_decl.cast(zir.Inst.Export)) |export_inst| {1579 } else if (src_decl.cast(zir.Inst.Export)) |export_inst| {
893 try exports_to_resolve.append(&export_inst.base);1580 try exports_to_resolve.append(&export_inst.base);
...@@ -1038,7 +1725,7 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi...@@ -1038,7 +1725,7 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi
1038 };1725 };
1039 errdefer decl_scope.arena.deinit();1726 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) {
1042 error.OutOfMemory => return error.OutOfMemory,1729 error.OutOfMemory => return error.OutOfMemory,
1043 error.AnalysisFail => {1730 error.AnalysisFail => {
1044 switch (decl.analysis) {1731 switch (decl.analysis) {
...@@ -1109,9 +1796,91 @@ fn markOutdatedDecl(self: *Module, decl: *Decl) !void {...@@ -1109,9 +1796,91 @@ fn markOutdatedDecl(self: *Module, decl: *Decl) !void {
1109 decl.analysis = .outdated;1796 decl.analysis = .outdated;
1110}1797}
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
1112fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl {1875fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl {
1113 const hash = Decl.hashSimpleName(old_inst.name);1876 if (old_inst.name.len == 0) {
1114 if (self.decl_table.get(hash)) |kv| {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| {
1115 const decl = kv.value;1884 const decl = kv.value;
1116 try self.reAnalyzeDecl(decl, old_inst);1885 try self.reAnalyzeDecl(decl, old_inst);
1117 return decl;1886 return decl;
...@@ -1119,63 +1888,9 @@ fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*De...@@ -1119,63 +1888,9 @@ fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*De
1119 // This is just a named reference to another decl.1888 // This is just a named reference to another decl.
1120 return self.analyzeDeclVal(scope, decl_val);1889 return self.analyzeDeclVal(scope, decl_val);
1121 } else {1890 } else {
1122 const new_decl = blk: {1891 const new_decl = try self.createNewDecl(scope, old_inst.name, old_inst.src, name_hash, old_inst.contents_hash);
1123 try self.decl_table.ensureCapacity(self.decl_table.size + 1);1892 try self.analyzeNewDecl(new_decl, old_inst);
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 };
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 }
1179 return new_decl;1894 return new_decl;
1180 }1895 }
1181}1896}
...@@ -1208,9 +1923,13 @@ fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In...@@ -1208,9 +1923,13 @@ fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
1208 }1923 }
1209 }1924 }
12101925
1211 const decl = try self.resolveCompleteDecl(scope, old_inst);1926 if (scope.namespace().tag == .zir_module) {
1212 const decl_ref = try self.analyzeDeclRef(scope, old_inst.src, decl);1927 const decl = try self.resolveCompleteDecl(scope, old_inst);
1213 return self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src);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);
1214}1933}
12151934
1216fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {1935fn 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...@@ -1451,7 +2170,7 @@ fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigI
1451 });2170 });
1452}2171}
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 {
1455 const new_inst = try self.analyzeInst(scope, old_inst);2174 const new_inst = try self.analyzeInst(scope, old_inst);
1456 return TypedValue{2175 return TypedValue{
1457 .ty = new_inst.ty,2176 .ty = new_inst.ty,
...@@ -1459,11 +2178,16 @@ fn analyzeInstConst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerErro...@@ -1459,11 +2178,16 @@ fn analyzeInstConst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerErro
1459 };2178 };
1460}2179}
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
1462fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {2185fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
1463 switch (old_inst.tag) {2186 switch (old_inst.tag) {
1464 .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?),2187 .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?),
1465 .call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?),2188 .call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?),
1466 .compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?),2189 .compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?),
2190 .@"const" => return self.analyzeInstConst(scope, old_inst.cast(zir.Inst.Const).?),
1467 .declref => return self.analyzeInstDeclRef(scope, old_inst.cast(zir.Inst.DeclRef).?),2191 .declref => return self.analyzeInstDeclRef(scope, old_inst.cast(zir.Inst.DeclRef).?),
1468 .declval => return self.analyzeInstDeclVal(scope, old_inst.cast(zir.Inst.DeclVal).?),2192 .declval => return self.analyzeInstDeclVal(scope, old_inst.cast(zir.Inst.DeclVal).?),
1469 .str => {2193 .str => {
...@@ -1520,18 +2244,23 @@ fn analyzeInstRef(self: *Module, scope: *Scope, inst: *zir.Inst.Ref) InnerError!...@@ -1520,18 +2244,23 @@ fn analyzeInstRef(self: *Module, scope: *Scope, inst: *zir.Inst.Ref) InnerError!
1520fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst {2244fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst {
1521 const decl_name = try self.resolveConstString(scope, inst.positionals.name);2245 const decl_name = try self.resolveConstString(scope, inst.positionals.name);
1522 // This will need to get more fleshed out when there are proper structs & namespaces.2246 // This will need to get more fleshed out when there are proper structs & namespaces.
1523 const zir_module = scope.namespace();2247 const namespace = scope.namespace();
1524 const src_decl = zir_module.contents.module.findDecl(decl_name) orelse2248 if (namespace.cast(Scope.File)) |scope_file| {
1525 return self.fail(scope, inst.positionals.name.src, "use of undeclared identifier '{}'", .{decl_name});2249 return self.fail(scope, inst.base.src, "TODO implement declref for zig source", .{});
15262250 } else if (namespace.cast(Scope.ZIRModule)) |zir_module| {
1527 const decl = try self.resolveCompleteDecl(scope, src_decl);2251 const src_decl = zir_module.contents.module.findDecl(decl_name) orelse
1528 return self.analyzeDeclRef(scope, inst.base.src, decl);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 }
1529}2259}
15302260
1531fn analyzeDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Decl {2261fn analyzeDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Decl {
1532 const decl_name = inst.positionals.name;2262 const decl_name = inst.positionals.name;
1533 // This will need to get more fleshed out when there are proper structs & namespaces.2263 const zir_module = scope.namespace().cast(Scope.ZIRModule).?;
1534 const zir_module = scope.namespace();
1535 const src_decl = zir_module.contents.module.findDecl(decl_name) orelse2264 const src_decl = zir_module.contents.module.findDecl(decl_name) orelse
1536 return self.fail(scope, inst.base.src, "use of undeclared identifier '{}'", .{decl_name});2265 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...@@ -2316,6 +3045,30 @@ fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, a
2316 return self.failWithOwnedErrorMsg(scope, src, err_msg);3045 return self.failWithOwnedErrorMsg(scope, src, err_msg);
2317}3046}
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
2319fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *ErrorMsg) InnerError {3072fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *ErrorMsg) InnerError {
2320 {3073 {
2321 errdefer err_msg.destroy(self.allocator);3074 errdefer err_msg.destroy(self.allocator);
...@@ -2336,8 +3089,9 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err...@@ -2336,8 +3089,9 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err
2336 .zir_module => {3089 .zir_module => {
2337 const zir_module = scope.cast(Scope.ZIRModule).?;3090 const zir_module = scope.cast(Scope.ZIRModule).?;
2338 zir_module.status = .loaded_sema_failure;3091 zir_module.status = .loaded_sema_failure;
2339 self.failed_files.putAssumeCapacityNoClobber(zir_module, err_msg);3092 self.failed_files.putAssumeCapacityNoClobber(scope, err_msg);
2340 },3093 },
3094 .file => unreachable,
2341 }3095 }
2342 return error.AnalysisFail;3096 return error.AnalysisFail;
2343}3097}
src-self-hosted/main.zig+1-1
...@@ -86,7 +86,7 @@ const usage_build_generic =...@@ -86,7 +86,7 @@ const usage_build_generic =
86 \\ zig build-obj <options> [files]86 \\ zig build-obj <options> [files]
87 \\87 \\
88 \\Supported file types:88 \\Supported file types:
89 \\ (planned) .zig Zig source code89 \\ .zig Zig source code
90 \\ .zir Zig Intermediate Representation code90 \\ .zir Zig Intermediate Representation code
91 \\ (planned) .o ELF object file91 \\ (planned) .o ELF object file
92 \\ (planned) .o MACH-O (macOS) object file92 \\ (planned) .o MACH-O (macOS) object file
src-self-hosted/value.zig+2-2
...@@ -78,8 +78,8 @@ pub const Value = extern union {...@@ -78,8 +78,8 @@ pub const Value = extern union {
78 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;78 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
79 };79 };
8080
81 pub fn initTag(comptime small_tag: Tag) Value {81 pub fn initTag(small_tag: Tag) Value {
82 comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);82 assert(@enumToInt(small_tag) < Tag.no_payload_count);
83 return .{ .tag_if_small_enough = @enumToInt(small_tag) };83 return .{ .tag_if_small_enough = @enumToInt(small_tag) };
84 }84 }
8585
src-self-hosted/zir.zig+35-17
...@@ -14,20 +14,24 @@ const IrModule = @import("Module.zig");...@@ -14,20 +14,24 @@ const IrModule = @import("Module.zig");
1414
15/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for15/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for
16/// in-memory, analyzed instructions with types and values.16/// 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.
17pub const Inst = struct {19pub const Inst = struct {
18 tag: Tag,20 tag: Tag,
19 /// Byte offset into the source.21 /// Byte offset into the source.
20 src: usize,22 src: usize,
21 name: []const u8,23 name: []const u8,
2224
23 /// Slice into the source of the part after the = and before the next instruction.25 /// Hash of slice into the source of the part after the = and before the next instruction.
24 contents: []const u8 = &[0]u8{},26 contents_hash: std.zig.SrcHash = undefined,
2527
26 /// These names are used directly as the instruction names in the text format.28 /// These names are used directly as the instruction names in the text format.
27 pub const Tag = enum {29 pub const Tag = enum {
28 breakpoint,30 breakpoint,
29 call,31 call,
30 compileerror,32 compileerror,
33 /// Special case, has no textual representation.
34 @"const",
31 /// Represents a pointer to a global decl by name.35 /// Represents a pointer to a global decl by name.
32 declref,36 declref,
33 /// The syntax `@foo` is equivalent to `declval("foo")`.37 /// The syntax `@foo` is equivalent to `declval("foo")`.
...@@ -43,10 +47,10 @@ pub const Inst = struct {...@@ -43,10 +47,10 @@ pub const Inst = struct {
43 @"unreachable",47 @"unreachable",
44 @"return",48 @"return",
45 @"fn",49 @"fn",
50 fntype,
46 @"export",51 @"export",
47 primitive,52 primitive,
48 ref,53 ref,
49 fntype,
50 intcast,54 intcast,
51 bitcast,55 bitcast,
52 elemptr,56 elemptr,
...@@ -64,6 +68,7 @@ pub const Inst = struct {...@@ -64,6 +68,7 @@ pub const Inst = struct {
64 .declref => DeclRef,68 .declref => DeclRef,
65 .declval => DeclVal,69 .declval => DeclVal,
66 .compileerror => CompileError,70 .compileerror => CompileError,
71 .@"const" => Const,
67 .str => Str,72 .str => Str,
68 .int => Int,73 .int => Int,
69 .ptrtoint => PtrToInt,74 .ptrtoint => PtrToInt,
...@@ -147,6 +152,16 @@ pub const Inst = struct {...@@ -147,6 +152,16 @@ pub const Inst = struct {
147 kw_args: struct {},152 kw_args: struct {},
148 };153 };
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
150 pub const Str = struct {165 pub const Str = struct {
151 pub const base_tag = Tag.str;166 pub const base_tag = Tag.str;
152 base: Inst,167 base: Inst,
...@@ -253,6 +268,19 @@ pub const Inst = struct {...@@ -253,6 +268,19 @@ pub const Inst = struct {
253 kw_args: struct {},268 kw_args: struct {},
254 };269 };
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
256 pub const Export = struct {284 pub const Export = struct {
257 pub const base_tag = Tag.@"export";285 pub const base_tag = Tag.@"export";
258 base: Inst,286 base: Inst,
...@@ -348,19 +376,6 @@ pub const Inst = struct {...@@ -348,19 +376,6 @@ pub const Inst = struct {
348 };376 };
349 };377 };
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
364 pub const IntCast = struct {379 pub const IntCast = struct {
365 pub const base_tag = Tag.intcast;380 pub const base_tag = Tag.intcast;
366 base: Inst,381 base: Inst,
...@@ -526,6 +541,7 @@ pub const Module = struct {...@@ -526,6 +541,7 @@ pub const Module = struct {
526 .declref => return self.writeInstToStreamGeneric(stream, .declref, decl, inst_table),541 .declref => return self.writeInstToStreamGeneric(stream, .declref, decl, inst_table),
527 .declval => return self.writeInstToStreamGeneric(stream, .declval, decl, inst_table),542 .declval => return self.writeInstToStreamGeneric(stream, .declval, decl, inst_table),
528 .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, decl, inst_table),543 .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, decl, inst_table),
544 .@"const" => return self.writeInstToStreamGeneric(stream, .@"const", decl, inst_table),
529 .str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table),545 .str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table),
530 .int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table),546 .int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table),
531 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table),547 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table),
...@@ -619,6 +635,7 @@ pub const Module = struct {...@@ -619,6 +635,7 @@ pub const Module = struct {
619 bool => return stream.writeByte("01"[@boolToInt(param)]),635 bool => return stream.writeByte("01"[@boolToInt(param)]),
620 []u8, []const u8 => return std.zig.renderStringLiteral(param, stream),636 []u8, []const u8 => return std.zig.renderStringLiteral(param, stream),
621 BigIntConst => return stream.print("{}", .{param}),637 BigIntConst => return stream.print("{}", .{param}),
638 TypedValue => unreachable, // this is a special case
622 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),639 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
623 }640 }
624 }641 }
...@@ -929,7 +946,7 @@ const Parser = struct {...@@ -929,7 +946,7 @@ const Parser = struct {
929 }946 }
930 try requireEatBytes(self, ")");947 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]);
933 //std.debug.warn("parsed {} = '{}'\n", .{ inst_specific.base.name, inst_specific.base.contents });950 //std.debug.warn("parsed {} = '{}'\n", .{ inst_specific.base.name, inst_specific.base.contents });
934951
935 return &inst_specific.base;952 return &inst_specific.base;
...@@ -978,6 +995,7 @@ const Parser = struct {...@@ -978,6 +995,7 @@ const Parser = struct {
978 *Inst => return parseParameterInst(self, body_ctx),995 *Inst => return parseParameterInst(self, body_ctx),
979 []u8, []const u8 => return self.parseStringLiteral(),996 []u8, []const u8 => return self.parseStringLiteral(),
980 BigIntConst => return self.parseIntegerLiteral(),997 BigIntConst => return self.parseIntegerLiteral(),
998 TypedValue => return self.fail("'const' is a special instruction; not legal in ZIR text", .{}),
981 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),999 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
982 }1000 }
983 return self.fail("TODO parse parameter {}", .{@typeName(T)});1001 return self.fail("TODO parse parameter {}", .{@typeName(T)});