authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-24 22:37:58-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-06-24 22:37:58-04:00
logd337469e4484ffd160b4508e2366fefd435f6c8a
tree7ad577eb66febb985ed029ae75c47461611775e2
parent7875649c2481f90b918581670c9268d6033f873f
parent20b4a2cf2cded8904a57714ed2b90c857f12c6b1
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5583 from ziglang/zig-ast-to-zir

self-hosted: hook up Zig AST to ZIR

20 files changed, 2578 insertions(+), 1202 deletions(-)

build.zig+13
......@@ -72,9 +72,22 @@ pub fn build(b: *Builder) !void {
7272 if (!only_install_lib_files) {
7373 exe.install();
7474 }
75 const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");
7576 const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse false;
7677 if (link_libc) exe.linkLibC();
7778
79 exe.addBuildOption(bool, "enable_tracy", tracy != null);
80 if (tracy) |tracy_path| {
81 const client_cpp = fs.path.join(
82 b.allocator,
83 &[_][]const u8{ tracy_path, "TracyClient.cpp" },
84 ) catch unreachable;
85 exe.addIncludeDir(tracy_path);
86 exe.addCSourceFile(client_cpp, &[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" });
87 exe.linkSystemLibraryName("c++");
88 exe.linkLibC();
89 }
90
7891 b.installDirectory(InstallDirectoryOptions{
7992 .source_dir = "lib",
8093 .install_dir = .Lib,
lib/std/build.zig+3-2
......@@ -1905,10 +1905,11 @@ pub const LibExeObjStep = struct {
19051905 builder.allocator,
19061906 &[_][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", .{self.name}) },
19071907 );
1908 try fs.cwd().writeFile(build_options_file, self.build_options_contents.span());
1908 const path_from_root = builder.pathFromRoot(build_options_file);
1909 try fs.cwd().writeFile(path_from_root, self.build_options_contents.span());
19091910 try zig_args.append("--pkg-begin");
19101911 try zig_args.append("build_options");
1911 try zig_args.append(builder.pathFromRoot(build_options_file));
1912 try zig_args.append(path_from_root);
19121913 try zig_args.append("--pkg-end");
19131914 }
19141915
lib/std/zig.zig+38
......@@ -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;
......@@ -26,6 +43,27 @@ pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usi
2643 return .{ .line = line, .column = column };
2744}
2845
46/// Returns the standard file system basename of a binary generated by the Zig compiler.
47pub fn binNameAlloc(
48 allocator: *std.mem.Allocator,
49 root_name: []const u8,
50 target: std.Target,
51 output_mode: std.builtin.OutputMode,
52 link_mode: ?std.builtin.LinkMode,
53) error{OutOfMemory}![]u8 {
54 switch (output_mode) {
55 .Exe => return std.fmt.allocPrint(allocator, "{}{}", .{ root_name, target.exeFileExt() }),
56 .Lib => {
57 const suffix = switch (link_mode orelse .Static) {
58 .Static => target.staticLibSuffix(),
59 .Dynamic => target.dynamicLibSuffix(),
60 };
61 return std.fmt.allocPrint(allocator, "{}{}{}", .{ target.libPrefix(), root_name, suffix });
62 },
63 .Obj => return std.fmt.allocPrint(allocator, "{}{}", .{ root_name, target.oFileExt() }),
64 }
65}
66
2967test "" {
3068 @import("std").meta.refAllDecls(@This());
3169}
lib/std/zig/ast.zig+2
......@@ -2260,6 +2260,8 @@ pub const Node = struct {
22602260 }
22612261 };
22622262
2263 /// TODO break this into separate Break, Continue, Return AST Nodes to save memory.
2264 /// Could be further broken into LabeledBreak, LabeledContinue, and ReturnVoid to save even more.
22632265 pub const ControlFlowExpression = struct {
22642266 base: Node = Node{ .id = .ControlFlowExpression },
22652267 ltoken: TokenIndex,
lib/std/zig/parse.zig+1-1
......@@ -3222,7 +3222,7 @@ const Parser = struct {
32223222 }
32233223
32243224 /// Op* Child
3225 fn parsePrefixOpExpr(p: *Parser, opParseFn: NodeParseFn, childParseFn: NodeParseFn) Error!?*Node {
3225 fn parsePrefixOpExpr(p: *Parser, comptime opParseFn: NodeParseFn, comptime childParseFn: NodeParseFn) Error!?*Node {
32263226 if (try opParseFn(p)) |first_op| {
32273227 var rightmost_op = first_op;
32283228 while (true) {
src-self-hosted/Module.zig+1457-460
......@@ -15,13 +15,16 @@ const ir = @import("ir.zig");
1515const zir = @import("zir.zig");
1616const Module = @This();
1717const Inst = ir.Inst;
18const ast = std.zig.ast;
19const trace = @import("tracy.zig").trace;
1820
1921/// General-purpose allocator.
2022allocator: *Allocator,
2123/// Pointer to externally managed resource.
2224root_pkg: *Package,
2325/// Module owns this resource.
24root_scope: *Scope.ZIRModule,
26/// The `Scope` is either a `Scope.ZIRModule` or `Scope.File`.
27root_scope: *Scope,
2528bin_file: link.ElfFile,
2629bin_file_dir: std.fs.Dir,
2730bin_file_path: []const u8,
......@@ -35,10 +38,10 @@ decl_exports: std.AutoHashMap(*Decl, []*Export),
3538/// This table owns the Export memory.
3639export_owners: std.AutoHashMap(*Decl, []*Export),
3740/// Maps fully qualified namespaced names to the Decl struct for them.
38decl_table: std.AutoHashMap(Decl.Hash, *Decl),
41decl_table: DeclTable,
3942
4043optimize_mode: std.builtin.Mode,
41link_error_flags: link.ElfFile.ErrorFlags = link.ElfFile.ErrorFlags{},
44link_error_flags: link.ElfFile.ErrorFlags = .{},
4245
4346work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic),
4447
......@@ -49,8 +52,8 @@ work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic),
4952/// a Decl can have a failed_decls entry but have analysis status of success.
5053failed_decls: std.AutoHashMap(*Decl, *ErrorMsg),
5154/// 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),
55/// The ErrorMsg memory is owned by the `Scope`, using Module's allocator.
56failed_files: std.AutoHashMap(*Scope, *ErrorMsg),
5457/// Using a map here for consistency with the other fields here.
5558/// The ErrorMsg memory is owned by the `Export`, using Module's allocator.
5659failed_exports: std.AutoHashMap(*Export, *ErrorMsg),
......@@ -60,15 +63,23 @@ failed_exports: std.AutoHashMap(*Export, *ErrorMsg),
6063/// previous analysis.
6164generation: u32 = 0,
6265
66next_anon_name_index: usize = 0,
67
6368/// Candidates for deletion. After a semantic analysis update completes, this list
6469/// contains Decls that need to be deleted if they end up having no references to them.
65deletion_set: std.ArrayListUnmanaged(*Decl) = std.ArrayListUnmanaged(*Decl){},
70deletion_set: std.ArrayListUnmanaged(*Decl) = .{},
71
72keep_source_files_loaded: bool,
73
74const DeclTable = std.HashMap(Scope.NameHash, *Decl, Scope.name_hash_hash, Scope.name_hash_eql);
6675
67pub const WorkItem = union(enum) {
76const WorkItem = union(enum) {
6877 /// Write the machine code for a Decl to the output file.
6978 codegen_decl: *Decl,
70 /// Decl has been determined to be outdated; perform semantic analysis again.
71 re_analyze_decl: *Decl,
79 /// The Decl needs to be analyzed and possibly export itself.
80 /// It may have already be analyzed, or it may have been determined
81 /// to be outdated; in this case perform semantic analysis again.
82 analyze_decl: *Decl,
7283};
7384
7485pub const Export = struct {
......@@ -99,13 +110,12 @@ pub const Decl = struct {
99110 /// mapping them to an address in the output file.
100111 /// Memory owned by this decl, using Module's allocator.
101112 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.
113 /// The direct parent container of the Decl. This is either a `Scope.File` or `Scope.ZIRModule`.
104114 /// Reference to externally owned memory.
105 scope: *Scope.ZIRModule,
106 /// 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.
108 src: usize,
115 scope: *Scope,
116 /// The AST Node decl index or ZIR Inst index that contains this declaration.
117 /// Must be recomputed when the corresponding source file is modified.
118 src_index: usize,
109119 /// The most recent value of the Decl after a successful semantic analysis.
110120 typed_value: union(enum) {
111121 never_succeeded: void,
......@@ -116,6 +126,9 @@ pub const Decl = struct {
116126 /// analysis of the function body is performed with this value set to `success`. Functions
117127 /// have their own analysis status field.
118128 analysis: enum {
129 /// This Decl corresponds to an AST Node that has not been referenced yet, and therefore
130 /// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced.
131 unreferenced,
119132 /// Semantic analysis for this Decl is running right now. This state detects dependency loops.
120133 in_progress,
121134 /// This Decl might be OK but it depends on another one which did not successfully complete
......@@ -125,6 +138,10 @@ pub const Decl = struct {
125138 /// There will be a corresponding ErrorMsg in Module.failed_decls.
126139 sema_failure,
127140 /// There will be a corresponding ErrorMsg in Module.failed_decls.
141 /// This indicates the failure was something like running out of disk space,
142 /// and attempting semantic analysis again may succeed.
143 sema_failure_retryable,
144 /// There will be a corresponding ErrorMsg in Module.failed_decls.
128145 codegen_failure,
129146 /// There will be a corresponding ErrorMsg in Module.failed_decls.
130147 /// This indicates the failure was something like running out of disk space,
......@@ -150,7 +167,7 @@ pub const Decl = struct {
150167 /// This is populated regardless of semantic analysis and code generation.
151168 link: link.ElfFile.TextBlock = link.ElfFile.TextBlock.empty,
152169
153 contents_hash: Hash,
170 contents_hash: std.zig.SrcHash,
154171
155172 /// The shallow set of other decls whose typed_value could possibly change if this Decl's
156173 /// typed_value is modified.
......@@ -169,28 +186,28 @@ pub const Decl = struct {
169186 allocator.destroy(self);
170187 }
171188
172 pub const Hash = [16]u8;
173
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 {
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);
189 pub fn src(self: Decl) usize {
190 switch (self.scope.tag) {
191 .file => {
192 const file = @fieldParentPtr(Scope.File, "base", self.scope);
193 const tree = file.contents.tree;
194 const decl_node = tree.root_node.decls()[self.src_index];
195 return tree.token_locs[decl_node.firstToken()].start;
196 },
197 .zir_module => {
198 const zir_module = @fieldParentPtr(Scope.ZIRModule, "base", self.scope);
199 const module = zir_module.contents.module;
200 const src_decl = module.decls[self.src_index];
201 return src_decl.inst.src;
202 },
203 .block => unreachable,
204 .gen_zir => unreachable,
205 .decl => unreachable,
183206 }
184 return out;
185207 }
186208
187 /// Must generate unique bytes with no collisions with other decls.
188 /// The point of hashing here is only to limit the number of bytes of
189 /// the unique identifier to a fixed size (16 bytes).
190 pub fn fullyQualifiedNameHash(self: Decl) Hash {
191 // Right now we only have ZIRModule as the source. So this is simply the
192 // relative name of the decl.
193 return hashSimpleName(mem.spanZ(self.name));
209 pub fn fullyQualifiedNameHash(self: Decl) Scope.NameHash {
210 return self.scope.fullyQualifiedNameHash(mem.spanZ(self.name));
194211 }
195212
196213 pub fn typedValue(self: *Decl) error{AnalysisFail}!TypedValue {
......@@ -248,11 +265,9 @@ pub const Decl = struct {
248265/// Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
249266pub const Fn = struct {
250267 /// This memory owned by the Decl's TypedValue.Managed arena allocator.
251 fn_type: Type,
252268 analysis: union(enum) {
253 /// The value is the source instruction.
254 queued: *zir.Inst.Fn,
255 in_progress: *Analysis,
269 queued: *ZIR,
270 in_progress,
256271 /// There will be a corresponding ErrorMsg in Module.failed_decls
257272 sema_failure,
258273 /// This Fn might be OK but it depends on another Decl which did not successfully complete
......@@ -266,16 +281,20 @@ pub const Fn = struct {
266281 /// of Fn analysis.
267282 pub const Analysis = struct {
268283 inner_block: Scope.Block,
269 /// TODO Performance optimization idea: instead of this inst_table,
270 /// use a field in the zir.Inst instead to track corresponding instructions
271 inst_table: std.AutoHashMap(*zir.Inst, *Inst),
272 needed_inst_capacity: usize,
284 };
285
286 /// Contains un-analyzed ZIR instructions generated from Zig source AST.
287 pub const ZIR = struct {
288 body: zir.Module.Body,
289 arena: std.heap.ArenaAllocator.State,
273290 };
274291};
275292
276293pub const Scope = struct {
277294 tag: Tag,
278295
296 pub const NameHash = [16]u8;
297
279298 pub fn cast(base: *Scope, comptime T: type) ?*T {
280299 if (base.tag != T.base_tag)
281300 return null;
......@@ -289,7 +308,9 @@ pub const Scope = struct {
289308 switch (self.tag) {
290309 .block => return self.cast(Block).?.arena,
291310 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
311 .gen_zir => return &self.cast(GenZIR).?.arena.allocator,
292312 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
313 .file => unreachable,
293314 }
294315 }
295316
......@@ -298,18 +319,45 @@ pub const Scope = struct {
298319 pub fn decl(self: *Scope) ?*Decl {
299320 return switch (self.tag) {
300321 .block => self.cast(Block).?.decl,
322 .gen_zir => self.cast(GenZIR).?.decl,
301323 .decl => self.cast(DeclAnalysis).?.decl,
302324 .zir_module => null,
325 .file => null,
303326 };
304327 }
305328
306 /// Asserts the scope has a parent which is a ZIRModule and
329 /// Asserts the scope has a parent which is a ZIRModule or File and
307330 /// returns it.
308 pub fn namespace(self: *Scope) *ZIRModule {
331 pub fn namespace(self: *Scope) *Scope {
309332 switch (self.tag) {
310333 .block => return self.cast(Block).?.decl.scope,
334 .gen_zir => return self.cast(GenZIR).?.decl.scope,
311335 .decl => return self.cast(DeclAnalysis).?.decl.scope,
312 .zir_module => return self.cast(ZIRModule).?,
336 .zir_module, .file => return self,
337 }
338 }
339
340 /// Must generate unique bytes with no collisions with other decls.
341 /// The point of hashing here is only to limit the number of bytes of
342 /// the unique identifier to a fixed size (16 bytes).
343 pub fn fullyQualifiedNameHash(self: *Scope, name: []const u8) NameHash {
344 switch (self.tag) {
345 .block => unreachable,
346 .gen_zir => unreachable,
347 .decl => unreachable,
348 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),
349 .file => return self.cast(File).?.fullyQualifiedNameHash(name),
350 }
351 }
352
353 /// Asserts the scope is a child of a File and has an AST tree and returns the tree.
354 pub fn tree(self: *Scope) *ast.Tree {
355 switch (self.tag) {
356 .file => return self.cast(File).?.contents.tree,
357 .zir_module => unreachable,
358 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(File).?.contents.tree,
359 .block => return self.cast(Block).?.decl.scope.cast(File).?.contents.tree,
360 .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(File).?.contents.tree,
313361 }
314362 }
315363
......@@ -325,10 +373,173 @@ pub const Scope = struct {
325373 });
326374 }
327375
376 /// Asserts the scope has a parent which is a ZIRModule or File and
377 /// returns the sub_file_path field.
378 pub fn subFilePath(base: *Scope) []const u8 {
379 switch (base.tag) {
380 .file => return @fieldParentPtr(File, "base", base).sub_file_path,
381 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,
382 .block => unreachable,
383 .gen_zir => unreachable,
384 .decl => unreachable,
385 }
386 }
387
388 pub fn unload(base: *Scope, allocator: *Allocator) void {
389 switch (base.tag) {
390 .file => return @fieldParentPtr(File, "base", base).unload(allocator),
391 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).unload(allocator),
392 .block => unreachable,
393 .gen_zir => unreachable,
394 .decl => unreachable,
395 }
396 }
397
398 pub fn getSource(base: *Scope, module: *Module) ![:0]const u8 {
399 switch (base.tag) {
400 .file => return @fieldParentPtr(File, "base", base).getSource(module),
401 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),
402 .gen_zir => unreachable,
403 .block => unreachable,
404 .decl => unreachable,
405 }
406 }
407
408 /// Asserts the scope is a namespace Scope and removes the Decl from the namespace.
409 pub fn removeDecl(base: *Scope, child: *Decl) void {
410 switch (base.tag) {
411 .file => return @fieldParentPtr(File, "base", base).removeDecl(child),
412 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),
413 .block => unreachable,
414 .gen_zir => unreachable,
415 .decl => unreachable,
416 }
417 }
418
419 /// Asserts the scope is a File or ZIRModule and deinitializes it, then deallocates it.
420 pub fn destroy(base: *Scope, allocator: *Allocator) void {
421 switch (base.tag) {
422 .file => {
423 const scope_file = @fieldParentPtr(File, "base", base);
424 scope_file.deinit(allocator);
425 allocator.destroy(scope_file);
426 },
427 .zir_module => {
428 const scope_zir_module = @fieldParentPtr(ZIRModule, "base", base);
429 scope_zir_module.deinit(allocator);
430 allocator.destroy(scope_zir_module);
431 },
432 .block => unreachable,
433 .gen_zir => unreachable,
434 .decl => unreachable,
435 }
436 }
437
438 fn name_hash_hash(x: NameHash) u32 {
439 return @truncate(u32, @bitCast(u128, x));
440 }
441
442 fn name_hash_eql(a: NameHash, b: NameHash) bool {
443 return @bitCast(u128, a) == @bitCast(u128, b);
444 }
445
328446 pub const Tag = enum {
447 /// .zir source code.
329448 zir_module,
449 /// .zig source code.
450 file,
330451 block,
331452 decl,
453 gen_zir,
454 };
455
456 pub const File = struct {
457 pub const base_tag: Tag = .file;
458 base: Scope = Scope{ .tag = base_tag },
459
460 /// Relative to the owning package's root_src_dir.
461 /// Reference to external memory, not owned by File.
462 sub_file_path: []const u8,
463 source: union(enum) {
464 unloaded: void,
465 bytes: [:0]const u8,
466 },
467 contents: union {
468 not_available: void,
469 tree: *ast.Tree,
470 },
471 status: enum {
472 never_loaded,
473 unloaded_success,
474 unloaded_parse_failure,
475 loaded_success,
476 },
477
478 /// Direct children of the file.
479 decls: ArrayListUnmanaged(*Decl),
480
481 pub fn unload(self: *File, allocator: *Allocator) void {
482 switch (self.status) {
483 .never_loaded,
484 .unloaded_parse_failure,
485 .unloaded_success,
486 => {},
487
488 .loaded_success => {
489 self.contents.tree.deinit();
490 self.status = .unloaded_success;
491 },
492 }
493 switch (self.source) {
494 .bytes => |bytes| {
495 allocator.free(bytes);
496 self.source = .{ .unloaded = {} };
497 },
498 .unloaded => {},
499 }
500 }
501
502 pub fn deinit(self: *File, allocator: *Allocator) void {
503 self.decls.deinit(allocator);
504 self.unload(allocator);
505 self.* = undefined;
506 }
507
508 pub fn removeDecl(self: *File, child: *Decl) void {
509 for (self.decls.items) |item, i| {
510 if (item == child) {
511 _ = self.decls.swapRemove(i);
512 return;
513 }
514 }
515 }
516
517 pub fn dumpSrc(self: *File, src: usize) void {
518 const loc = std.zig.findLineColumn(self.source.bytes, src);
519 std.debug.warn("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
520 }
521
522 pub fn getSource(self: *File, module: *Module) ![:0]const u8 {
523 switch (self.source) {
524 .unloaded => {
525 const source = try module.root_pkg.root_src_dir.readFileAllocOptions(
526 module.allocator,
527 self.sub_file_path,
528 std.math.maxInt(u32),
529 1,
530 0,
531 );
532 self.source = .{ .bytes = source };
533 return source;
534 },
535 .bytes => |bytes| return bytes,
536 }
537 }
538
539 pub fn fullyQualifiedNameHash(self: *File, name: []const u8) NameHash {
540 // We don't have struct scopes yet so this is currently just a simple name hash.
541 return std.zig.hashSrc(name);
542 }
332543 };
333544
334545 pub const ZIRModule = struct {
......@@ -355,6 +566,11 @@ pub const Scope = struct {
355566 loaded_success,
356567 },
357568
569 /// Even though .zir files only have 1 module, this set is still needed
570 /// because of anonymous Decls, which can exist in the global set, but
571 /// not this one.
572 decls: ArrayListUnmanaged(*Decl),
573
358574 pub fn unload(self: *ZIRModule, allocator: *Allocator) void {
359575 switch (self.status) {
360576 .never_loaded,
......@@ -366,11 +582,13 @@ pub const Scope = struct {
366582 .loaded_success => {
367583 self.contents.module.deinit(allocator);
368584 allocator.destroy(self.contents.module);
585 self.contents = .{ .not_available = {} };
369586 self.status = .unloaded_success;
370587 },
371588 .loaded_sema_failure => {
372589 self.contents.module.deinit(allocator);
373590 allocator.destroy(self.contents.module);
591 self.contents = .{ .not_available = {} };
374592 self.status = .unloaded_sema_failure;
375593 },
376594 }
......@@ -384,14 +602,46 @@ pub const Scope = struct {
384602 }
385603
386604 pub fn deinit(self: *ZIRModule, allocator: *Allocator) void {
605 self.decls.deinit(allocator);
387606 self.unload(allocator);
388607 self.* = undefined;
389608 }
390609
610 pub fn removeDecl(self: *ZIRModule, child: *Decl) void {
611 for (self.decls.items) |item, i| {
612 if (item == child) {
613 _ = self.decls.swapRemove(i);
614 return;
615 }
616 }
617 }
618
391619 pub fn dumpSrc(self: *ZIRModule, src: usize) void {
392620 const loc = std.zig.findLineColumn(self.source.bytes, src);
393621 std.debug.warn("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
394622 }
623
624 pub fn getSource(self: *ZIRModule, module: *Module) ![:0]const u8 {
625 switch (self.source) {
626 .unloaded => {
627 const source = try module.root_pkg.root_src_dir.readFileAllocOptions(
628 module.allocator,
629 self.sub_file_path,
630 std.math.maxInt(u32),
631 1,
632 0,
633 );
634 self.source = .{ .bytes = source };
635 return source;
636 },
637 .bytes => |bytes| return bytes,
638 }
639 }
640
641 pub fn fullyQualifiedNameHash(self: *ZIRModule, name: []const u8) NameHash {
642 // ZIR modules only have 1 file with all decls global in the same namespace.
643 return std.zig.hashSrc(name);
644 }
395645 };
396646
397647 /// This is a temporary structure, references to it are valid only
......@@ -399,7 +649,7 @@ pub const Scope = struct {
399649 pub const Block = struct {
400650 pub const base_tag: Tag = .block;
401651 base: Scope = Scope{ .tag = base_tag },
402 func: *Fn,
652 func: ?*Fn,
403653 decl: *Decl,
404654 instructions: ArrayListUnmanaged(*Inst),
405655 /// Points to the arena allocator of DeclAnalysis
......@@ -414,6 +664,16 @@ pub const Scope = struct {
414664 decl: *Decl,
415665 arena: std.heap.ArenaAllocator,
416666 };
667
668 /// This is a temporary structure, references to it are valid only
669 /// during semantic analysis of the decl.
670 pub const GenZIR = struct {
671 pub const base_tag: Tag = .gen_zir;
672 base: Scope = Scope{ .tag = base_tag },
673 decl: *Decl,
674 arena: std.heap.ArenaAllocator,
675 instructions: std.ArrayList(*zir.Inst),
676 };
417677};
418678
419679pub const Body = struct {
......@@ -463,19 +723,10 @@ pub const InitOptions = struct {
463723 link_mode: ?std.builtin.LinkMode = null,
464724 object_format: ?std.builtin.ObjectFormat = null,
465725 optimize_mode: std.builtin.Mode = .Debug,
726 keep_source_files_loaded: bool = false,
466727};
467728
468729pub 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
479730 const bin_file_dir = options.bin_file_dir orelse std.fs.cwd();
480731 var bin_file = try link.openBinFilePath(gpa, bin_file_dir, options.bin_file_path, .{
481732 .target = options.target,
......@@ -485,6 +736,32 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
485736 });
486737 errdefer bin_file.deinit();
487738
739 const root_scope = blk: {
740 if (mem.endsWith(u8, options.root_pkg.root_src_path, ".zig")) {
741 const root_scope = try gpa.create(Scope.File);
742 root_scope.* = .{
743 .sub_file_path = options.root_pkg.root_src_path,
744 .source = .{ .unloaded = {} },
745 .contents = .{ .not_available = {} },
746 .status = .never_loaded,
747 .decls = .{},
748 };
749 break :blk &root_scope.base;
750 } else if (mem.endsWith(u8, options.root_pkg.root_src_path, ".zir")) {
751 const root_scope = try gpa.create(Scope.ZIRModule);
752 root_scope.* = .{
753 .sub_file_path = options.root_pkg.root_src_path,
754 .source = .{ .unloaded = {} },
755 .contents = .{ .not_available = {} },
756 .status = .never_loaded,
757 .decls = .{},
758 };
759 break :blk &root_scope.base;
760 } else {
761 unreachable;
762 }
763 };
764
488765 return Module{
489766 .allocator = gpa,
490767 .root_pkg = options.root_pkg,
......@@ -493,13 +770,14 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
493770 .bin_file_path = options.bin_file_path,
494771 .bin_file = bin_file,
495772 .optimize_mode = options.optimize_mode,
496 .decl_table = std.AutoHashMap(Decl.Hash, *Decl).init(gpa),
773 .decl_table = DeclTable.init(gpa),
497774 .decl_exports = std.AutoHashMap(*Decl, []*Export).init(gpa),
498775 .export_owners = std.AutoHashMap(*Decl, []*Export).init(gpa),
499776 .failed_decls = std.AutoHashMap(*Decl, *ErrorMsg).init(gpa),
500 .failed_files = std.AutoHashMap(*Scope.ZIRModule, *ErrorMsg).init(gpa),
777 .failed_files = std.AutoHashMap(*Scope, *ErrorMsg).init(gpa),
501778 .failed_exports = std.AutoHashMap(*Export, *ErrorMsg).init(gpa),
502779 .work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa),
780 .keep_source_files_loaded = options.keep_source_files_loaded,
503781 };
504782}
505783
......@@ -551,10 +829,7 @@ pub fn deinit(self: *Module) void {
551829 }
552830 self.export_owners.deinit();
553831 }
554 {
555 self.root_scope.deinit(allocator);
556 allocator.destroy(self.root_scope);
557 }
832 self.root_scope.destroy(allocator);
558833 self.* = undefined;
559834}
560835
......@@ -571,19 +846,31 @@ pub fn target(self: Module) std.Target {
571846
572847/// Detect changes to source files, perform semantic analysis, and update the output files.
573848pub fn update(self: *Module) !void {
849 const tracy = trace(@src());
850 defer tracy.end();
851
574852 self.generation += 1;
575853
576854 // 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 };
855 // Until then we simulate a full cache miss. Source files could have been loaded for any reason;
856 // to force a refresh we unload now.
857 if (self.root_scope.cast(Scope.File)) |zig_file| {
858 zig_file.unload(self.allocator);
859 self.analyzeRootSrcFile(zig_file) catch |err| switch (err) {
860 error.AnalysisFail => {
861 assert(self.totalErrorCount() != 0);
862 },
863 else => |e| return e,
864 };
865 } else if (self.root_scope.cast(Scope.ZIRModule)) |zir_module| {
866 zir_module.unload(self.allocator);
867 self.analyzeRootZIRModule(zir_module) catch |err| switch (err) {
868 error.AnalysisFail => {
869 assert(self.totalErrorCount() != 0);
870 },
871 else => |e| return e,
872 };
873 }
587874
588875 try self.performAllTheWork();
589876
......@@ -596,14 +883,16 @@ pub fn update(self: *Module) !void {
596883 try self.deleteDecl(decl);
597884 }
598885
886 self.link_error_flags = self.bin_file.error_flags;
887
599888 // If there are any errors, we anticipate the source files being loaded
600889 // to report error messages. Otherwise we unload all source files to save memory.
601890 if (self.totalErrorCount() == 0) {
602 self.root_scope.unload(self.allocator);
891 if (!self.keep_source_files_loaded) {
892 self.root_scope.unload(self.allocator);
893 }
894 try self.bin_file.flush();
603895 }
604
605 try self.bin_file.flush();
606 self.link_error_flags = self.bin_file.error_flags;
607896}
608897
609898/// Having the file open for writing is problematic as far as executing the
......@@ -619,10 +908,10 @@ pub fn makeBinFileWritable(self: *Module) !void {
619908}
620909
621910pub fn totalErrorCount(self: *Module) usize {
622 return self.failed_decls.size +
911 const total = self.failed_decls.size +
623912 self.failed_files.size +
624 self.failed_exports.size +
625 @boolToInt(self.link_error_flags.no_entry_point_found);
913 self.failed_exports.size;
914 return if (total == 0) @boolToInt(self.link_error_flags.no_entry_point_found) else total;
626915}
627916
628917pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
......@@ -637,8 +926,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
637926 while (it.next()) |kv| {
638927 const scope = kv.key;
639928 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.*);
929 const source = try scope.getSource(self);
930 try AllErrors.add(&arena, &errors, scope.subFilePath(), source, err_msg.*);
642931 }
643932 }
644933 {
......@@ -646,8 +935,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
646935 while (it.next()) |kv| {
647936 const decl = kv.key;
648937 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.*);
938 const source = try decl.scope.getSource(self);
939 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
651940 }
652941 }
653942 {
......@@ -655,12 +944,12 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
655944 while (it.next()) |kv| {
656945 const decl = kv.key.owner_decl;
657946 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.*);
947 const source = try decl.scope.getSource(self);
948 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
660949 }
661950 }
662951
663 if (self.link_error_flags.no_entry_point_found) {
952 if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) {
664953 try errors.append(.{
665954 .src_path = self.root_pkg.root_src_path,
666955 .line = 0,
......@@ -683,12 +972,14 @@ const InnerError = error{ OutOfMemory, AnalysisFail };
683972pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
684973 while (self.work_queue.readItem()) |work_item| switch (work_item) {
685974 .codegen_decl => |decl| switch (decl.analysis) {
975 .unreferenced => unreachable,
686976 .in_progress => unreachable,
687977 .outdated => unreachable,
688978
689979 .sema_failure,
690980 .codegen_failure,
691981 .dependency_failure,
982 .sema_failure_retryable,
692983 => continue,
693984
694985 .complete, .codegen_failure_retryable => {
......@@ -696,12 +987,10 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
696987 switch (payload.func.analysis) {
697988 .queued => self.analyzeFnBody(decl, payload.func) catch |err| switch (err) {
698989 error.AnalysisFail => {
699 if (payload.func.analysis == .queued) {
700 payload.func.analysis = .dependency_failure;
701 }
990 assert(payload.func.analysis != .in_progress);
702991 continue;
703992 },
704 else => |e| return e,
993 error.OutOfMemory => return error.OutOfMemory,
705994 },
706995 .in_progress => unreachable,
707996 .sema_failure, .dependency_failure => continue,
......@@ -720,7 +1009,7 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
7201009 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
7211010 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
7221011 self.allocator,
723 decl.src,
1012 decl.src(),
7241013 "unable to codegen: {}",
7251014 .{@errorName(err)},
7261015 ));
......@@ -729,41 +1018,560 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
7291018 };
7301019 },
7311020 },
732 .re_analyze_decl => |decl| switch (decl.analysis) {
733 .in_progress => unreachable,
1021 .analyze_decl => |decl| {
1022 self.ensureDeclAnalyzed(decl) catch |err| switch (err) {
1023 error.OutOfMemory => return error.OutOfMemory,
1024 error.AnalysisFail => continue,
1025 };
1026 },
1027 };
1028}
7341029
735 .sema_failure,
736 .codegen_failure,
737 .dependency_failure,
738 .complete,
739 .codegen_failure_retryable,
740 => continue,
1030fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
1031 const tracy = trace(@src());
1032 defer tracy.end();
7411033
742 .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;
1034 const subsequent_analysis = switch (decl.analysis) {
1035 .in_progress => unreachable,
1036
1037 .sema_failure,
1038 .sema_failure_retryable,
1039 .codegen_failure,
1040 .dependency_failure,
1041 .codegen_failure_retryable,
1042 => return error.AnalysisFail,
1043
1044 .complete, .outdated => blk: {
1045 if (decl.generation == self.generation) {
1046 assert(decl.analysis == .complete);
1047 return;
1048 }
1049 //std.debug.warn("re-analyzing {}\n", .{decl.name});
1050
1051 // The exports this Decl performs will be re-discovered, so we remove them here
1052 // prior to re-analysis.
1053 self.deleteDeclExports(decl);
1054 // Dependencies will be re-discovered, so we remove them here prior to re-analysis.
1055 for (decl.dependencies.items) |dep| {
1056 dep.removeDependant(decl);
1057 if (dep.dependants.items.len == 0 and !dep.deletion_flag) {
1058 // We don't perform a deletion here, because this Decl or another one
1059 // may end up referencing it before the update is complete.
1060 dep.deletion_flag = true;
1061 try self.deletion_set.append(self.allocator, dep);
1062 }
1063 }
1064 decl.dependencies.shrink(self.allocator, 0);
1065
1066 break :blk true;
1067 },
1068
1069 .unreferenced => false,
1070 };
1071
1072 const type_changed = if (self.root_scope.cast(Scope.ZIRModule)) |zir_module|
1073 try self.analyzeZirDecl(decl, zir_module.contents.module.decls[decl.src_index])
1074 else
1075 self.astGenAndAnalyzeDecl(decl) catch |err| switch (err) {
1076 error.OutOfMemory => return error.OutOfMemory,
1077 error.AnalysisFail => return error.AnalysisFail,
1078 else => {
1079 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
1080 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
1081 self.allocator,
1082 decl.src(),
1083 "unable to analyze: {}",
1084 .{@errorName(err)},
1085 ));
1086 decl.analysis = .sema_failure_retryable;
1087 return error.AnalysisFail;
1088 },
1089 };
1090
1091 if (subsequent_analysis) {
1092 // We may need to chase the dependants and re-analyze them.
1093 // However, if the decl is a function, and the type is the same, we do not need to.
1094 if (type_changed or decl.typed_value.most_recent.typed_value.val.tag() != .function) {
1095 for (decl.dependants.items) |dep| {
1096 switch (dep.analysis) {
1097 .unreferenced => unreachable,
1098 .in_progress => unreachable,
1099 .outdated => continue, // already queued for update
1100
1101 .dependency_failure,
1102 .sema_failure,
1103 .sema_failure_retryable,
1104 .codegen_failure,
1105 .codegen_failure_retryable,
1106 .complete,
1107 => if (dep.generation != self.generation) {
1108 try self.markOutdatedDecl(dep);
7551109 },
1110 }
1111 }
1112 }
1113 }
1114}
1115
1116fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1117 const tracy = trace(@src());
1118 defer tracy.end();
1119
1120 const file_scope = decl.scope.cast(Scope.File).?;
1121 const tree = try self.getAstTree(file_scope);
1122 const ast_node = tree.root_node.decls()[decl.src_index];
1123 switch (ast_node.id) {
1124 .FnProto => {
1125 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", ast_node);
1126
1127 decl.analysis = .in_progress;
1128
1129 // This arena allocator's memory is discarded at the end of this function. It is used
1130 // to determine the type of the function, and hence the type of the decl, which is needed
1131 // to complete the Decl analysis.
1132 var fn_type_scope: Scope.GenZIR = .{
1133 .decl = decl,
1134 .arena = std.heap.ArenaAllocator.init(self.allocator),
1135 .instructions = std.ArrayList(*zir.Inst).init(self.allocator),
1136 };
1137 defer fn_type_scope.arena.deinit();
1138 defer fn_type_scope.instructions.deinit();
1139
1140 const body_node = fn_proto.body_node orelse
1141 return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
1142 if (fn_proto.params_len != 0) {
1143 return self.failTok(
1144 &fn_type_scope.base,
1145 fn_proto.params()[0].name_token.?,
1146 "TODO implement function parameters",
1147 .{},
1148 );
1149 }
1150 if (fn_proto.lib_name) |lib_name| {
1151 return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{});
1152 }
1153 if (fn_proto.align_expr) |align_expr| {
1154 return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{});
1155 }
1156 if (fn_proto.section_expr) |sect_expr| {
1157 return self.failNode(&fn_type_scope.base, sect_expr, "TODO implement function section expression", .{});
1158 }
1159 if (fn_proto.callconv_expr) |callconv_expr| {
1160 return self.failNode(
1161 &fn_type_scope.base,
1162 callconv_expr,
1163 "TODO implement function calling convention expression",
1164 .{},
1165 );
1166 }
1167 const return_type_expr = switch (fn_proto.return_type) {
1168 .Explicit => |node| node,
1169 .InferErrorSet => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement inferred error sets", .{}),
1170 .Invalid => |tok| return self.failTok(&fn_type_scope.base, tok, "unable to parse return type", .{}),
1171 };
1172
1173 const return_type_inst = try self.astGenExpr(&fn_type_scope.base, return_type_expr);
1174 const fn_src = tree.token_locs[fn_proto.fn_token].start;
1175 const fn_type_inst = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.FnType, .{
1176 .return_type = return_type_inst,
1177 .param_types = &[0]*zir.Inst{},
1178 }, .{});
1179 _ = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.Return, .{ .operand = fn_type_inst }, .{});
1180
1181 // We need the memory for the Type to go into the arena for the Decl
1182 var decl_arena = std.heap.ArenaAllocator.init(self.allocator);
1183 errdefer decl_arena.deinit();
1184 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
1185
1186 var block_scope: Scope.Block = .{
1187 .func = null,
1188 .decl = decl,
1189 .instructions = .{},
1190 .arena = &decl_arena.allocator,
1191 };
1192 defer block_scope.instructions.deinit(self.allocator);
1193
1194 const fn_type = try self.analyzeBodyValueAsType(&block_scope, .{
1195 .instructions = fn_type_scope.instructions.items,
1196 });
1197 const new_func = try decl_arena.allocator.create(Fn);
1198 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
1199
1200 const fn_zir = blk: {
1201 // This scope's arena memory is discarded after the ZIR generation
1202 // pass completes, and semantic analysis of it completes.
1203 var gen_scope: Scope.GenZIR = .{
1204 .decl = decl,
1205 .arena = std.heap.ArenaAllocator.init(self.allocator),
1206 .instructions = std.ArrayList(*zir.Inst).init(self.allocator),
7561207 };
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,
1208 errdefer gen_scope.arena.deinit();
1209 defer gen_scope.instructions.deinit();
1210
1211 const body_block = body_node.cast(ast.Node.Block).?;
1212
1213 try self.astGenBlock(&gen_scope.base, body_block);
1214
1215 const fn_zir = try gen_scope.arena.allocator.create(Fn.ZIR);
1216 fn_zir.* = .{
1217 .body = .{
1218 .instructions = try gen_scope.arena.allocator.dupe(*zir.Inst, gen_scope.instructions.items),
1219 },
1220 .arena = gen_scope.arena.state,
7631221 };
764 },
1222 break :blk fn_zir;
1223 };
1224
1225 new_func.* = .{
1226 .analysis = .{ .queued = fn_zir },
1227 .owner_decl = decl,
1228 };
1229 fn_payload.* = .{ .func = new_func };
1230
1231 var prev_type_has_bits = false;
1232 var type_changed = true;
1233
1234 if (decl.typedValueManaged()) |tvm| {
1235 prev_type_has_bits = tvm.typed_value.ty.hasCodeGenBits();
1236 type_changed = !tvm.typed_value.ty.eql(fn_type);
1237
1238 tvm.deinit(self.allocator);
1239 }
1240
1241 decl_arena_state.* = decl_arena.state;
1242 decl.typed_value = .{
1243 .most_recent = .{
1244 .typed_value = .{
1245 .ty = fn_type,
1246 .val = Value.initPayload(&fn_payload.base),
1247 },
1248 .arena = decl_arena_state,
1249 },
1250 };
1251 decl.analysis = .complete;
1252 decl.generation = self.generation;
1253
1254 if (fn_type.hasCodeGenBits()) {
1255 // We don't fully codegen the decl until later, but we do need to reserve a global
1256 // offset table index for it. This allows us to codegen decls out of dependency order,
1257 // increasing how many computations can be done in parallel.
1258 try self.bin_file.allocateDeclIndexes(decl);
1259 try self.work_queue.writeItem(.{ .codegen_decl = decl });
1260 } else if (prev_type_has_bits) {
1261 self.bin_file.freeDecl(decl);
1262 }
1263
1264 if (fn_proto.extern_export_inline_token) |maybe_export_token| {
1265 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1266 const export_src = tree.token_locs[maybe_export_token].start;
1267 const name_loc = tree.token_locs[fn_proto.name_token.?];
1268 const name = tree.tokenSliceLoc(name_loc);
1269 // The scope needs to have the decl in it.
1270 try self.analyzeExport(&block_scope.base, export_src, name, decl);
1271 }
1272 }
1273 return type_changed;
7651274 },
1275 .VarDecl => @panic("TODO var decl"),
1276 .Comptime => @panic("TODO comptime decl"),
1277 .Use => @panic("TODO usingnamespace decl"),
1278 else => unreachable,
1279 }
1280}
1281
1282fn analyzeBodyValueAsType(self: *Module, block_scope: *Scope.Block, body: zir.Module.Body) !Type {
1283 try self.analyzeBody(&block_scope.base, body);
1284 for (block_scope.instructions.items) |inst| {
1285 if (inst.cast(Inst.Ret)) |ret| {
1286 const val = try self.resolveConstValue(&block_scope.base, ret.args.operand);
1287 return val.toType();
1288 } else {
1289 return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{});
1290 }
1291 }
1292 unreachable;
1293}
1294
1295fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir.Inst {
1296 switch (ast_node.id) {
1297 .Identifier => return self.astGenIdent(scope, @fieldParentPtr(ast.Node.Identifier, "base", ast_node)),
1298 .Asm => return self.astGenAsm(scope, @fieldParentPtr(ast.Node.Asm, "base", ast_node)),
1299 .StringLiteral => return self.astGenStringLiteral(scope, @fieldParentPtr(ast.Node.StringLiteral, "base", ast_node)),
1300 .IntegerLiteral => return self.astGenIntegerLiteral(scope, @fieldParentPtr(ast.Node.IntegerLiteral, "base", ast_node)),
1301 .BuiltinCall => return self.astGenBuiltinCall(scope, @fieldParentPtr(ast.Node.BuiltinCall, "base", ast_node)),
1302 .Call => return self.astGenCall(scope, @fieldParentPtr(ast.Node.Call, "base", ast_node)),
1303 .Unreachable => return self.astGenUnreachable(scope, @fieldParentPtr(ast.Node.Unreachable, "base", ast_node)),
1304 .ControlFlowExpression => return self.astGenControlFlowExpression(scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)),
1305 else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}),
1306 }
1307}
1308
1309fn astGenControlFlowExpression(
1310 self: *Module,
1311 scope: *Scope,
1312 cfe: *ast.Node.ControlFlowExpression,
1313) InnerError!*zir.Inst {
1314 switch (cfe.kind) {
1315 .Break => return self.failNode(scope, &cfe.base, "TODO implement astGenExpr for Break", .{}),
1316 .Continue => return self.failNode(scope, &cfe.base, "TODO implement astGenExpr for Continue", .{}),
1317 .Return => {},
1318 }
1319 const tree = scope.tree();
1320 const src = tree.token_locs[cfe.ltoken].start;
1321 if (cfe.rhs) |rhs_node| {
1322 const operand = try self.astGenExpr(scope, rhs_node);
1323 return self.addZIRInst(scope, src, zir.Inst.Return, .{ .operand = operand }, .{});
1324 } else {
1325 return self.addZIRInst(scope, src, zir.Inst.ReturnVoid, .{}, .{});
1326 }
1327}
1328
1329fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst {
1330 const tree = scope.tree();
1331 const ident_name = tree.tokenSlice(ident.token);
1332 if (mem.eql(u8, ident_name, "_")) {
1333 return self.failNode(scope, &ident.base, "TODO implement '_' identifier", .{});
1334 }
1335
1336 if (getSimplePrimitiveValue(ident_name)) |typed_value| {
1337 const src = tree.token_locs[ident.token].start;
1338 return self.addZIRInstConst(scope, src, typed_value);
1339 }
1340
1341 if (ident_name.len >= 2) integer: {
1342 const first_c = ident_name[0];
1343 if (first_c == 'i' or first_c == 'u') {
1344 const is_signed = first_c == 'i';
1345 const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) {
1346 error.Overflow => return self.failNode(
1347 scope,
1348 &ident.base,
1349 "primitive integer type '{}' exceeds maximum bit width of 65535",
1350 .{ident_name},
1351 ),
1352 error.InvalidCharacter => break :integer,
1353 };
1354 return self.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{});
1355 }
1356 }
1357
1358 if (self.lookupDeclName(scope, ident_name)) |decl| {
1359 const src = tree.token_locs[ident.token].start;
1360 return try self.addZIRInst(scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});
1361 }
1362
1363 return self.failNode(scope, &ident.base, "TODO implement local variable identifier lookup", .{});
1364}
1365
1366fn astGenStringLiteral(self: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral) InnerError!*zir.Inst {
1367 const tree = scope.tree();
1368 const unparsed_bytes = tree.tokenSlice(str_lit.token);
1369 const arena = scope.arena();
1370
1371 var bad_index: usize = undefined;
1372 const bytes = std.zig.parseStringLiteral(arena, unparsed_bytes, &bad_index) catch |err| switch (err) {
1373 error.InvalidCharacter => {
1374 const bad_byte = unparsed_bytes[bad_index];
1375 const src = tree.token_locs[str_lit.token].start;
1376 return self.fail(scope, src + bad_index, "invalid string literal character: '{c}'\n", .{bad_byte});
1377 },
1378 else => |e| return e,
7661379 };
1380
1381 const src = tree.token_locs[str_lit.token].start;
1382 return self.addZIRInst(scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
1383}
1384
1385fn astGenIntegerLiteral(self: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral) InnerError!*zir.Inst {
1386 const arena = scope.arena();
1387 const tree = scope.tree();
1388 const prefixed_bytes = tree.tokenSlice(int_lit.token);
1389 const base = if (mem.startsWith(u8, prefixed_bytes, "0x"))
1390 16
1391 else if (mem.startsWith(u8, prefixed_bytes, "0o"))
1392 8
1393 else if (mem.startsWith(u8, prefixed_bytes, "0b"))
1394 2
1395 else
1396 @as(u8, 10);
1397
1398 const bytes = if (base == 10)
1399 prefixed_bytes
1400 else
1401 prefixed_bytes[2..];
1402
1403 if (std.fmt.parseInt(u64, bytes, base)) |small_int| {
1404 const int_payload = try arena.create(Value.Payload.Int_u64);
1405 int_payload.* = .{ .int = small_int };
1406 const src = tree.token_locs[int_lit.token].start;
1407 return self.addZIRInstConst(scope, src, .{
1408 .ty = Type.initTag(.comptime_int),
1409 .val = Value.initPayload(&int_payload.base),
1410 });
1411 } else |err| {
1412 return self.failTok(scope, int_lit.token, "TODO implement int literals that don't fit in a u64", .{});
1413 }
1414}
1415
1416fn astGenBlock(self: *Module, scope: *Scope, block_node: *ast.Node.Block) !void {
1417 const tracy = trace(@src());
1418 defer tracy.end();
1419
1420 if (block_node.label) |label| {
1421 return self.failTok(scope, label, "TODO implement labeled blocks", .{});
1422 }
1423 for (block_node.statements()) |statement| {
1424 _ = try self.astGenExpr(scope, statement);
1425 }
1426}
1427
1428fn astGenAsm(self: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst {
1429 if (asm_node.outputs.len != 0) {
1430 return self.failNode(scope, &asm_node.base, "TODO implement asm with an output", .{});
1431 }
1432 const arena = scope.arena();
1433 const tree = scope.tree();
1434
1435 const inputs = try arena.alloc(*zir.Inst, asm_node.inputs.len);
1436 const args = try arena.alloc(*zir.Inst, asm_node.inputs.len);
1437
1438 for (asm_node.inputs) |input, i| {
1439 // TODO semantically analyze constraints
1440 inputs[i] = try self.astGenExpr(scope, input.constraint);
1441 args[i] = try self.astGenExpr(scope, input.expr);
1442 }
1443
1444 const src = tree.token_locs[asm_node.asm_token].start;
1445 const return_type = try self.addZIRInstConst(scope, src, .{
1446 .ty = Type.initTag(.type),
1447 .val = Value.initTag(.void_type),
1448 });
1449 const asm_inst = try self.addZIRInst(scope, src, zir.Inst.Asm, .{
1450 .asm_source = try self.astGenExpr(scope, asm_node.template),
1451 .return_type = return_type,
1452 }, .{
1453 .@"volatile" = asm_node.volatile_token != null,
1454 //.clobbers = TODO handle clobbers
1455 .inputs = inputs,
1456 .args = args,
1457 });
1458 return asm_inst;
1459}
1460
1461fn astGenBuiltinCall(self: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
1462 const tree = scope.tree();
1463 const builtin_name = tree.tokenSlice(call.builtin_token);
1464 const src = tree.token_locs[call.builtin_token].start;
1465
1466 inline for (std.meta.declarations(zir.Inst)) |inst| {
1467 if (inst.data != .Type) continue;
1468 const T = inst.data.Type;
1469 if (!@hasDecl(T, "builtin_name")) continue;
1470 if (std.mem.eql(u8, builtin_name, T.builtin_name)) {
1471 var value: T = undefined;
1472 const positionals = @typeInfo(std.meta.fieldInfo(T, "positionals").field_type).Struct;
1473 if (positionals.fields.len == 0) {
1474 return self.addZIRInst(scope, src, T, value.positionals, value.kw_args);
1475 }
1476 const arg_count: ?usize = if (positionals.fields[0].field_type == []*zir.Inst) null else positionals.fields.len;
1477 if (arg_count) |some| {
1478 if (call.params_len != some) {
1479 return self.failTok(scope, call.builtin_token, "expected {} parameter, found {}", .{ some, call.params_len });
1480 }
1481 const params = call.params();
1482 inline for (positionals.fields) |p, i| {
1483 @field(value.positionals, p.name) = try self.astGenExpr(scope, params[i]);
1484 }
1485 } else {
1486 return self.failTok(scope, call.builtin_token, "TODO var args builtin '{}'", .{builtin_name});
1487 }
1488
1489 return self.addZIRInst(scope, src, T, value.positionals, .{});
1490 }
1491 }
1492 return self.failTok(scope, call.builtin_token, "TODO implement builtin call for '{}'", .{builtin_name});
1493}
1494
1495fn astGenCall(self: *Module, scope: *Scope, call: *ast.Node.Call) InnerError!*zir.Inst {
1496 const tree = scope.tree();
1497
1498 if (call.params_len != 0) {
1499 return self.failNode(scope, &call.base, "TODO implement fn calls with parameters", .{});
1500 }
1501 const lhs = try self.astGenExpr(scope, call.lhs);
1502
1503 const src = tree.token_locs[call.lhs.firstToken()].start;
1504 return self.addZIRInst(scope, src, zir.Inst.Call, .{
1505 .func = lhs,
1506 .args = &[0]*zir.Inst{},
1507 }, .{});
1508}
1509
1510fn astGenUnreachable(self: *Module, scope: *Scope, unreach_node: *ast.Node.Unreachable) InnerError!*zir.Inst {
1511 const tree = scope.tree();
1512 const src = tree.token_locs[unreach_node.token].start;
1513 return self.addZIRInst(scope, src, zir.Inst.Unreachable, .{}, .{});
1514}
1515
1516fn getSimplePrimitiveValue(name: []const u8) ?TypedValue {
1517 const simple_types = std.ComptimeStringMap(Value.Tag, .{
1518 .{ "u8", .u8_type },
1519 .{ "i8", .i8_type },
1520 .{ "isize", .isize_type },
1521 .{ "usize", .usize_type },
1522 .{ "c_short", .c_short_type },
1523 .{ "c_ushort", .c_ushort_type },
1524 .{ "c_int", .c_int_type },
1525 .{ "c_uint", .c_uint_type },
1526 .{ "c_long", .c_long_type },
1527 .{ "c_ulong", .c_ulong_type },
1528 .{ "c_longlong", .c_longlong_type },
1529 .{ "c_ulonglong", .c_ulonglong_type },
1530 .{ "c_longdouble", .c_longdouble_type },
1531 .{ "f16", .f16_type },
1532 .{ "f32", .f32_type },
1533 .{ "f64", .f64_type },
1534 .{ "f128", .f128_type },
1535 .{ "c_void", .c_void_type },
1536 .{ "bool", .bool_type },
1537 .{ "void", .void_type },
1538 .{ "type", .type_type },
1539 .{ "anyerror", .anyerror_type },
1540 .{ "comptime_int", .comptime_int_type },
1541 .{ "comptime_float", .comptime_float_type },
1542 .{ "noreturn", .noreturn_type },
1543 });
1544 if (simple_types.get(name)) |tag| {
1545 return TypedValue{
1546 .ty = Type.initTag(.type),
1547 .val = Value.initTag(tag),
1548 };
1549 }
1550 if (mem.eql(u8, name, "null")) {
1551 return TypedValue{
1552 .ty = Type.initTag(.@"null"),
1553 .val = Value.initTag(.null_value),
1554 };
1555 }
1556 if (mem.eql(u8, name, "undefined")) {
1557 return TypedValue{
1558 .ty = Type.initTag(.@"undefined"),
1559 .val = Value.initTag(.undef),
1560 };
1561 }
1562 if (mem.eql(u8, name, "true")) {
1563 return TypedValue{
1564 .ty = Type.initTag(.bool),
1565 .val = Value.initTag(.bool_true),
1566 };
1567 }
1568 if (mem.eql(u8, name, "false")) {
1569 return TypedValue{
1570 .ty = Type.initTag(.bool),
1571 .val = Value.initTag(.bool_false),
1572 };
1573 }
1574 return null;
7671575}
7681576
7691577fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {
......@@ -775,28 +1583,11 @@ fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void
7751583 } else {
7761584 depender.dependencies.appendAssumeCapacity(dependee);
7771585 }
778
779 for (dependee.dependants.items) |item| {
780 if (item == depender) break; // Already in the set.
781 } else {
782 dependee.dependants.appendAssumeCapacity(depender);
783 }
784}
785
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,
1586
1587 for (dependee.dependants.items) |item| {
1588 if (item == depender) break; // Already in the set.
1589 } else {
1590 dependee.dependants.appendAssumeCapacity(depender);
8001591 }
8011592}
8021593
......@@ -805,7 +1596,7 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
8051596 .never_loaded, .unloaded_success => {
8061597 try self.failed_files.ensureCapacity(self.failed_files.size + 1);
8071598
808 const source = try self.getSource(root_scope);
1599 const source = try root_scope.getSource(self);
8091600
8101601 var keep_zir_module = false;
8111602 const zir_module = try self.allocator.create(zir.Module);
......@@ -816,7 +1607,7 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
8161607
8171608 if (zir_module.error_msg) |src_err_msg| {
8181609 self.failed_files.putAssumeCapacityNoClobber(
819 root_scope,
1610 &root_scope.base,
8201611 try ErrorMsg.create(self.allocator, src_err_msg.byte_offset, "{}", .{src_err_msg.msg}),
8211612 );
8221613 root_scope.status = .unloaded_parse_failure;
......@@ -838,90 +1629,189 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
8381629 }
8391630}
8401631
841fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void {
1632fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {
1633 const tracy = trace(@src());
1634 defer tracy.end();
1635
8421636 switch (root_scope.status) {
843 .never_loaded => {
844 const src_module = try self.getSrcModule(root_scope);
1637 .never_loaded, .unloaded_success => {
1638 try self.failed_files.ensureCapacity(self.failed_files.size + 1);
8451639
846 // Here we ensure enough queue capacity to store all the decls, so that later we can use
847 // appendAssumeCapacity.
848 try self.work_queue.ensureUnusedCapacity(src_module.decls.len);
1640 const source = try root_scope.getSource(self);
8491641
850 for (src_module.decls) |decl| {
851 if (decl.cast(zir.Inst.Export)) |export_inst| {
852 _ = try self.resolveDecl(&root_scope.base, &export_inst.base);
853 }
1642 var keep_tree = false;
1643 const tree = try std.zig.parse(self.allocator, source);
1644 defer if (!keep_tree) tree.deinit();
1645
1646 if (tree.errors.len != 0) {
1647 const parse_err = tree.errors[0];
1648
1649 var msg = std.ArrayList(u8).init(self.allocator);
1650 defer msg.deinit();
1651
1652 try parse_err.render(tree.token_ids, msg.outStream());
1653 const err_msg = try self.allocator.create(ErrorMsg);
1654 err_msg.* = .{
1655 .msg = msg.toOwnedSlice(),
1656 .byte_offset = tree.token_locs[parse_err.loc()].start,
1657 };
1658
1659 self.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);
1660 root_scope.status = .unloaded_parse_failure;
1661 return error.AnalysisFail;
8541662 }
1663
1664 root_scope.status = .loaded_success;
1665 root_scope.contents = .{ .tree = tree };
1666 keep_tree = true;
1667
1668 return tree;
8551669 },
8561670
857 .unloaded_parse_failure,
858 .unloaded_sema_failure,
859 .unloaded_success,
860 .loaded_sema_failure,
861 .loaded_success,
862 => {
863 const src_module = try self.getSrcModule(root_scope);
864
865 var exports_to_resolve = std.ArrayList(*zir.Inst).init(self.allocator);
866 defer exports_to_resolve.deinit();
867
868 // Keep track of the decls that we expect to see in this file so that
869 // we know which ones have been deleted.
870 var deleted_decls = std.AutoHashMap(*Decl, void).init(self.allocator);
871 defer deleted_decls.deinit();
872 try deleted_decls.ensureCapacity(self.decl_table.size);
873 {
874 var it = self.decl_table.iterator();
875 while (it.next()) |kv| {
876 deleted_decls.putAssumeCapacityNoClobber(kv.value, {});
1671 .unloaded_parse_failure => return error.AnalysisFail,
1672
1673 .loaded_success => return root_scope.contents.tree,
1674 }
1675}
1676
1677fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1678 // We may be analyzing it for the first time, or this may be
1679 // an incremental update. This code handles both cases.
1680 const tree = try self.getAstTree(root_scope);
1681 const decls = tree.root_node.decls();
1682
1683 try self.work_queue.ensureUnusedCapacity(decls.len);
1684 try root_scope.decls.ensureCapacity(self.allocator, decls.len);
1685
1686 // Keep track of the decls that we expect to see in this file so that
1687 // we know which ones have been deleted.
1688 var deleted_decls = std.AutoHashMap(*Decl, void).init(self.allocator);
1689 defer deleted_decls.deinit();
1690 try deleted_decls.ensureCapacity(root_scope.decls.items.len);
1691 for (root_scope.decls.items) |file_decl| {
1692 deleted_decls.putAssumeCapacityNoClobber(file_decl, {});
1693 }
1694
1695 for (decls) |src_decl, decl_i| {
1696 if (src_decl.cast(ast.Node.FnProto)) |fn_proto| {
1697 // We will create a Decl for it regardless of analysis status.
1698 const name_tok = fn_proto.name_token orelse
1699 @panic("TODO handle missing function name in the parser");
1700 const name_loc = tree.token_locs[name_tok];
1701 const name = tree.tokenSliceLoc(name_loc);
1702 const name_hash = root_scope.fullyQualifiedNameHash(name);
1703 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1704 if (self.decl_table.get(name_hash)) |kv| {
1705 const decl = kv.value;
1706 // Update the AST Node index of the decl, even if its contents are unchanged, it may
1707 // have been re-ordered.
1708 decl.src_index = decl_i;
1709 deleted_decls.removeAssertDiscard(decl);
1710 if (!srcHashEql(decl.contents_hash, contents_hash)) {
1711 try self.markOutdatedDecl(decl);
1712 decl.contents_hash = contents_hash;
8771713 }
878 }
879
880 for (src_module.decls) |src_decl| {
881 const name_hash = Decl.hashSimpleName(src_decl.name);
882 if (self.decl_table.get(name_hash)) |kv| {
883 const decl = kv.value;
884 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 });
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 });
889 try self.markOutdatedDecl(decl);
890 decl.contents_hash = new_contents_hash;
1714 } else {
1715 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
1716 root_scope.decls.appendAssumeCapacity(new_decl);
1717 if (fn_proto.extern_export_inline_token) |maybe_export_token| {
1718 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1719 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
8911720 }
892 } else if (src_decl.cast(zir.Inst.Export)) |export_inst| {
893 try exports_to_resolve.append(&export_inst.base);
8941721 }
8951722 }
896 {
897 // Handle explicitly deleted decls from the source code. Not to be confused
898 // with when we delete decls because they are no longer referenced.
899 var it = deleted_decls.iterator();
900 while (it.next()) |kv| {
901 //std.debug.warn("noticed '{}' deleted from source\n", .{kv.key.name});
902 try self.deleteDecl(kv.key);
903 }
1723 }
1724 // TODO also look for global variable declarations
1725 // TODO also look for comptime blocks and exported globals
1726 }
1727 {
1728 // Handle explicitly deleted decls from the source code. Not to be confused
1729 // with when we delete decls because they are no longer referenced.
1730 var it = deleted_decls.iterator();
1731 while (it.next()) |kv| {
1732 //std.debug.warn("noticed '{}' deleted from source\n", .{kv.key.name});
1733 try self.deleteDecl(kv.key);
1734 }
1735 }
1736}
1737
1738fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
1739 // We may be analyzing it for the first time, or this may be
1740 // an incremental update. This code handles both cases.
1741 const src_module = try self.getSrcModule(root_scope);
1742
1743 try self.work_queue.ensureUnusedCapacity(src_module.decls.len);
1744 try root_scope.decls.ensureCapacity(self.allocator, src_module.decls.len);
1745
1746 var exports_to_resolve = std.ArrayList(*zir.Decl).init(self.allocator);
1747 defer exports_to_resolve.deinit();
1748
1749 // Keep track of the decls that we expect to see in this file so that
1750 // we know which ones have been deleted.
1751 var deleted_decls = std.AutoHashMap(*Decl, void).init(self.allocator);
1752 defer deleted_decls.deinit();
1753 try deleted_decls.ensureCapacity(self.decl_table.size);
1754 {
1755 var it = self.decl_table.iterator();
1756 while (it.next()) |kv| {
1757 deleted_decls.putAssumeCapacityNoClobber(kv.value, {});
1758 }
1759 }
1760
1761 for (src_module.decls) |src_decl, decl_i| {
1762 const name_hash = root_scope.fullyQualifiedNameHash(src_decl.name);
1763 if (self.decl_table.get(name_hash)) |kv| {
1764 const decl = kv.value;
1765 deleted_decls.removeAssertDiscard(decl);
1766 //std.debug.warn("'{}' contents: '{}'\n", .{ src_decl.name, src_decl.contents });
1767 if (!srcHashEql(src_decl.contents_hash, decl.contents_hash)) {
1768 try self.markOutdatedDecl(decl);
1769 decl.contents_hash = src_decl.contents_hash;
9041770 }
905 for (exports_to_resolve.items) |export_inst| {
906 _ = try self.resolveDecl(&root_scope.base, export_inst);
1771 } else {
1772 const new_decl = try self.createNewDecl(
1773 &root_scope.base,
1774 src_decl.name,
1775 decl_i,
1776 name_hash,
1777 src_decl.contents_hash,
1778 );
1779 root_scope.decls.appendAssumeCapacity(new_decl);
1780 if (src_decl.inst.cast(zir.Inst.Export)) |export_inst| {
1781 try exports_to_resolve.append(src_decl);
9071782 }
908 },
1783 }
1784 }
1785 for (exports_to_resolve.items) |export_decl| {
1786 _ = try self.resolveZirDecl(&root_scope.base, export_decl);
1787 }
1788 {
1789 // Handle explicitly deleted decls from the source code. Not to be confused
1790 // with when we delete decls because they are no longer referenced.
1791 var it = deleted_decls.iterator();
1792 while (it.next()) |kv| {
1793 //std.debug.warn("noticed '{}' deleted from source\n", .{kv.key.name});
1794 try self.deleteDecl(kv.key);
1795 }
9091796 }
9101797}
9111798
9121799fn deleteDecl(self: *Module, decl: *Decl) !void {
9131800 try self.deletion_set.ensureCapacity(self.allocator, self.deletion_set.items.len + decl.dependencies.items.len);
9141801
1802 // Remove from the namespace it resides in. In the case of an anonymous Decl it will
1803 // not be present in the set, and this does nothing.
1804 decl.scope.removeDecl(decl);
1805
9151806 //std.debug.warn("deleting decl '{}'\n", .{decl.name});
9161807 const name_hash = decl.fullyQualifiedNameHash();
9171808 self.decl_table.removeAssertDiscard(name_hash);
9181809 // Remove itself from its dependencies, because we are about to destroy the decl pointer.
9191810 for (decl.dependencies.items) |dep| {
9201811 dep.removeDependant(decl);
921 if (dep.dependants.items.len == 0) {
1812 if (dep.dependants.items.len == 0 and !dep.deletion_flag) {
9221813 // We don't recursively perform a deletion here, because during the update,
9231814 // another reference to it may turn up.
924 assert(!dep.deletion_flag);
9251815 dep.deletion_flag = true;
9261816 self.deletion_set.appendAssumeCapacity(dep);
9271817 }
......@@ -974,83 +1864,89 @@ fn deleteDeclExports(self: *Module, decl: *Decl) void {
9741864}
9751865
9761866fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {
1867 const tracy = trace(@src());
1868 defer tracy.end();
1869
9771870 // Use the Decl's arena for function memory.
9781871 var arena = decl.typed_value.most_recent.arena.?.promote(self.allocator);
9791872 defer decl.typed_value.most_recent.arena.?.* = arena.state;
980 var analysis: Fn.Analysis = .{
981 .inner_block = .{
982 .func = func,
983 .decl = decl,
984 .instructions = .{},
985 .arena = &arena.allocator,
986 },
987 .needed_inst_capacity = 0,
988 .inst_table = std.AutoHashMap(*zir.Inst, *Inst).init(self.allocator),
1873 var inner_block: Scope.Block = .{
1874 .func = func,
1875 .decl = decl,
1876 .instructions = .{},
1877 .arena = &arena.allocator,
9891878 };
990 defer analysis.inner_block.instructions.deinit(self.allocator);
991 defer analysis.inst_table.deinit();
1879 defer inner_block.instructions.deinit(self.allocator);
9921880
993 const fn_inst = func.analysis.queued;
994 func.analysis = .{ .in_progress = &analysis };
1881 const fn_zir = func.analysis.queued;
1882 defer fn_zir.arena.promote(self.allocator).deinit();
1883 func.analysis = .{ .in_progress = {} };
1884 //std.debug.warn("set {} to in_progress\n", .{decl.name});
9951885
996 try self.analyzeBody(&analysis.inner_block.base, fn_inst.positionals.body);
1886 try self.analyzeBody(&inner_block.base, fn_zir.body);
9971887
998 func.analysis = .{
999 .success = .{
1000 .instructions = try arena.allocator.dupe(*Inst, analysis.inner_block.instructions.items),
1001 },
1002 };
1888 const instructions = try arena.allocator.dupe(*Inst, inner_block.instructions.items);
1889 func.analysis = .{ .success = .{ .instructions = instructions } };
1890 //std.debug.warn("set {} to success\n", .{decl.name});
10031891}
10041892
1005fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!void {
1006 switch (decl.analysis) {
1007 .in_progress => unreachable,
1008 .dependency_failure,
1009 .sema_failure,
1010 .codegen_failure,
1011 .codegen_failure_retryable,
1012 .complete,
1013 => return,
1014
1015 .outdated => {}, // Decl re-analysis
1893fn markOutdatedDecl(self: *Module, decl: *Decl) !void {
1894 //std.debug.warn("mark {} outdated\n", .{decl.name});
1895 try self.work_queue.writeItem(.{ .analyze_decl = decl });
1896 if (self.failed_decls.remove(decl)) |entry| {
1897 entry.value.destroy(self.allocator);
10161898 }
1017 //std.debug.warn("re-analyzing {}\n", .{decl.name});
1018 decl.src = old_inst.src;
1899 decl.analysis = .outdated;
1900}
10191901
1020 // The exports this Decl performs will be re-discovered, so we remove them here
1021 // prior to re-analysis.
1022 self.deleteDeclExports(decl);
1023 // Dependencies will be re-discovered, so we remove them here prior to re-analysis.
1024 for (decl.dependencies.items) |dep| {
1025 dep.removeDependant(decl);
1026 if (dep.dependants.items.len == 0) {
1027 // We don't perform a deletion here, because this Decl or another one
1028 // may end up referencing it before the update is complete.
1029 assert(!dep.deletion_flag);
1030 dep.deletion_flag = true;
1031 try self.deletion_set.append(self.allocator, dep);
1032 }
1033 }
1034 decl.dependencies.shrink(self.allocator, 0);
1902fn allocateNewDecl(
1903 self: *Module,
1904 scope: *Scope,
1905 src_index: usize,
1906 contents_hash: std.zig.SrcHash,
1907) !*Decl {
1908 const new_decl = try self.allocator.create(Decl);
1909 new_decl.* = .{
1910 .name = "",
1911 .scope = scope.namespace(),
1912 .src_index = src_index,
1913 .typed_value = .{ .never_succeeded = {} },
1914 .analysis = .unreferenced,
1915 .deletion_flag = false,
1916 .contents_hash = contents_hash,
1917 .link = link.ElfFile.TextBlock.empty,
1918 .generation = 0,
1919 };
1920 return new_decl;
1921}
1922
1923fn createNewDecl(
1924 self: *Module,
1925 scope: *Scope,
1926 decl_name: []const u8,
1927 src_index: usize,
1928 name_hash: Scope.NameHash,
1929 contents_hash: std.zig.SrcHash,
1930) !*Decl {
1931 try self.decl_table.ensureCapacity(self.decl_table.size + 1);
1932 const new_decl = try self.allocateNewDecl(scope, src_index, contents_hash);
1933 errdefer self.allocator.destroy(new_decl);
1934 new_decl.name = try mem.dupeZ(self.allocator, u8, decl_name);
1935 self.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
1936 return new_decl;
1937}
1938
1939fn analyzeZirDecl(self: *Module, decl: *Decl, src_decl: *zir.Decl) InnerError!bool {
10351940 var decl_scope: Scope.DeclAnalysis = .{
10361941 .decl = decl,
10371942 .arena = std.heap.ArenaAllocator.init(self.allocator),
10381943 };
10391944 errdefer decl_scope.arena.deinit();
10401945
1041 const typed_value = self.analyzeInstConst(&decl_scope.base, old_inst) catch |err| switch (err) {
1042 error.OutOfMemory => return error.OutOfMemory,
1043 error.AnalysisFail => {
1044 switch (decl.analysis) {
1045 .in_progress => decl.analysis = .dependency_failure,
1046 else => {},
1047 }
1048 decl.generation = self.generation;
1049 return error.AnalysisFail;
1050 },
1051 };
1946 decl.analysis = .in_progress;
1947
1948 const typed_value = try self.analyzeConstInst(&decl_scope.base, src_decl.inst);
10521949 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);
1053 arena_state.* = decl_scope.arena.state;
10541950
10551951 var prev_type_has_bits = false;
10561952 var type_changed = true;
......@@ -1061,6 +1957,8 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi
10611957
10621958 tvm.deinit(self.allocator);
10631959 }
1960
1961 arena_state.* = decl_scope.arena.state;
10641962 decl.typed_value = .{
10651963 .most_recent = .{
10661964 .typed_value = typed_value,
......@@ -1079,137 +1977,66 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi
10791977 self.bin_file.freeDecl(decl);
10801978 }
10811979
1082 // If the decl is a function, and the type is the same, we do not need
1083 // to chase the dependants.
1084 if (type_changed or typed_value.val.tag() != .function) {
1085 for (decl.dependants.items) |dep| {
1086 switch (dep.analysis) {
1087 .in_progress => unreachable,
1088 .outdated => continue, // already queued for update
1089
1090 .dependency_failure,
1091 .sema_failure,
1092 .codegen_failure,
1093 .codegen_failure_retryable,
1094 .complete,
1095 => if (dep.generation != self.generation) {
1096 try self.markOutdatedDecl(dep);
1097 },
1098 }
1099 }
1100 }
1980 return type_changed;
11011981}
11021982
1103fn markOutdatedDecl(self: *Module, decl: *Decl) !void {
1104 //std.debug.warn("mark {} outdated\n", .{decl.name});
1105 try self.work_queue.writeItem(.{ .re_analyze_decl = decl });
1106 if (self.failed_decls.remove(decl)) |entry| {
1107 entry.value.destroy(self.allocator);
1108 }
1109 decl.analysis = .outdated;
1983fn resolveZirDecl(self: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!*Decl {
1984 const zir_module = self.root_scope.cast(Scope.ZIRModule).?;
1985 const entry = zir_module.contents.module.findDecl(src_decl.name).?;
1986 return self.resolveZirDeclHavingIndex(scope, src_decl, entry.index);
11101987}
11111988
1112fn 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| {
1115 const decl = kv.value;
1116 try self.reAnalyzeDecl(decl, old_inst);
1117 return decl;
1118 } else if (old_inst.cast(zir.Inst.DeclVal)) |decl_val| {
1119 // This is just a named reference to another decl.
1120 return self.analyzeDeclVal(scope, decl_val);
1121 } 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 };
1142
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;
1180 }
1989fn resolveZirDeclHavingIndex(self: *Module, scope: *Scope, src_decl: *zir.Decl, src_index: usize) InnerError!*Decl {
1990 const name_hash = scope.namespace().fullyQualifiedNameHash(src_decl.name);
1991 const decl = self.decl_table.getValue(name_hash).?;
1992 decl.src_index = src_index;
1993 try self.ensureDeclAnalyzed(decl);
1994 return decl;
11811995}
11821996
11831997/// Declares a dependency on the decl.
1184fn resolveCompleteDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl {
1185 const decl = try self.resolveDecl(scope, old_inst);
1998fn resolveCompleteZirDecl(self: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!*Decl {
1999 const decl = try self.resolveZirDecl(scope, src_decl);
11862000 switch (decl.analysis) {
2001 .unreferenced => unreachable,
11872002 .in_progress => unreachable,
11882003 .outdated => unreachable,
11892004
11902005 .dependency_failure,
11912006 .sema_failure,
2007 .sema_failure_retryable,
11922008 .codegen_failure,
11932009 .codegen_failure_retryable,
11942010 => return error.AnalysisFail,
11952011
11962012 .complete => {},
11972013 }
1198 if (scope.decl()) |scope_decl| {
1199 try self.declareDeclDependency(scope_decl, decl);
1200 }
12012014 return decl;
12022015}
12032016
2017/// TODO Look into removing this function. The body is only needed for .zir files, not .zig files.
12042018fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
1205 if (scope.cast(Scope.Block)) |block| {
1206 if (block.func.analysis.in_progress.inst_table.get(old_inst)) |kv| {
1207 return kv.value;
1208 }
1209 }
1210
1211 const decl = try self.resolveCompleteDecl(scope, old_inst);
2019 if (old_inst.analyzed_inst) |inst| return inst;
2020
2021 // If this assert trips, the instruction that was referenced did not get properly
2022 // analyzed before it was referenced.
2023 const zir_module = scope.namespace().cast(Scope.ZIRModule).?;
2024 const entry = if (old_inst.cast(zir.Inst.DeclVal)) |declval| blk: {
2025 const decl_name = declval.positionals.name;
2026 const entry = zir_module.contents.module.findDecl(decl_name) orelse
2027 return self.fail(scope, old_inst.src, "decl '{}' not found", .{decl_name});
2028 break :blk entry;
2029 } else blk: {
2030 // If this assert trips, the instruction that was referenced did not get
2031 // properly analyzed by a previous instruction analysis before it was
2032 // referenced by the current one.
2033 break :blk zir_module.contents.module.findInstDecl(old_inst).?;
2034 };
2035 const decl = try self.resolveCompleteZirDecl(scope, entry.decl);
12122036 const decl_ref = try self.analyzeDeclRef(scope, old_inst.src, decl);
2037 // Note: it would be tempting here to store the result into old_inst.analyzed_inst field,
2038 // but this would prevent the analyzeDeclRef from happening, which is needed to properly
2039 // detect Decl dependencies and dependency failures on updates.
12132040 return self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src);
12142041}
12152042
......@@ -1258,21 +2085,16 @@ fn resolveType(self: *Module, scope: *Scope, old_inst: *zir.Inst) !Type {
12582085 return val.toType();
12592086}
12602087
1261fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) InnerError!void {
1262 try self.decl_exports.ensureCapacity(self.decl_exports.size + 1);
1263 try self.export_owners.ensureCapacity(self.export_owners.size + 1);
1264 const symbol_name = try self.resolveConstString(scope, export_inst.positionals.symbol_name);
1265 const exported_decl = try self.resolveCompleteDecl(scope, export_inst.positionals.value);
2088fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const u8, exported_decl: *Decl) !void {
2089 try self.ensureDeclAnalyzed(exported_decl);
12662090 const typed_value = exported_decl.typed_value.most_recent.typed_value;
12672091 switch (typed_value.ty.zigTypeTag()) {
12682092 .Fn => {},
1269 else => return self.fail(
1270 scope,
1271 export_inst.positionals.value.src,
1272 "unable to export type '{}'",
1273 .{typed_value.ty},
1274 ),
2093 else => return self.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}),
12752094 }
2095 try self.decl_exports.ensureCapacity(self.decl_exports.size + 1);
2096 try self.export_owners.ensureCapacity(self.export_owners.size + 1);
2097
12762098 const new_export = try self.allocator.create(Export);
12772099 errdefer self.allocator.destroy(new_export);
12782100
......@@ -1280,7 +2102,7 @@ fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) In
12802102
12812103 new_export.* = .{
12822104 .options = .{ .name = symbol_name },
1283 .src = export_inst.base.src,
2105 .src = src,
12842106 .link = .{},
12852107 .owner_decl = owner_decl,
12862108 .exported_decl = exported_decl,
......@@ -1311,7 +2133,7 @@ fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) In
13112133 try self.failed_exports.ensureCapacity(self.failed_exports.size + 1);
13122134 self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create(
13132135 self.allocator,
1314 export_inst.base.src,
2136 src,
13152137 "unable to export: {}",
13162138 .{@errorName(err)},
13172139 ));
......@@ -1320,7 +2142,6 @@ fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) In
13202142 };
13212143}
13222144
1323/// TODO should not need the cast on the last parameter at the callsites
13242145fn addNewInstArgs(
13252146 self: *Module,
13262147 block: *Scope.Block,
......@@ -1334,6 +2155,46 @@ fn addNewInstArgs(
13342155 return &inst.base;
13352156}
13362157
2158fn newZIRInst(
2159 allocator: *Allocator,
2160 src: usize,
2161 comptime T: type,
2162 positionals: std.meta.fieldInfo(T, "positionals").field_type,
2163 kw_args: std.meta.fieldInfo(T, "kw_args").field_type,
2164) !*zir.Inst {
2165 const inst = try allocator.create(T);
2166 inst.* = .{
2167 .base = .{
2168 .tag = T.base_tag,
2169 .src = src,
2170 },
2171 .positionals = positionals,
2172 .kw_args = kw_args,
2173 };
2174 return &inst.base;
2175}
2176
2177fn addZIRInst(
2178 self: *Module,
2179 scope: *Scope,
2180 src: usize,
2181 comptime T: type,
2182 positionals: std.meta.fieldInfo(T, "positionals").field_type,
2183 kw_args: std.meta.fieldInfo(T, "kw_args").field_type,
2184) !*zir.Inst {
2185 const gen_zir = scope.cast(Scope.GenZIR).?;
2186 try gen_zir.instructions.ensureCapacity(gen_zir.instructions.items.len + 1);
2187 const inst = try newZIRInst(&gen_zir.arena.allocator, src, T, positionals, kw_args);
2188 gen_zir.instructions.appendAssumeCapacity(inst);
2189 return inst;
2190}
2191
2192/// TODO The existence of this function is a workaround for a bug in stage1.
2193fn addZIRInstConst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*zir.Inst {
2194 const P = std.meta.fieldInfo(zir.Inst.Const, "positionals").field_type;
2195 return self.addZIRInst(scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{});
2196}
2197
13372198fn addNewInst(self: *Module, block: *Scope.Block, src: usize, ty: Type, comptime T: type) !*T {
13382199 const inst = try block.arena.create(T);
13392200 inst.* = .{
......@@ -1361,19 +2222,6 @@ fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue)
13612222 return &const_inst.base;
13622223}
13632224
1364fn constStr(self: *Module, scope: *Scope, src: usize, str: []const u8) !*Inst {
1365 const ty_payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
1366 ty_payload.* = .{ .len = str.len };
1367
1368 const bytes_payload = try scope.arena().create(Value.Payload.Bytes);
1369 bytes_payload.* = .{ .data = str };
1370
1371 return self.constInst(scope, src, .{
1372 .ty = Type.initPayload(&ty_payload.base),
1373 .val = Value.initPayload(&bytes_payload.base),
1374 });
1375}
1376
13772225fn constType(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {
13782226 return self.constInst(scope, src, .{
13792227 .ty = Type.initTag(.type),
......@@ -1388,6 +2236,13 @@ fn constVoid(self: *Module, scope: *Scope, src: usize) !*Inst {
13882236 });
13892237}
13902238
2239fn constNoReturn(self: *Module, scope: *Scope, src: usize) !*Inst {
2240 return self.constInst(scope, src, .{
2241 .ty = Type.initTag(.noreturn),
2242 .val = Value.initTag(.the_one_possible_value),
2243 });
2244}
2245
13912246fn constUndef(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {
13922247 return self.constInst(scope, src, .{
13932248 .ty = ty,
......@@ -1451,7 +2306,7 @@ fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigI
14512306 });
14522307}
14532308
1454fn analyzeInstConst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue {
2309fn analyzeConstInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue {
14552310 const new_inst = try self.analyzeInst(scope, old_inst);
14562311 return TypedValue{
14572312 .ty = new_inst.ty,
......@@ -1459,20 +2314,24 @@ fn analyzeInstConst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerErro
14592314 };
14602315}
14612316
2317fn analyzeInstConst(self: *Module, scope: *Scope, const_inst: *zir.Inst.Const) InnerError!*Inst {
2318 // Move the TypedValue from old memory to new memory. This allows freeing the ZIR instructions
2319 // after analysis.
2320 const typed_value_copy = try const_inst.positionals.typed_value.copy(scope.arena());
2321 return self.constInst(scope, const_inst.base.src, typed_value_copy);
2322}
2323
14622324fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
14632325 switch (old_inst.tag) {
14642326 .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?),
14652327 .call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?),
14662328 .compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?),
2329 .@"const" => return self.analyzeInstConst(scope, old_inst.cast(zir.Inst.Const).?),
14672330 .declref => return self.analyzeInstDeclRef(scope, old_inst.cast(zir.Inst.DeclRef).?),
2331 .declref_str => return self.analyzeInstDeclRefStr(scope, old_inst.cast(zir.Inst.DeclRefStr).?),
14682332 .declval => return self.analyzeInstDeclVal(scope, old_inst.cast(zir.Inst.DeclVal).?),
1469 .str => {
1470 const bytes = old_inst.cast(zir.Inst.Str).?.positionals.bytes;
1471 // The bytes references memory inside the ZIR module, which can get deallocated
1472 // after semantic analysis is complete. We need the memory to be in the Decl's arena.
1473 const arena_bytes = try scope.arena().dupe(u8, bytes);
1474 return self.constStr(scope, old_inst.src, arena_bytes);
1475 },
2333 .declval_in_module => return self.analyzeInstDeclValInModule(scope, old_inst.cast(zir.Inst.DeclValInModule).?),
2334 .str => return self.analyzeInstStr(scope, old_inst.cast(zir.Inst.Str).?),
14762335 .int => {
14772336 const big_int = old_inst.cast(zir.Inst.Int).?.positionals.int;
14782337 return self.constIntBig(scope, old_inst.src, Type.initTag(.comptime_int), big_int);
......@@ -1484,13 +2343,10 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
14842343 .@"asm" => return self.analyzeInstAsm(scope, old_inst.cast(zir.Inst.Asm).?),
14852344 .@"unreachable" => return self.analyzeInstUnreachable(scope, old_inst.cast(zir.Inst.Unreachable).?),
14862345 .@"return" => return self.analyzeInstRet(scope, old_inst.cast(zir.Inst.Return).?),
2346 .returnvoid => return self.analyzeInstRetVoid(scope, old_inst.cast(zir.Inst.ReturnVoid).?),
14872347 .@"fn" => return self.analyzeInstFn(scope, old_inst.cast(zir.Inst.Fn).?),
1488 .@"export" => {
1489 try self.analyzeExport(scope, old_inst.cast(zir.Inst.Export).?);
1490 return self.constVoid(scope, old_inst.src);
1491 },
2348 .@"export" => return self.analyzeInstExport(scope, old_inst.cast(zir.Inst.Export).?),
14922349 .primitive => return self.analyzeInstPrimitive(scope, old_inst.cast(zir.Inst.Primitive).?),
1493 .ref => return self.analyzeInstRef(scope, old_inst.cast(zir.Inst.Ref).?),
14942350 .fntype => return self.analyzeInstFnType(scope, old_inst.cast(zir.Inst.FnType).?),
14952351 .intcast => return self.analyzeInstIntCast(scope, old_inst.cast(zir.Inst.IntCast).?),
14962352 .bitcast => return self.analyzeInstBitCast(scope, old_inst.cast(zir.Inst.BitCast).?),
......@@ -1503,39 +2359,104 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
15032359 }
15042360}
15052361
2362fn analyzeInstStr(self: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerError!*Inst {
2363 // The bytes references memory inside the ZIR module, which can get deallocated
2364 // after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena.
2365 var new_decl_arena = std.heap.ArenaAllocator.init(self.allocator);
2366 const arena_bytes = try new_decl_arena.allocator.dupe(u8, str_inst.positionals.bytes);
2367
2368 const ty_payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
2369 ty_payload.* = .{ .len = arena_bytes.len };
2370
2371 const bytes_payload = try scope.arena().create(Value.Payload.Bytes);
2372 bytes_payload.* = .{ .data = arena_bytes };
2373
2374 const new_decl = try self.createAnonymousDecl(scope, &new_decl_arena, .{
2375 .ty = Type.initPayload(&ty_payload.base),
2376 .val = Value.initPayload(&bytes_payload.base),
2377 });
2378 return self.analyzeDeclRef(scope, str_inst.base.src, new_decl);
2379}
2380
2381fn createAnonymousDecl(
2382 self: *Module,
2383 scope: *Scope,
2384 decl_arena: *std.heap.ArenaAllocator,
2385 typed_value: TypedValue,
2386) !*Decl {
2387 const name_index = self.getNextAnonNameIndex();
2388 const scope_decl = scope.decl().?;
2389 const name = try std.fmt.allocPrint(self.allocator, "{}${}", .{ scope_decl.name, name_index });
2390 defer self.allocator.free(name);
2391 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
2392 const src_hash: std.zig.SrcHash = undefined;
2393 const new_decl = try self.createNewDecl(scope, name, scope_decl.src_index, name_hash, src_hash);
2394 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
2395
2396 decl_arena_state.* = decl_arena.state;
2397 new_decl.typed_value = .{
2398 .most_recent = .{
2399 .typed_value = typed_value,
2400 .arena = decl_arena_state,
2401 },
2402 };
2403 new_decl.analysis = .complete;
2404 new_decl.generation = self.generation;
2405
2406 // TODO: This generates the Decl into the machine code file if it is of a type that is non-zero size.
2407 // We should be able to further improve the compiler to not omit Decls which are only referenced at
2408 // compile-time and not runtime.
2409 if (typed_value.ty.hasCodeGenBits()) {
2410 try self.bin_file.allocateDeclIndexes(new_decl);
2411 try self.work_queue.writeItem(.{ .codegen_decl = new_decl });
2412 }
2413
2414 return new_decl;
2415}
2416
2417fn getNextAnonNameIndex(self: *Module) usize {
2418 return @atomicRmw(usize, &self.next_anon_name_index, .Add, 1, .Monotonic);
2419}
2420
2421fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
2422 const namespace = scope.namespace();
2423 const name_hash = namespace.fullyQualifiedNameHash(ident_name);
2424 return self.decl_table.getValue(name_hash);
2425}
2426
2427fn analyzeInstExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) InnerError!*Inst {
2428 const symbol_name = try self.resolveConstString(scope, export_inst.positionals.symbol_name);
2429 const exported_decl = self.lookupDeclName(scope, export_inst.positionals.decl_name) orelse
2430 return self.fail(scope, export_inst.base.src, "decl '{}' not found", .{export_inst.positionals.decl_name});
2431 try self.analyzeExport(scope, export_inst.base.src, symbol_name, exported_decl);
2432 return self.constVoid(scope, export_inst.base.src);
2433}
2434
15062435fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.CompileError) InnerError!*Inst {
15072436 return self.fail(scope, inst.base.src, "{}", .{inst.positionals.msg});
15082437}
15092438
15102439fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoint) InnerError!*Inst {
15112440 const b = try self.requireRuntimeBlock(scope, inst.base.src);
1512 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){});
2441 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, {});
15132442}
15142443
1515fn analyzeInstRef(self: *Module, scope: *Scope, inst: *zir.Inst.Ref) InnerError!*Inst {
1516 const decl = try self.resolveCompleteDecl(scope, inst.positionals.operand);
1517 return self.analyzeDeclRef(scope, inst.base.src, decl);
2444fn analyzeInstDeclRefStr(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr) InnerError!*Inst {
2445 const decl_name = try self.resolveConstString(scope, inst.positionals.name);
2446 return self.analyzeDeclRefByName(scope, inst.base.src, decl_name);
15182447}
15192448
15202449fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst {
1521 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.
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);
2450 return self.analyzeDeclRefByName(scope, inst.base.src, inst.positionals.name);
15292451}
15302452
15312453fn analyzeDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Decl {
15322454 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();
2455 const zir_module = scope.namespace().cast(Scope.ZIRModule).?;
15352456 const src_decl = zir_module.contents.module.findDecl(decl_name) orelse
15362457 return self.fail(scope, inst.base.src, "use of undeclared identifier '{}'", .{decl_name});
15372458
1538 const decl = try self.resolveCompleteDecl(scope, src_decl);
2459 const decl = try self.resolveCompleteZirDecl(scope, src_decl.decl);
15392460
15402461 return decl;
15412462}
......@@ -1546,18 +2467,46 @@ fn analyzeInstDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) Inn
15462467 return self.analyzeDeref(scope, inst.base.src, ptr, inst.base.src);
15472468}
15482469
2470fn analyzeInstDeclValInModule(self: *Module, scope: *Scope, inst: *zir.Inst.DeclValInModule) InnerError!*Inst {
2471 const decl = inst.positionals.decl;
2472 const ptr = try self.analyzeDeclRef(scope, inst.base.src, decl);
2473 return self.analyzeDeref(scope, inst.base.src, ptr, inst.base.src);
2474}
2475
15492476fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {
2477 const scope_decl = scope.decl().?;
2478 try self.declareDeclDependency(scope_decl, decl);
2479 self.ensureDeclAnalyzed(decl) catch |err| {
2480 if (scope.cast(Scope.Block)) |block| {
2481 if (block.func) |func| {
2482 func.analysis = .dependency_failure;
2483 } else {
2484 block.decl.analysis = .dependency_failure;
2485 }
2486 } else {
2487 scope_decl.analysis = .dependency_failure;
2488 }
2489 return err;
2490 };
2491
15502492 const decl_tv = try decl.typedValue();
15512493 const ty_payload = try scope.arena().create(Type.Payload.SingleConstPointer);
15522494 ty_payload.* = .{ .pointee_type = decl_tv.ty };
15532495 const val_payload = try scope.arena().create(Value.Payload.DeclRef);
15542496 val_payload.* = .{ .decl = decl };
2497
15552498 return self.constInst(scope, src, .{
15562499 .ty = Type.initPayload(&ty_payload.base),
15572500 .val = Value.initPayload(&val_payload.base),
15582501 });
15592502}
15602503
2504fn analyzeDeclRefByName(self: *Module, scope: *Scope, src: usize, decl_name: []const u8) InnerError!*Inst {
2505 const decl = self.lookupDeclName(scope, decl_name) orelse
2506 return self.fail(scope, src, "decl '{}' not found", .{decl_name});
2507 return self.analyzeDeclRef(scope, src, decl);
2508}
2509
15612510fn analyzeInstCall(self: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
15622511 const func = try self.resolveInst(scope, inst.positionals.func);
15632512 if (func.ty.zigTypeTag() != .Fn)
......@@ -1616,7 +2565,7 @@ fn analyzeInstCall(self: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerErro
16162565 }
16172566
16182567 const b = try self.requireRuntimeBlock(scope, inst.base.src);
1619 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Call, Inst.Args(Inst.Call){
2568 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Call, .{
16202569 .func = func,
16212570 .args = casted_args,
16222571 });
......@@ -1624,10 +2573,22 @@ fn analyzeInstCall(self: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerErro
16242573
16252574fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst {
16262575 const fn_type = try self.resolveType(scope, fn_inst.positionals.fn_type);
2576 const fn_zir = blk: {
2577 var fn_arena = std.heap.ArenaAllocator.init(self.allocator);
2578 errdefer fn_arena.deinit();
2579
2580 const fn_zir = try scope.arena().create(Fn.ZIR);
2581 fn_zir.* = .{
2582 .body = .{
2583 .instructions = fn_inst.positionals.body.instructions,
2584 },
2585 .arena = fn_arena.state,
2586 };
2587 break :blk fn_zir;
2588 };
16272589 const new_func = try scope.arena().create(Fn);
16282590 new_func.* = .{
1629 .fn_type = fn_type,
1630 .analysis = .{ .queued = fn_inst },
2591 .analysis = .{ .queued = fn_zir },
16312592 .owner_decl = scope.decl().?,
16322593 };
16332594 const fn_payload = try scope.arena().create(Value.Payload.Function);
......@@ -1648,6 +2609,13 @@ fn analyzeInstFnType(self: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inn
16482609 return self.constType(scope, fntype.base.src, Type.initTag(.fn_noreturn_no_args));
16492610 }
16502611
2612 if (return_type.zigTypeTag() == .Void and
2613 fntype.positionals.param_types.len == 0 and
2614 fntype.kw_args.cc == .Unspecified)
2615 {
2616 return self.constType(scope, fntype.base.src, Type.initTag(.fn_void_no_args));
2617 }
2618
16512619 if (return_type.zigTypeTag() == .NoReturn and
16522620 fntype.positionals.param_types.len == 0 and
16532621 fntype.kw_args.cc == .Naked)
......@@ -1683,7 +2651,7 @@ fn analyzeInstPtrToInt(self: *Module, scope: *Scope, ptrtoint: *zir.Inst.PtrToIn
16832651 // TODO handle known-pointer-address
16842652 const b = try self.requireRuntimeBlock(scope, ptrtoint.base.src);
16852653 const ty = Type.initTag(.usize);
1686 return self.addNewInstArgs(b, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr });
2654 return self.addNewInstArgs(b, ptrtoint.base.src, ty, Inst.PtrToInt, .{ .ptr = ptr });
16872655}
16882656
16892657fn analyzeInstFieldPtr(self: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr) InnerError!*Inst {
......@@ -1875,7 +2843,7 @@ fn analyzeInstAsm(self: *Module, scope: *Scope, assembly: *zir.Inst.Asm) InnerEr
18752843 }
18762844
18772845 const b = try self.requireRuntimeBlock(scope, assembly.base.src);
1878 return self.addNewInstArgs(b, assembly.base.src, return_type, Inst.Assembly, Inst.Args(Inst.Assembly){
2846 return self.addNewInstArgs(b, assembly.base.src, return_type, Inst.Assembly, .{
18792847 .asm_source = asm_source,
18802848 .is_volatile = assembly.kw_args.@"volatile",
18812849 .output = output,
......@@ -1911,20 +2879,12 @@ fn analyzeInstCmp(self: *Module, scope: *Scope, inst: *zir.Inst.Cmp) InnerError!
19112879 }
19122880 const b = try self.requireRuntimeBlock(scope, inst.base.src);
19132881 switch (op) {
1914 .eq => return self.addNewInstArgs(
1915 b,
1916 inst.base.src,
1917 Type.initTag(.bool),
1918 Inst.IsNull,
1919 Inst.Args(Inst.IsNull){ .operand = opt_operand },
1920 ),
1921 .neq => return self.addNewInstArgs(
1922 b,
1923 inst.base.src,
1924 Type.initTag(.bool),
1925 Inst.IsNonNull,
1926 Inst.Args(Inst.IsNonNull){ .operand = opt_operand },
1927 ),
2882 .eq => return self.addNewInstArgs(b, inst.base.src, Type.initTag(.bool), Inst.IsNull, .{
2883 .operand = opt_operand,
2884 }),
2885 .neq => return self.addNewInstArgs(b, inst.base.src, Type.initTag(.bool), Inst.IsNonNull, .{
2886 .operand = opt_operand,
2887 }),
19282888 else => unreachable,
19292889 }
19302890 } else if (is_equality_cmp and
......@@ -2019,23 +2979,19 @@ fn analyzeInstUnreachable(self: *Module, scope: *Scope, unreach: *zir.Inst.Unrea
20192979}
20202980
20212981fn analyzeInstRet(self: *Module, scope: *Scope, inst: *zir.Inst.Return) InnerError!*Inst {
2982 const operand = try self.resolveInst(scope, inst.positionals.operand);
2983 const b = try self.requireRuntimeBlock(scope, inst.base.src);
2984 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.Ret, .{ .operand = operand });
2985}
2986
2987fn analyzeInstRetVoid(self: *Module, scope: *Scope, inst: *zir.Inst.ReturnVoid) InnerError!*Inst {
20222988 const b = try self.requireRuntimeBlock(scope, inst.base.src);
2023 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.Ret, {});
2989 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.RetVoid, {});
20242990}
20252991
20262992fn analyzeBody(self: *Module, scope: *Scope, body: zir.Module.Body) !void {
2027 if (scope.cast(Scope.Block)) |b| {
2028 const analysis = b.func.analysis.in_progress;
2029 analysis.needed_inst_capacity += body.instructions.len;
2030 try analysis.inst_table.ensureCapacity(analysis.needed_inst_capacity);
2031 for (body.instructions) |src_inst| {
2032 const new_inst = try self.analyzeInst(scope, src_inst);
2033 analysis.inst_table.putAssumeCapacityNoClobber(src_inst, new_inst);
2034 }
2035 } else {
2036 for (body.instructions) |src_inst| {
2037 _ = try self.analyzeInst(scope, src_inst);
2038 }
2993 for (body.instructions) |src_inst| {
2994 src_inst.analyzed_inst = try self.analyzeInst(scope, src_inst);
20392995 }
20402996}
20412997
......@@ -2118,7 +3074,7 @@ fn cmpNumeric(
21183074 };
21193075 const casted_lhs = try self.coerce(scope, dest_type, lhs);
21203076 const casted_rhs = try self.coerce(scope, dest_type, rhs);
2121 return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, Inst.Args(Inst.Cmp){
3077 return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, .{
21223078 .lhs = casted_lhs,
21233079 .rhs = casted_rhs,
21243080 .op = op,
......@@ -2222,7 +3178,7 @@ fn cmpNumeric(
22223178 const casted_lhs = try self.coerce(scope, dest_type, lhs);
22233179 const casted_rhs = try self.coerce(scope, dest_type, lhs);
22243180
2225 return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, Inst.Args(Inst.Cmp){
3181 return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, .{
22263182 .lhs = casted_lhs,
22273183 .rhs = casted_rhs,
22283184 .op = op,
......@@ -2299,7 +3255,7 @@ fn bitcast(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
22993255 }
23003256 // TODO validate the type size and other compile errors
23013257 const b = try self.requireRuntimeBlock(scope, inst.src);
2302 return self.addNewInstArgs(b, inst.src, dest_type, Inst.BitCast, Inst.Args(Inst.BitCast){ .operand = inst });
3258 return self.addNewInstArgs(b, inst.src, dest_type, Inst.BitCast, .{ .operand = inst });
23033259}
23043260
23053261fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
......@@ -2316,6 +3272,30 @@ fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, a
23163272 return self.failWithOwnedErrorMsg(scope, src, err_msg);
23173273}
23183274
3275fn failTok(
3276 self: *Module,
3277 scope: *Scope,
3278 token_index: ast.TokenIndex,
3279 comptime format: []const u8,
3280 args: var,
3281) InnerError {
3282 @setCold(true);
3283 const src = scope.tree().token_locs[token_index].start;
3284 return self.fail(scope, src, format, args);
3285}
3286
3287fn failNode(
3288 self: *Module,
3289 scope: *Scope,
3290 ast_node: *ast.Node,
3291 comptime format: []const u8,
3292 args: var,
3293) InnerError {
3294 @setCold(true);
3295 const src = scope.tree().token_locs[ast_node.firstToken()].start;
3296 return self.fail(scope, src, format, args);
3297}
3298
23193299fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *ErrorMsg) InnerError {
23203300 {
23213301 errdefer err_msg.destroy(self.allocator);
......@@ -2326,18 +3306,31 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err
23263306 .decl => {
23273307 const decl = scope.cast(Scope.DeclAnalysis).?.decl;
23283308 decl.analysis = .sema_failure;
3309 decl.generation = self.generation;
23293310 self.failed_decls.putAssumeCapacityNoClobber(decl, err_msg);
23303311 },
23313312 .block => {
23323313 const block = scope.cast(Scope.Block).?;
2333 block.func.analysis = .sema_failure;
3314 if (block.func) |func| {
3315 func.analysis = .sema_failure;
3316 } else {
3317 block.decl.analysis = .sema_failure;
3318 block.decl.generation = self.generation;
3319 }
23343320 self.failed_decls.putAssumeCapacityNoClobber(block.decl, err_msg);
23353321 },
3322 .gen_zir => {
3323 const gen_zir = scope.cast(Scope.GenZIR).?;
3324 gen_zir.decl.analysis = .sema_failure;
3325 gen_zir.decl.generation = self.generation;
3326 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3327 },
23363328 .zir_module => {
23373329 const zir_module = scope.cast(Scope.ZIRModule).?;
23383330 zir_module.status = .loaded_sema_failure;
2339 self.failed_files.putAssumeCapacityNoClobber(zir_module, err_msg);
3331 self.failed_files.putAssumeCapacityNoClobber(scope, err_msg);
23403332 },
3333 .file => unreachable,
23413334 }
23423335 return error.AnalysisFail;
23433336}
......@@ -2385,3 +3378,7 @@ pub const ErrorMsg = struct {
23853378 self.* = undefined;
23863379 }
23873380};
3381
3382fn srcHashEql(a: std.zig.SrcHash, b: std.zig.SrcHash) bool {
3383 return @bitCast(u128, a) == @bitCast(u128, b);
3384}
src-self-hosted/TypedValue.zig+8
......@@ -21,3 +21,11 @@ pub const Managed = struct {
2121 self.* = undefined;
2222 }
2323};
24
25/// Assumes arena allocation. Does a recursive copy.
26pub fn copy(self: TypedValue, allocator: *Allocator) error{OutOfMemory}!TypedValue {
27 return TypedValue{
28 .ty = try self.ty.copy(allocator),
29 .val = try self.val.copy(allocator),
30 };
31}
src-self-hosted/codegen.zig+20-3
......@@ -10,6 +10,7 @@ const Module = @import("Module.zig");
1010const ErrorMsg = Module.ErrorMsg;
1111const Target = std.Target;
1212const Allocator = mem.Allocator;
13const trace = @import("tracy.zig").trace;
1314
1415pub const Result = union(enum) {
1516 /// The `code` parameter passed to `generateSymbol` has the value appended.
......@@ -29,6 +30,9 @@ pub fn generateSymbol(
2930 /// A Decl that this symbol depends on had a semantic analysis failure.
3031 AnalysisFail,
3132}!Result {
33 const tracy = trace(@src());
34 defer tracy.end();
35
3236 switch (typed_value.ty.zigTypeTag()) {
3337 .Fn => {
3438 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
......@@ -178,6 +182,7 @@ const Function = struct {
178182 .ptrtoint => return self.genPtrToInt(inst.cast(ir.Inst.PtrToInt).?),
179183 .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?),
180184 .ret => return self.genRet(inst.cast(ir.Inst.Ret).?),
185 .retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?),
181186 .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?),
182187 .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?),
183188 .isnull => return self.genIsNull(inst.cast(ir.Inst.IsNull).?),
......@@ -213,7 +218,7 @@ const Function = struct {
213218 try self.code.resize(self.code.items.len + 7);
214219 self.code.items[self.code.items.len - 7 ..][0..3].* = [3]u8{ 0xff, 0x14, 0x25 };
215220 mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], got_addr);
216 const return_type = func.fn_type.fnReturnType();
221 const return_type = func.owner_decl.typed_value.most_recent.typed_value.ty.fnReturnType();
217222 switch (return_type.zigTypeTag()) {
218223 .Void => return MCValue{ .none = {} },
219224 .NoReturn => return MCValue{ .unreach = {} },
......@@ -230,16 +235,28 @@ const Function = struct {
230235 }
231236 }
232237
233 fn genRet(self: *Function, inst: *ir.Inst.Ret) !MCValue {
238 fn ret(self: *Function, src: usize, mcv: MCValue) !MCValue {
239 if (mcv != .none) {
240 return self.fail(src, "TODO implement return with non-void operand", .{});
241 }
234242 switch (self.target.cpu.arch) {
235243 .i386, .x86_64 => {
236244 try self.code.append(0xc3); // ret
237245 },
238 else => return self.fail(inst.base.src, "TODO implement return for {}", .{self.target.cpu.arch}),
246 else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}),
239247 }
240248 return .unreach;
241249 }
242250
251 fn genRet(self: *Function, inst: *ir.Inst.Ret) !MCValue {
252 const operand = try self.resolveInst(inst.args.operand);
253 return self.ret(inst.base.src, operand);
254 }
255
256 fn genRetVoid(self: *Function, inst: *ir.Inst.RetVoid) !MCValue {
257 return self.ret(inst.base.src, .none);
258 }
259
243260 fn genCmp(self: *Function, inst: *ir.Inst.Cmp) !MCValue {
244261 switch (self.target.cpu.arch) {
245262 else => return self.fail(inst.base.src, "TODO implement cmp for {}", .{self.target.cpu.arch}),
src-self-hosted/ir.zig+9
......@@ -26,6 +26,7 @@ pub const Inst = struct {
2626 isnull,
2727 ptrtoint,
2828 ret,
29 retvoid,
2930 unreach,
3031 };
3132
......@@ -146,6 +147,14 @@ pub const Inst = struct {
146147 pub const Ret = struct {
147148 pub const base_tag = Tag.ret;
148149 base: Inst,
150 args: struct {
151 operand: *Inst,
152 },
153 };
154
155 pub const RetVoid = struct {
156 pub const base_tag = Tag.retvoid;
157 base: Inst,
149158 args: void,
150159 };
151160
src-self-hosted/link.zig+12-13
......@@ -369,7 +369,7 @@ pub const ElfFile = struct {
369369 const file_size = self.options.program_code_size_hint;
370370 const p_align = 0x1000;
371371 const off = self.findFreeSpace(file_size, p_align);
372 //std.debug.warn("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
372 //std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
373373 try self.program_headers.append(self.allocator, .{
374374 .p_type = elf.PT_LOAD,
375375 .p_offset = off,
......@@ -390,7 +390,7 @@ pub const ElfFile = struct {
390390 // page align.
391391 const p_align = 0x1000;
392392 const off = self.findFreeSpace(file_size, p_align);
393 //std.debug.warn("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
393 //std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
394394 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
395395 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
396396 // else in virtual memory.
......@@ -412,7 +412,7 @@ pub const ElfFile = struct {
412412 assert(self.shstrtab.items.len == 0);
413413 try self.shstrtab.append(self.allocator, 0); // need a 0 at position 0
414414 const off = self.findFreeSpace(self.shstrtab.items.len, 1);
415 //std.debug.warn("found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len });
415 //std.log.debug(.link, "found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len });
416416 try self.sections.append(self.allocator, .{
417417 .sh_name = try self.makeString(".shstrtab"),
418418 .sh_type = elf.SHT_STRTAB,
......@@ -470,7 +470,7 @@ pub const ElfFile = struct {
470470 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
471471 const file_size = self.options.symbol_count_hint * each_size;
472472 const off = self.findFreeSpace(file_size, min_align);
473 //std.debug.warn("found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
473 //std.log.debug(.link, "found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
474474
475475 try self.sections.append(self.allocator, .{
476476 .sh_name = try self.makeString(".symtab"),
......@@ -586,7 +586,7 @@ pub const ElfFile = struct {
586586 shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1);
587587 }
588588 shstrtab_sect.sh_size = needed_size;
589 //std.debug.warn("shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });
589 //std.log.debug(.link, "shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });
590590
591591 try self.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
592592 if (!self.shdr_table_dirty) {
......@@ -632,7 +632,7 @@ pub const ElfFile = struct {
632632
633633 for (buf) |*shdr, i| {
634634 shdr.* = self.sections.items[i];
635 //std.debug.warn("writing section {}\n", .{shdr.*});
635 //std.log.debug(.link, "writing section {}\n", .{shdr.*});
636636 if (foreign_endian) {
637637 bswapAllFields(elf.Elf64_Shdr, shdr);
638638 }
......@@ -956,10 +956,10 @@ pub const ElfFile = struct {
956956 try self.offset_table_free_list.ensureCapacity(self.allocator, self.local_symbols.items.len);
957957
958958 if (self.local_symbol_free_list.popOrNull()) |i| {
959 //std.debug.warn("reusing symbol index {} for {}\n", .{i, decl.name});
959 //std.log.debug(.link, "reusing symbol index {} for {}\n", .{i, decl.name});
960960 decl.link.local_sym_index = i;
961961 } else {
962 //std.debug.warn("allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name});
962 //std.log.debug(.link, "allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name});
963963 decl.link.local_sym_index = @intCast(u32, self.local_symbols.items.len);
964964 _ = self.local_symbols.addOneAssumeCapacity();
965965 }
......@@ -1002,7 +1002,7 @@ pub const ElfFile = struct {
10021002 defer code_buffer.deinit();
10031003
10041004 const typed_value = decl.typed_value.most_recent.typed_value;
1005 const code = switch (try codegen.generateSymbol(self, decl.src, typed_value, &code_buffer)) {
1005 const code = switch (try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer)) {
10061006 .externally_managed => |x| x,
10071007 .appended => code_buffer.items,
10081008 .fail => |em| {
......@@ -1027,11 +1027,11 @@ pub const ElfFile = struct {
10271027 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
10281028 if (need_realloc) {
10291029 const vaddr = try self.growTextBlock(&decl.link, code.len, required_alignment);
1030 //std.debug.warn("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
1030 //std.log.debug(.link, "growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
10311031 if (vaddr != local_sym.st_value) {
10321032 local_sym.st_value = vaddr;
10331033
1034 //std.debug.warn(" (writing new offset table entry)\n", .{});
1034 //std.log.debug(.link, " (writing new offset table entry)\n", .{});
10351035 self.offset_table.items[decl.link.offset_table_index] = vaddr;
10361036 try self.writeOffsetTableEntry(decl.link.offset_table_index);
10371037 }
......@@ -1049,7 +1049,7 @@ pub const ElfFile = struct {
10491049 const decl_name = mem.spanZ(decl.name);
10501050 const name_str_index = try self.makeString(decl_name);
10511051 const vaddr = try self.allocateTextBlock(&decl.link, code.len, required_alignment);
1052 //std.debug.warn("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
1052 //std.log.debug(.link, "allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
10531053 errdefer self.freeTextBlock(&decl.link);
10541054
10551055 local_sym.* = .{
......@@ -1307,7 +1307,6 @@ pub const ElfFile = struct {
13071307 .p32 => @sizeOf(elf.Elf32_Sym),
13081308 .p64 => @sizeOf(elf.Elf64_Sym),
13091309 };
1310 //std.debug.warn("symtab start=0x{x} end=0x{x}\n", .{ syms_sect.sh_offset, syms_sect.sh_offset + needed_size });
13111310 const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
13121311 const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size;
13131312 switch (self.ptr_width) {
src-self-hosted/main.zig+30-16
......@@ -38,6 +38,29 @@ const usage =
3838 \\
3939;
4040
41pub fn log(
42 comptime level: std.log.Level,
43 comptime scope: @TypeOf(.EnumLiteral),
44 comptime format: []const u8,
45 args: var,
46) void {
47 if (@enumToInt(level) > @enumToInt(std.log.level))
48 return;
49
50 const scope_prefix = "(" ++ switch (scope) {
51 // Uncomment to hide logs
52 //.compiler,
53 .link => return,
54
55 else => @tagName(scope),
56 } ++ "): ";
57
58 const prefix = "[" ++ @tagName(level) ++ "] " ++ scope_prefix;
59
60 // Print the message to stderr, silently ignoring any errors
61 std.debug.print(prefix ++ format, args);
62}
63
4164pub fn main() !void {
4265 // TODO general purpose allocator in the zig std lib
4366 const gpa = if (std.builtin.link_libc) std.heap.c_allocator else std.heap.page_allocator;
......@@ -86,7 +109,7 @@ const usage_build_generic =
86109 \\ zig build-obj <options> [files]
87110 \\
88111 \\Supported file types:
89 \\ (planned) .zig Zig source code
112 \\ .zig Zig source code
90113 \\ .zir Zig Intermediate Representation code
91114 \\ (planned) .o ELF object file
92115 \\ (planned) .o MACH-O (macOS) object file
......@@ -407,21 +430,7 @@ fn buildOutputType(
407430 std.debug.warn("-fno-emit-bin not supported yet", .{});
408431 process.exit(1);
409432 },
410 .yes_default_path => switch (output_mode) {
411 .Exe => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.exeFileExt() }),
412 .Lib => blk: {
413 const suffix = switch (link_mode orelse .Static) {
414 .Static => target_info.target.staticLibSuffix(),
415 .Dynamic => target_info.target.dynamicLibSuffix(),
416 };
417 break :blk try std.fmt.allocPrint(arena, "{}{}{}", .{
418 target_info.target.libPrefix(),
419 root_name,
420 suffix,
421 });
422 },
423 .Obj => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.oFileExt() }),
424 },
433 .yes_default_path => try std.zig.binNameAlloc(arena, root_name, target_info.target, output_mode, link_mode),
425434 .yes => |p| p,
426435 };
427436
......@@ -450,6 +459,7 @@ fn buildOutputType(
450459 .link_mode = link_mode,
451460 .object_format = object_format,
452461 .optimize_mode = build_mode,
462 .keep_source_files_loaded = zir_out_path != null,
453463 });
454464 defer module.deinit();
455465
......@@ -487,7 +497,9 @@ fn buildOutputType(
487497}
488498
489499fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !void {
500 var timer = try std.time.Timer.start();
490501 try module.update();
502 const update_nanos = timer.read();
491503
492504 var errors = try module.getAllErrorsAlloc();
493505 defer errors.deinit(module.allocator);
......@@ -501,6 +513,8 @@ fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !vo
501513 full_err_msg.msg,
502514 });
503515 }
516 } else {
517 std.log.info(.compiler, "Update completed in {} ms\n", .{update_nanos / std.time.ns_per_ms});
504518 }
505519
506520 if (zir_out_path) |zop| {
src-self-hosted/test.zig+146-156
......@@ -21,32 +21,7 @@ const ErrorMsg = struct {
2121};
2222
2323pub const TestContext = struct {
24 // TODO: remove these. They are deprecated.
25 zir_cmp_output_cases: std.ArrayList(ZIRCompareOutputCase),
26
27 /// TODO: find a way to treat cases as individual tests (shouldn't show "1 test passed" if there are 200 cases)
28 zir_cases: std.ArrayList(ZIRCase),
29
30 // TODO: remove
31 pub const ZIRCompareOutputCase = struct {
32 name: []const u8,
33 src_list: []const []const u8,
34 expected_stdout_list: []const []const u8,
35 };
36
37 pub const ZIRUpdateType = enum {
38 /// A transformation update transforms the input ZIR and tests against
39 /// the expected output
40 Transformation,
41 /// An error update attempts to compile bad code, and ensures that it
42 /// fails to compile, and for the expected reasons
43 Error,
44 /// An execution update compiles and runs the input ZIR, feeding in
45 /// provided input and ensuring that the outputs match what is expected
46 Execution,
47 /// A compilation update checks that the ZIR compiles without any issues
48 Compiles,
49 };
24 zir_cases: std.ArrayList(Case),
5025
5126 pub const ZIRUpdate = struct {
5227 /// The input to the current update. We simulate an incremental update
......@@ -57,58 +32,55 @@ pub const TestContext = struct {
5732 /// you can keep it mostly consistent, with small changes, testing the
5833 /// effects of the incremental compilation.
5934 src: [:0]const u8,
60 case: union(ZIRUpdateType) {
61 /// The expected output ZIR
35 case: union(enum) {
36 /// A transformation update transforms the input ZIR and tests against
37 /// the expected output ZIR.
6238 Transformation: [:0]const u8,
39 /// An error update attempts to compile bad code, and ensures that it
40 /// fails to compile, and for the expected reasons.
6341 /// A slice containing the expected errors *in sequential order*.
6442 Error: []const ErrorMsg,
65
66 /// Input to feed to the program, and expected outputs.
67 ///
68 /// If stdout, stderr, and exit_code are all null, addZIRCase will
69 /// discard the test. To test for successful compilation, use a
70 /// dedicated Compile update instead.
71 Execution: struct {
72 stdin: ?[]const u8,
73 stdout: ?[]const u8,
74 stderr: ?[]const u8,
75 exit_code: ?u8,
76 },
77 /// A Compiles test checks only that compilation of the given ZIR
78 /// succeeds. To test outputs, use an Execution test. It is good to
79 /// use a Compiles test before an Execution, as the overhead should
80 /// be low (due to incremental compilation) and TODO: provide a way
81 /// to check changed / new / etc decls in testing mode
82 /// (usingnamespace a debug info struct with a comptime flag?)
83 Compiles: void,
43 /// An execution update compiles and runs the input ZIR, feeding in
44 /// provided input and ensuring that the stdout match what is expected.
45 Execution: []const u8,
8446 },
8547 };
8648
87 /// A ZIRCase consists of a set of *updates*. A update can transform ZIR,
49 /// A Case consists of a set of *updates*. A update can transform ZIR,
8850 /// compile it, ensure that compilation fails, and more. The same Module is
8951 /// used for each update, so each update's source is treated as a single file
9052 /// being updated by the test harness and incrementally compiled.
91 pub const ZIRCase = struct {
53 pub const Case = struct {
9254 name: []const u8,
9355 /// The platform the ZIR targets. For non-native platforms, an emulator
9456 /// such as QEMU is required for tests to complete.
9557 target: std.zig.CrossTarget,
9658 updates: std.ArrayList(ZIRUpdate),
59 output_mode: std.builtin.OutputMode,
60 /// Either ".zir" or ".zig"
61 extension: [4]u8,
9762
9863 /// Adds a subcase in which the module is updated with new ZIR, and the
9964 /// resulting ZIR is validated.
100 pub fn addTransform(self: *ZIRCase, src: [:0]const u8, result: [:0]const u8) void {
65 pub fn addTransform(self: *Case, src: [:0]const u8, result: [:0]const u8) void {
10166 self.updates.append(.{
10267 .src = src,
10368 .case = .{ .Transformation = result },
10469 }) catch unreachable;
10570 }
10671
72 pub fn addCompareOutput(self: *Case, src: [:0]const u8, result: []const u8) void {
73 self.updates.append(.{
74 .src = src,
75 .case = .{ .Execution = result },
76 }) catch unreachable;
77 }
78
10779 /// Adds a subcase in which the module is updated with invalid ZIR, and
10880 /// ensures that compilation fails for the expected reasons.
10981 ///
11082 /// Errors must be specified in sequential order.
111 pub fn addError(self: *ZIRCase, src: [:0]const u8, errors: []const []const u8) void {
83 pub fn addError(self: *Case, src: [:0]const u8, errors: []const []const u8) void {
11284 var array = self.updates.allocator.alloc(ErrorMsg, errors.len) catch unreachable;
11385 for (errors) |e, i| {
11486 if (e[0] != ':') {
......@@ -146,15 +118,65 @@ pub const TestContext = struct {
146118 }
147119 };
148120
149 pub fn addZIRMulti(
121 pub fn addExeZIR(
122 ctx: *TestContext,
123 name: []const u8,
124 target: std.zig.CrossTarget,
125 ) *Case {
126 const case = Case{
127 .name = name,
128 .target = target,
129 .updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
130 .output_mode = .Exe,
131 .extension = ".zir".*,
132 };
133 ctx.zir_cases.append(case) catch unreachable;
134 return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
135 }
136
137 pub fn addObjZIR(
150138 ctx: *TestContext,
151139 name: []const u8,
152140 target: std.zig.CrossTarget,
153 ) *ZIRCase {
154 const case = ZIRCase{
141 ) *Case {
142 const case = Case{
155143 .name = name,
156144 .target = target,
157145 .updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
146 .output_mode = .Obj,
147 .extension = ".zir".*,
148 };
149 ctx.zir_cases.append(case) catch unreachable;
150 return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
151 }
152
153 pub fn addExe(
154 ctx: *TestContext,
155 name: []const u8,
156 target: std.zig.CrossTarget,
157 ) *Case {
158 const case = Case{
159 .name = name,
160 .target = target,
161 .updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
162 .output_mode = .Exe,
163 .extension = ".zig".*,
164 };
165 ctx.zir_cases.append(case) catch unreachable;
166 return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
167 }
168
169 pub fn addObj(
170 ctx: *TestContext,
171 name: []const u8,
172 target: std.zig.CrossTarget,
173 ) *Case {
174 const case = Case{
175 .name = name,
176 .target = target,
177 .updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
178 .output_mode = .Obj,
179 .extension = ".zig".*,
158180 };
159181 ctx.zir_cases.append(case) catch unreachable;
160182 return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
......@@ -163,14 +185,21 @@ pub const TestContext = struct {
163185 pub fn addZIRCompareOutput(
164186 ctx: *TestContext,
165187 name: []const u8,
166 src_list: []const []const u8,
167 expected_stdout_list: []const []const u8,
188 src: [:0]const u8,
189 expected_stdout: []const u8,
168190 ) void {
169 ctx.zir_cmp_output_cases.append(.{
170 .name = name,
171 .src_list = src_list,
172 .expected_stdout_list = expected_stdout_list,
173 }) catch unreachable;
191 var c = ctx.addExeZIR(name, .{});
192 c.addCompareOutput(src, expected_stdout);
193 }
194
195 pub fn addCompareOutput(
196 ctx: *TestContext,
197 name: []const u8,
198 src: [:0]const u8,
199 expected_stdout: []const u8,
200 ) void {
201 var c = ctx.addExe(name, .{});
202 c.addCompareOutput(src, expected_stdout);
174203 }
175204
176205 pub fn addZIRTransform(
......@@ -180,7 +209,7 @@ pub const TestContext = struct {
180209 src: [:0]const u8,
181210 result: [:0]const u8,
182211 ) void {
183 var c = ctx.addZIRMulti(name, target);
212 var c = ctx.addObjZIR(name, target);
184213 c.addTransform(src, result);
185214 }
186215
......@@ -191,20 +220,18 @@ pub const TestContext = struct {
191220 src: [:0]const u8,
192221 expected_errors: []const []const u8,
193222 ) void {
194 var c = ctx.addZIRMulti(name, target);
223 var c = ctx.addObjZIR(name, target);
195224 c.addError(src, expected_errors);
196225 }
197226
198227 fn init() TestContext {
199228 const allocator = std.heap.page_allocator;
200229 return .{
201 .zir_cmp_output_cases = std.ArrayList(ZIRCompareOutputCase).init(allocator),
202 .zir_cases = std.ArrayList(ZIRCase).init(allocator),
230 .zir_cases = std.ArrayList(Case).init(allocator),
203231 };
204232 }
205233
206234 fn deinit(self: *TestContext) void {
207 self.zir_cmp_output_cases.deinit();
208235 for (self.zir_cases.items) |c| {
209236 for (c.updates.items) |u| {
210237 if (u.case == .Error) {
......@@ -226,30 +253,32 @@ pub const TestContext = struct {
226253
227254 for (self.zir_cases.items) |case| {
228255 std.testing.base_allocator_instance.reset();
229 const info = try std.zig.system.NativeTargetInfo.detect(std.testing.allocator, case.target);
230 try self.runOneZIRCase(std.testing.allocator, root_node, case, info.target);
231 try std.testing.allocator_instance.validate();
232 }
233256
234 // TODO: wipe the rest of this function
235 for (self.zir_cmp_output_cases.items) |case| {
236 std.testing.base_allocator_instance.reset();
237 try self.runOneZIRCmpOutputCase(std.testing.allocator, root_node, case, native_info.target);
257 var prg_node = root_node.start(case.name, case.updates.items.len);
258 prg_node.activate();
259 defer prg_node.end();
260
261 // So that we can see which test case failed when the leak checker goes off.
262 progress.refresh();
263
264 const info = try std.zig.system.NativeTargetInfo.detect(std.testing.allocator, case.target);
265 try self.runOneCase(std.testing.allocator, &prg_node, case, info.target);
238266 try std.testing.allocator_instance.validate();
239267 }
240268 }
241269
242 fn runOneZIRCase(self: *TestContext, allocator: *Allocator, root_node: *std.Progress.Node, case: ZIRCase, target: std.Target) !void {
270 fn runOneCase(self: *TestContext, allocator: *Allocator, prg_node: *std.Progress.Node, case: Case, target: std.Target) !void {
243271 var tmp = std.testing.tmpDir(.{});
244272 defer tmp.cleanup();
245273
246 const tmp_src_path = "test_case.zir";
274 const root_name = "test_case";
275 const tmp_src_path = try std.fmt.allocPrint(allocator, "{}{}", .{ root_name, case.extension });
276 defer allocator.free(tmp_src_path);
247277 const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);
248278 defer root_pkg.destroy();
249279
250 var prg_node = root_node.start(case.name, case.updates.items.len);
251 prg_node.activate();
252 defer prg_node.end();
280 const bin_name = try std.zig.binNameAlloc(allocator, root_name, target, case.output_mode, null);
281 defer allocator.free(bin_name);
253282
254283 var module = try Module.init(allocator, .{
255284 .target = target,
......@@ -259,16 +288,17 @@ pub const TestContext = struct {
259288 // TODO: support tests for object file building, and library builds
260289 // and linking. This will require a rework to support multi-file
261290 // tests.
262 .output_mode = .Obj,
291 .output_mode = case.output_mode,
263292 // TODO: support testing optimizations
264293 .optimize_mode = .Debug,
265294 .bin_file_dir = tmp.dir,
266 .bin_file_path = "test_case.o",
295 .bin_file_path = bin_name,
267296 .root_pkg = root_pkg,
297 .keep_source_files_loaded = true,
268298 });
269299 defer module.deinit();
270300
271 for (case.updates.items) |update| {
301 for (case.updates.items) |update, update_index| {
272302 var update_node = prg_node.start("update", 4);
273303 update_node.activate();
274304 defer update_node.end();
......@@ -280,6 +310,7 @@ pub const TestContext = struct {
280310
281311 var module_node = update_node.start("parse/analysis/codegen", null);
282312 module_node.activate();
313 try module.makeBinFileWritable();
283314 try module.update();
284315 module_node.end();
285316
......@@ -328,82 +359,41 @@ pub const TestContext = struct {
328359 }
329360 }
330361 },
331
332 else => return error.unimplemented,
333 }
334 }
335 }
336
337 fn runOneZIRCmpOutputCase(
338 self: *TestContext,
339 allocator: *Allocator,
340 root_node: *std.Progress.Node,
341 case: ZIRCompareOutputCase,
342 target: std.Target,
343 ) !void {
344 var tmp = std.testing.tmpDir(.{});
345 defer tmp.cleanup();
346
347 const tmp_src_path = "test-case.zir";
348 const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);
349 defer root_pkg.destroy();
350
351 var prg_node = root_node.start(case.name, case.src_list.len);
352 prg_node.activate();
353 defer prg_node.end();
354
355 var module = try Module.init(allocator, .{
356 .target = target,
357 .output_mode = .Exe,
358 .optimize_mode = .Debug,
359 .bin_file_dir = tmp.dir,
360 .bin_file_path = "a.out",
361 .root_pkg = root_pkg,
362 });
363 defer module.deinit();
364
365 for (case.src_list) |source, i| {
366 var src_node = prg_node.start("update", 2);
367 src_node.activate();
368 defer src_node.end();
369
370 try tmp.dir.writeFile(tmp_src_path, source);
371
372 var update_node = src_node.start("parse,analysis,codegen", null);
373 update_node.activate();
374 try module.makeBinFileWritable();
375 try module.update();
376 update_node.end();
377
378 var exec_result = x: {
379 var exec_node = src_node.start("execute", null);
380 exec_node.activate();
381 defer exec_node.end();
382
383 try module.makeBinFileExecutable();
384 break :x try std.ChildProcess.exec(.{
385 .allocator = allocator,
386 .argv = &[_][]const u8{"./a.out"},
387 .cwd_dir = tmp.dir,
388 });
389 };
390 defer allocator.free(exec_result.stdout);
391 defer allocator.free(exec_result.stderr);
392 switch (exec_result.term) {
393 .Exited => |code| {
394 if (code != 0) {
395 std.debug.warn("elf file exited with code {}\n", .{code});
396 return error.BinaryBadExitCode;
362 .Execution => |expected_stdout| {
363 var exec_result = x: {
364 var exec_node = update_node.start("execute", null);
365 exec_node.activate();
366 defer exec_node.end();
367
368 try module.makeBinFileExecutable();
369
370 const exe_path = try std.fmt.allocPrint(allocator, "." ++ std.fs.path.sep_str ++ "{}", .{bin_name});
371 defer allocator.free(exe_path);
372
373 break :x try std.ChildProcess.exec(.{
374 .allocator = allocator,
375 .argv = &[_][]const u8{exe_path},
376 .cwd_dir = tmp.dir,
377 });
378 };
379 defer allocator.free(exec_result.stdout);
380 defer allocator.free(exec_result.stderr);
381 switch (exec_result.term) {
382 .Exited => |code| {
383 if (code != 0) {
384 std.debug.warn("elf file exited with code {}\n", .{code});
385 return error.BinaryBadExitCode;
386 }
387 },
388 else => return error.BinaryCrashed,
389 }
390 if (!std.mem.eql(u8, expected_stdout, exec_result.stdout)) {
391 std.debug.panic(
392 "update index {}, mismatched stdout\n====Expected (len={}):====\n{}\n====Actual (len={}):====\n{}\n========\n",
393 .{ update_index, expected_stdout.len, expected_stdout, exec_result.stdout.len, exec_result.stdout },
394 );
397395 }
398396 },
399 else => return error.BinaryCrashed,
400 }
401 const expected_stdout = case.expected_stdout_list[i];
402 if (!std.mem.eql(u8, expected_stdout, exec_result.stdout)) {
403 std.debug.panic(
404 "update index {}, mismatched stdout\n====Expected (len={}):====\n{}\n====Actual (len={}):====\n{}\n========\n",
405 .{ i, expected_stdout.len, expected_stdout, exec_result.stdout.len, exec_result.stdout },
406 );
407397 }
408398 }
409399 }
src-self-hosted/tracy.zig created+45
......@@ -0,0 +1,45 @@
1pub const std = @import("std");
2
3pub const enable = if (std.builtin.is_test) false else @import("build_options").enable_tracy;
4
5extern fn ___tracy_emit_zone_begin_callstack(
6 srcloc: *const ___tracy_source_location_data,
7 depth: c_int,
8 active: c_int,
9) ___tracy_c_zone_context;
10
11extern fn ___tracy_emit_zone_end(ctx: ___tracy_c_zone_context) void;
12
13pub const ___tracy_source_location_data = extern struct {
14 name: ?[*:0]const u8,
15 function: [*:0]const u8,
16 file: [*:0]const u8,
17 line: u32,
18 color: u32,
19};
20
21pub const ___tracy_c_zone_context = extern struct {
22 id: u32,
23 active: c_int,
24
25 pub fn end(self: ___tracy_c_zone_context) void {
26 ___tracy_emit_zone_end(self);
27 }
28};
29
30pub const Ctx = if (enable) ___tracy_c_zone_context else struct {
31 pub fn end(self: Ctx) void {}
32};
33
34pub inline fn trace(comptime src: std.builtin.SourceLocation) Ctx {
35 if (!enable) return .{};
36
37 const loc: ___tracy_source_location_data = .{
38 .name = null,
39 .function = src.fn_name.ptr,
40 .file = src.file.ptr,
41 .line = src.line,
42 .color = 0,
43 };
44 return ___tracy_emit_zone_begin_callstack(&loc, 1, 1);
45}
src-self-hosted/type.zig+102-1
......@@ -54,6 +54,7 @@ pub const Type = extern union {
5454 .@"undefined" => return .Undefined,
5555
5656 .fn_noreturn_no_args => return .Fn,
57 .fn_void_no_args => return .Fn,
5758 .fn_naked_noreturn_no_args => return .Fn,
5859 .fn_ccc_void_no_args => return .Fn,
5960
......@@ -112,6 +113,12 @@ pub const Type = extern union {
112113 .Undefined => return true,
113114 .Null => return true,
114115 .Pointer => {
116 // Hot path for common case:
117 if (a.cast(Payload.SingleConstPointer)) |a_payload| {
118 if (b.cast(Payload.SingleConstPointer)) |b_payload| {
119 return eql(a_payload.pointee_type, b_payload.pointee_type);
120 }
121 }
115122 const is_slice_a = isSlice(a);
116123 const is_slice_b = isSlice(b);
117124 if (is_slice_a != is_slice_b)
......@@ -163,6 +170,77 @@ pub const Type = extern union {
163170 }
164171 }
165172
173 pub fn copy(self: Type, allocator: *Allocator) error{OutOfMemory}!Type {
174 if (self.tag_if_small_enough < Tag.no_payload_count) {
175 return Type{ .tag_if_small_enough = self.tag_if_small_enough };
176 } else switch (self.ptr_otherwise.tag) {
177 .u8,
178 .i8,
179 .isize,
180 .usize,
181 .c_short,
182 .c_ushort,
183 .c_int,
184 .c_uint,
185 .c_long,
186 .c_ulong,
187 .c_longlong,
188 .c_ulonglong,
189 .c_longdouble,
190 .c_void,
191 .f16,
192 .f32,
193 .f64,
194 .f128,
195 .bool,
196 .void,
197 .type,
198 .anyerror,
199 .comptime_int,
200 .comptime_float,
201 .noreturn,
202 .@"null",
203 .@"undefined",
204 .fn_noreturn_no_args,
205 .fn_void_no_args,
206 .fn_naked_noreturn_no_args,
207 .fn_ccc_void_no_args,
208 .single_const_pointer_to_comptime_int,
209 .const_slice_u8,
210 => unreachable,
211
212 .array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0),
213 .array => {
214 const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
215 const new_payload = try allocator.create(Payload.Array);
216 new_payload.* = .{
217 .base = payload.base,
218 .len = payload.len,
219 .elem_type = try payload.elem_type.copy(allocator),
220 };
221 return Type{ .ptr_otherwise = &new_payload.base };
222 },
223 .single_const_pointer => {
224 const payload = @fieldParentPtr(Payload.SingleConstPointer, "base", self.ptr_otherwise);
225 const new_payload = try allocator.create(Payload.SingleConstPointer);
226 new_payload.* = .{
227 .base = payload.base,
228 .pointee_type = try payload.pointee_type.copy(allocator),
229 };
230 return Type{ .ptr_otherwise = &new_payload.base };
231 },
232 .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
233 .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
234 }
235 }
236
237 fn copyPayloadShallow(self: Type, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Type {
238 const payload = @fieldParentPtr(T, "base", self.ptr_otherwise);
239 const new_payload = try allocator.create(T);
240 new_payload.* = payload.*;
241 return Type{ .ptr_otherwise = &new_payload.base };
242 }
243
166244 pub fn format(
167245 self: Type,
168246 comptime fmt: []const u8,
......@@ -206,6 +284,7 @@ pub const Type = extern union {
206284
207285 .const_slice_u8 => return out_stream.writeAll("[]const u8"),
208286 .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),
287 .fn_void_no_args => return out_stream.writeAll("fn() void"),
209288 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
210289 .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),
211290 .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
......@@ -269,6 +348,7 @@ pub const Type = extern union {
269348 .@"null" => return Value.initTag(.null_type),
270349 .@"undefined" => return Value.initTag(.undefined_type),
271350 .fn_noreturn_no_args => return Value.initTag(.fn_noreturn_no_args_type),
351 .fn_void_no_args => return Value.initTag(.fn_void_no_args_type),
272352 .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type),
273353 .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),
274354 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
......@@ -303,6 +383,7 @@ pub const Type = extern union {
303383 .bool,
304384 .anyerror,
305385 .fn_noreturn_no_args,
386 .fn_void_no_args,
306387 .fn_naked_noreturn_no_args,
307388 .fn_ccc_void_no_args,
308389 .single_const_pointer_to_comptime_int,
......@@ -333,6 +414,7 @@ pub const Type = extern union {
333414 .i8,
334415 .bool,
335416 .fn_noreturn_no_args, // represents machine code; not a pointer
417 .fn_void_no_args, // represents machine code; not a pointer
336418 .fn_naked_noreturn_no_args, // represents machine code; not a pointer
337419 .fn_ccc_void_no_args, // represents machine code; not a pointer
338420 .array_u8_sentinel_0,
......@@ -420,6 +502,7 @@ pub const Type = extern union {
420502 .array_u8_sentinel_0,
421503 .const_slice_u8,
422504 .fn_noreturn_no_args,
505 .fn_void_no_args,
423506 .fn_naked_noreturn_no_args,
424507 .fn_ccc_void_no_args,
425508 .int_unsigned,
......@@ -466,6 +549,7 @@ pub const Type = extern union {
466549 .single_const_pointer,
467550 .single_const_pointer_to_comptime_int,
468551 .fn_noreturn_no_args,
552 .fn_void_no_args,
469553 .fn_naked_noreturn_no_args,
470554 .fn_ccc_void_no_args,
471555 .int_unsigned,
......@@ -509,6 +593,7 @@ pub const Type = extern union {
509593 .array,
510594 .array_u8_sentinel_0,
511595 .fn_noreturn_no_args,
596 .fn_void_no_args,
512597 .fn_naked_noreturn_no_args,
513598 .fn_ccc_void_no_args,
514599 .int_unsigned,
......@@ -553,6 +638,7 @@ pub const Type = extern union {
553638 .@"null",
554639 .@"undefined",
555640 .fn_noreturn_no_args,
641 .fn_void_no_args,
556642 .fn_naked_noreturn_no_args,
557643 .fn_ccc_void_no_args,
558644 .int_unsigned,
......@@ -597,6 +683,7 @@ pub const Type = extern union {
597683 .@"null",
598684 .@"undefined",
599685 .fn_noreturn_no_args,
686 .fn_void_no_args,
600687 .fn_naked_noreturn_no_args,
601688 .fn_ccc_void_no_args,
602689 .single_const_pointer,
......@@ -642,6 +729,7 @@ pub const Type = extern union {
642729 .@"null",
643730 .@"undefined",
644731 .fn_noreturn_no_args,
732 .fn_void_no_args,
645733 .fn_naked_noreturn_no_args,
646734 .fn_ccc_void_no_args,
647735 .single_const_pointer,
......@@ -675,6 +763,7 @@ pub const Type = extern union {
675763 .@"null",
676764 .@"undefined",
677765 .fn_noreturn_no_args,
766 .fn_void_no_args,
678767 .fn_naked_noreturn_no_args,
679768 .fn_ccc_void_no_args,
680769 .array,
......@@ -721,6 +810,7 @@ pub const Type = extern union {
721810 .@"null",
722811 .@"undefined",
723812 .fn_noreturn_no_args,
813 .fn_void_no_args,
724814 .fn_naked_noreturn_no_args,
725815 .fn_ccc_void_no_args,
726816 .array,
......@@ -777,6 +867,7 @@ pub const Type = extern union {
777867 pub fn fnParamLen(self: Type) usize {
778868 return switch (self.tag()) {
779869 .fn_noreturn_no_args => 0,
870 .fn_void_no_args => 0,
780871 .fn_naked_noreturn_no_args => 0,
781872 .fn_ccc_void_no_args => 0,
782873
......@@ -823,6 +914,7 @@ pub const Type = extern union {
823914 pub fn fnParamTypes(self: Type, types: []Type) void {
824915 switch (self.tag()) {
825916 .fn_noreturn_no_args => return,
917 .fn_void_no_args => return,
826918 .fn_naked_noreturn_no_args => return,
827919 .fn_ccc_void_no_args => return,
828920
......@@ -869,7 +961,10 @@ pub const Type = extern union {
869961 return switch (self.tag()) {
870962 .fn_noreturn_no_args => Type.initTag(.noreturn),
871963 .fn_naked_noreturn_no_args => Type.initTag(.noreturn),
872 .fn_ccc_void_no_args => Type.initTag(.void),
964
965 .fn_void_no_args,
966 .fn_ccc_void_no_args,
967 => Type.initTag(.void),
873968
874969 .f16,
875970 .f32,
......@@ -913,6 +1008,7 @@ pub const Type = extern union {
9131008 pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {
9141009 return switch (self.tag()) {
9151010 .fn_noreturn_no_args => .Unspecified,
1011 .fn_void_no_args => .Unspecified,
9161012 .fn_naked_noreturn_no_args => .Naked,
9171013 .fn_ccc_void_no_args => .C,
9181014
......@@ -958,6 +1054,7 @@ pub const Type = extern union {
9581054 pub fn fnIsVarArgs(self: Type) bool {
9591055 return switch (self.tag()) {
9601056 .fn_noreturn_no_args => false,
1057 .fn_void_no_args => false,
9611058 .fn_naked_noreturn_no_args => false,
9621059 .fn_ccc_void_no_args => false,
9631060
......@@ -1033,6 +1130,7 @@ pub const Type = extern union {
10331130 .@"null",
10341131 .@"undefined",
10351132 .fn_noreturn_no_args,
1133 .fn_void_no_args,
10361134 .fn_naked_noreturn_no_args,
10371135 .fn_ccc_void_no_args,
10381136 .array,
......@@ -1070,6 +1168,7 @@ pub const Type = extern union {
10701168 .type,
10711169 .anyerror,
10721170 .fn_noreturn_no_args,
1171 .fn_void_no_args,
10731172 .fn_naked_noreturn_no_args,
10741173 .fn_ccc_void_no_args,
10751174 .single_const_pointer_to_comptime_int,
......@@ -1126,6 +1225,7 @@ pub const Type = extern union {
11261225 .type,
11271226 .anyerror,
11281227 .fn_noreturn_no_args,
1228 .fn_void_no_args,
11291229 .fn_naked_noreturn_no_args,
11301230 .fn_ccc_void_no_args,
11311231 .single_const_pointer_to_comptime_int,
......@@ -1180,6 +1280,7 @@ pub const Type = extern union {
11801280 @"null",
11811281 @"undefined",
11821282 fn_noreturn_no_args,
1283 fn_void_no_args,
11831284 fn_naked_noreturn_no_args,
11841285 fn_ccc_void_no_args,
11851286 single_const_pointer_to_comptime_int,
src-self-hosted/value.zig+117-7
......@@ -49,6 +49,7 @@ pub const Value = extern union {
4949 null_type,
5050 undefined_type,
5151 fn_noreturn_no_args_type,
52 fn_void_no_args_type,
5253 fn_naked_noreturn_no_args_type,
5354 fn_ccc_void_no_args_type,
5455 single_const_pointer_to_comptime_int_type,
......@@ -78,8 +79,8 @@ pub const Value = extern union {
7879 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
7980 };
8081
81 pub fn initTag(comptime small_tag: Tag) Value {
82 comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);
82 pub fn initTag(small_tag: Tag) Value {
83 assert(@enumToInt(small_tag) < Tag.no_payload_count);
8384 return .{ .tag_if_small_enough = @enumToInt(small_tag) };
8485 }
8586
......@@ -107,6 +108,109 @@ pub const Value = extern union {
107108 return @fieldParentPtr(T, "base", self.ptr_otherwise);
108109 }
109110
111 pub fn copy(self: Value, allocator: *Allocator) error{OutOfMemory}!Value {
112 if (self.tag_if_small_enough < Tag.no_payload_count) {
113 return Value{ .tag_if_small_enough = self.tag_if_small_enough };
114 } else switch (self.ptr_otherwise.tag) {
115 .u8_type,
116 .i8_type,
117 .isize_type,
118 .usize_type,
119 .c_short_type,
120 .c_ushort_type,
121 .c_int_type,
122 .c_uint_type,
123 .c_long_type,
124 .c_ulong_type,
125 .c_longlong_type,
126 .c_ulonglong_type,
127 .c_longdouble_type,
128 .f16_type,
129 .f32_type,
130 .f64_type,
131 .f128_type,
132 .c_void_type,
133 .bool_type,
134 .void_type,
135 .type_type,
136 .anyerror_type,
137 .comptime_int_type,
138 .comptime_float_type,
139 .noreturn_type,
140 .null_type,
141 .undefined_type,
142 .fn_noreturn_no_args_type,
143 .fn_void_no_args_type,
144 .fn_naked_noreturn_no_args_type,
145 .fn_ccc_void_no_args_type,
146 .single_const_pointer_to_comptime_int_type,
147 .const_slice_u8_type,
148 .undef,
149 .zero,
150 .the_one_possible_value,
151 .null_value,
152 .bool_true,
153 .bool_false,
154 => unreachable,
155
156 .ty => {
157 const payload = @fieldParentPtr(Payload.Ty, "base", self.ptr_otherwise);
158 const new_payload = try allocator.create(Payload.Ty);
159 new_payload.* = .{
160 .base = payload.base,
161 .ty = try payload.ty.copy(allocator),
162 };
163 return Value{ .ptr_otherwise = &new_payload.base };
164 },
165 .int_u64 => return self.copyPayloadShallow(allocator, Payload.Int_u64),
166 .int_i64 => return self.copyPayloadShallow(allocator, Payload.Int_i64),
167 .int_big_positive => {
168 @panic("TODO implement copying of big ints");
169 },
170 .int_big_negative => {
171 @panic("TODO implement copying of big ints");
172 },
173 .function => return self.copyPayloadShallow(allocator, Payload.Function),
174 .ref_val => {
175 const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
176 const new_payload = try allocator.create(Payload.RefVal);
177 new_payload.* = .{
178 .base = payload.base,
179 .val = try payload.val.copy(allocator),
180 };
181 return Value{ .ptr_otherwise = &new_payload.base };
182 },
183 .decl_ref => return self.copyPayloadShallow(allocator, Payload.DeclRef),
184 .elem_ptr => {
185 const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise);
186 const new_payload = try allocator.create(Payload.ElemPtr);
187 new_payload.* = .{
188 .base = payload.base,
189 .array_ptr = try payload.array_ptr.copy(allocator),
190 .index = payload.index,
191 };
192 return Value{ .ptr_otherwise = &new_payload.base };
193 },
194 .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
195 .repeated => {
196 const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
197 const new_payload = try allocator.create(Payload.Repeated);
198 new_payload.* = .{
199 .base = payload.base,
200 .val = try payload.val.copy(allocator),
201 };
202 return Value{ .ptr_otherwise = &new_payload.base };
203 },
204 }
205 }
206
207 fn copyPayloadShallow(self: Value, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Value {
208 const payload = @fieldParentPtr(T, "base", self.ptr_otherwise);
209 const new_payload = try allocator.create(T);
210 new_payload.* = payload.*;
211 return Value{ .ptr_otherwise = &new_payload.base };
212 }
213
110214 pub fn format(
111215 self: Value,
112216 comptime fmt: []const u8,
......@@ -144,6 +248,7 @@ pub const Value = extern union {
144248 .null_type => return out_stream.writeAll("@TypeOf(null)"),
145249 .undefined_type => return out_stream.writeAll("@TypeOf(undefined)"),
146250 .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"),
251 .fn_void_no_args_type => return out_stream.writeAll("fn() void"),
147252 .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
148253 .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
149254 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
......@@ -229,6 +334,7 @@ pub const Value = extern union {
229334 .null_type => Type.initTag(.@"null"),
230335 .undefined_type => Type.initTag(.@"undefined"),
231336 .fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args),
337 .fn_void_no_args_type => Type.initTag(.fn_void_no_args),
232338 .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),
233339 .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),
234340 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
......@@ -286,6 +392,7 @@ pub const Value = extern union {
286392 .null_type,
287393 .undefined_type,
288394 .fn_noreturn_no_args_type,
395 .fn_void_no_args_type,
289396 .fn_naked_noreturn_no_args_type,
290397 .fn_ccc_void_no_args_type,
291398 .single_const_pointer_to_comptime_int_type,
......@@ -345,6 +452,7 @@ pub const Value = extern union {
345452 .null_type,
346453 .undefined_type,
347454 .fn_noreturn_no_args_type,
455 .fn_void_no_args_type,
348456 .fn_naked_noreturn_no_args_type,
349457 .fn_ccc_void_no_args_type,
350458 .single_const_pointer_to_comptime_int_type,
......@@ -405,6 +513,7 @@ pub const Value = extern union {
405513 .null_type,
406514 .undefined_type,
407515 .fn_noreturn_no_args_type,
516 .fn_void_no_args_type,
408517 .fn_naked_noreturn_no_args_type,
409518 .fn_ccc_void_no_args_type,
410519 .single_const_pointer_to_comptime_int_type,
......@@ -470,6 +579,7 @@ pub const Value = extern union {
470579 .null_type,
471580 .undefined_type,
472581 .fn_noreturn_no_args_type,
582 .fn_void_no_args_type,
473583 .fn_naked_noreturn_no_args_type,
474584 .fn_ccc_void_no_args_type,
475585 .single_const_pointer_to_comptime_int_type,
......@@ -564,6 +674,7 @@ pub const Value = extern union {
564674 .null_type,
565675 .undefined_type,
566676 .fn_noreturn_no_args_type,
677 .fn_void_no_args_type,
567678 .fn_naked_noreturn_no_args_type,
568679 .fn_ccc_void_no_args_type,
569680 .single_const_pointer_to_comptime_int_type,
......@@ -620,6 +731,7 @@ pub const Value = extern union {
620731 .null_type,
621732 .undefined_type,
622733 .fn_noreturn_no_args_type,
734 .fn_void_no_args_type,
623735 .fn_naked_noreturn_no_args_type,
624736 .fn_ccc_void_no_args_type,
625737 .single_const_pointer_to_comptime_int_type,
......@@ -721,6 +833,7 @@ pub const Value = extern union {
721833 .null_type,
722834 .undefined_type,
723835 .fn_noreturn_no_args_type,
836 .fn_void_no_args_type,
724837 .fn_naked_noreturn_no_args_type,
725838 .fn_ccc_void_no_args_type,
726839 .single_const_pointer_to_comptime_int_type,
......@@ -783,6 +896,7 @@ pub const Value = extern union {
783896 .null_type,
784897 .undefined_type,
785898 .fn_noreturn_no_args_type,
899 .fn_void_no_args_type,
786900 .fn_naked_noreturn_no_args_type,
787901 .fn_ccc_void_no_args_type,
788902 .single_const_pointer_to_comptime_int_type,
......@@ -862,6 +976,7 @@ pub const Value = extern union {
862976 .null_type,
863977 .undefined_type,
864978 .fn_noreturn_no_args_type,
979 .fn_void_no_args_type,
865980 .fn_naked_noreturn_no_args_type,
866981 .fn_ccc_void_no_args_type,
867982 .single_const_pointer_to_comptime_int_type,
......@@ -929,11 +1044,6 @@ pub const Value = extern union {
9291044 len: u64,
9301045 };
9311046
932 pub const SingleConstPtrType = struct {
933 base: Payload = Payload{ .tag = .single_const_ptr_type },
934 elem_type: *Type,
935 };
936
9371047 /// Represents a pointer to another immutable value.
9381048 pub const RefVal = struct {
9391049 base: Payload = Payload{ .tag = .ref_val },
src-self-hosted/zir.zig+287-181
......@@ -12,27 +12,43 @@ const TypedValue = @import("TypedValue.zig");
1212const ir = @import("ir.zig");
1313const IrModule = @import("Module.zig");
1414
15/// This struct is relevent only for the ZIR Module text format. It is not used for
16/// semantic analysis of Zig source code.
17pub const Decl = struct {
18 name: []const u8,
19
20 /// Hash of slice into the source of the part after the = and before the next instruction.
21 contents_hash: std.zig.SrcHash,
22
23 inst: *Inst,
24};
25
1526/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for
1627/// in-memory, analyzed instructions with types and values.
1728pub const Inst = struct {
1829 tag: Tag,
1930 /// Byte offset into the source.
2031 src: usize,
21 name: []const u8,
22
23 /// Slice into the source of the part after the = and before the next instruction.
24 contents: []const u8 = &[0]u8{},
32 /// Pre-allocated field for mapping ZIR text instructions to post-analysis instructions.
33 analyzed_inst: ?*ir.Inst = null,
2534
2635 /// These names are used directly as the instruction names in the text format.
2736 pub const Tag = enum {
2837 breakpoint,
2938 call,
3039 compileerror,
40 /// Special case, has no textual representation.
41 @"const",
3142 /// Represents a pointer to a global decl by name.
3243 declref,
44 /// Represents a pointer to a global decl by string name.
45 declref_str,
3346 /// The syntax `@foo` is equivalent to `declval("foo")`.
3447 /// declval is equivalent to declref followed by deref.
3548 declval,
49 /// Same as declval but the parameter is a `*Module.Decl` rather than a name.
50 declval_in_module,
51 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
3652 str,
3753 int,
3854 ptrtoint,
......@@ -42,11 +58,11 @@ pub const Inst = struct {
4258 @"asm",
4359 @"unreachable",
4460 @"return",
61 returnvoid,
4562 @"fn",
63 fntype,
4664 @"export",
4765 primitive,
48 ref,
49 fntype,
5066 intcast,
5167 bitcast,
5268 elemptr,
......@@ -62,8 +78,11 @@ pub const Inst = struct {
6278 .breakpoint => Breakpoint,
6379 .call => Call,
6480 .declref => DeclRef,
81 .declref_str => DeclRefStr,
6582 .declval => DeclVal,
83 .declval_in_module => DeclValInModule,
6684 .compileerror => CompileError,
85 .@"const" => Const,
6786 .str => Str,
6887 .int => Int,
6988 .ptrtoint => PtrToInt,
......@@ -73,10 +92,10 @@ pub const Inst = struct {
7392 .@"asm" => Asm,
7493 .@"unreachable" => Unreachable,
7594 .@"return" => Return,
95 .returnvoid => ReturnVoid,
7696 .@"fn" => Fn,
7797 .@"export" => Export,
7898 .primitive => Primitive,
79 .ref => Ref,
8099 .fntype => FnType,
81100 .intcast => IntCast,
82101 .bitcast => BitCast,
......@@ -121,6 +140,16 @@ pub const Inst = struct {
121140 pub const base_tag = Tag.declref;
122141 base: Inst,
123142
143 positionals: struct {
144 name: []const u8,
145 },
146 kw_args: struct {},
147 };
148
149 pub const DeclRefStr = struct {
150 pub const base_tag = Tag.declref_str;
151 base: Inst,
152
124153 positionals: struct {
125154 name: *Inst,
126155 },
......@@ -137,6 +166,16 @@ pub const Inst = struct {
137166 kw_args: struct {},
138167 };
139168
169 pub const DeclValInModule = struct {
170 pub const base_tag = Tag.declval_in_module;
171 base: Inst,
172
173 positionals: struct {
174 decl: *IrModule.Decl,
175 },
176 kw_args: struct {},
177 };
178
140179 pub const CompileError = struct {
141180 pub const base_tag = Tag.compileerror;
142181 base: Inst,
......@@ -147,6 +186,16 @@ pub const Inst = struct {
147186 kw_args: struct {},
148187 };
149188
189 pub const Const = struct {
190 pub const base_tag = Tag.@"const";
191 base: Inst,
192
193 positionals: struct {
194 typed_value: TypedValue,
195 },
196 kw_args: struct {},
197 };
198
150199 pub const Str = struct {
151200 pub const base_tag = Tag.str;
152201 base: Inst,
......@@ -168,6 +217,7 @@ pub const Inst = struct {
168217 };
169218
170219 pub const PtrToInt = struct {
220 pub const builtin_name = "@ptrToInt";
171221 pub const base_tag = Tag.ptrtoint;
172222 base: Inst,
173223
......@@ -238,6 +288,16 @@ pub const Inst = struct {
238288 pub const base_tag = Tag.@"return";
239289 base: Inst,
240290
291 positionals: struct {
292 operand: *Inst,
293 },
294 kw_args: struct {},
295 };
296
297 pub const ReturnVoid = struct {
298 pub const base_tag = Tag.returnvoid;
299 base: Inst,
300
241301 positionals: struct {},
242302 kw_args: struct {},
243303 };
......@@ -253,23 +313,26 @@ pub const Inst = struct {
253313 kw_args: struct {},
254314 };
255315
256 pub const Export = struct {
257 pub const base_tag = Tag.@"export";
316 pub const FnType = struct {
317 pub const base_tag = Tag.fntype;
258318 base: Inst,
259319
260320 positionals: struct {
261 symbol_name: *Inst,
262 value: *Inst,
321 param_types: []*Inst,
322 return_type: *Inst,
323 },
324 kw_args: struct {
325 cc: std.builtin.CallingConvention = .Unspecified,
263326 },
264 kw_args: struct {},
265327 };
266328
267 pub const Ref = struct {
268 pub const base_tag = Tag.ref;
329 pub const Export = struct {
330 pub const base_tag = Tag.@"export";
269331 base: Inst,
270332
271333 positionals: struct {
272 operand: *Inst,
334 symbol_name: *Inst,
335 decl_name: []const u8,
273336 },
274337 kw_args: struct {},
275338 };
......@@ -348,19 +411,6 @@ pub const Inst = struct {
348411 };
349412 };
350413
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
364414 pub const IntCast = struct {
365415 pub const base_tag = Tag.intcast;
366416 base: Inst,
......@@ -456,7 +506,7 @@ pub const ErrorMsg = struct {
456506};
457507
458508pub const Module = struct {
459 decls: []*Inst,
509 decls: []*Decl,
460510 arena: std.heap.ArenaAllocator,
461511 error_msg: ?ErrorMsg = null,
462512
......@@ -475,13 +525,33 @@ pub const Module = struct {
475525 self.writeToStream(std.heap.page_allocator, std.io.getStdErr().outStream()) catch {};
476526 }
477527
478 const InstPtrTable = std.AutoHashMap(*Inst, struct { inst: *Inst, index: ?usize });
528 const InstPtrTable = std.AutoHashMap(*Inst, struct { inst: *Inst, index: ?usize, name: []const u8 });
529
530 const DeclAndIndex = struct {
531 decl: *Decl,
532 index: usize,
533 };
479534
480535 /// TODO Look into making a table to speed this up.
481 pub fn findDecl(self: Module, name: []const u8) ?*Inst {
482 for (self.decls) |decl| {
536 pub fn findDecl(self: Module, name: []const u8) ?DeclAndIndex {
537 for (self.decls) |decl, i| {
483538 if (mem.eql(u8, decl.name, name)) {
484 return decl;
539 return DeclAndIndex{
540 .decl = decl,
541 .index = i,
542 };
543 }
544 }
545 return null;
546 }
547
548 pub fn findInstDecl(self: Module, inst: *Inst) ?DeclAndIndex {
549 for (self.decls) |decl, i| {
550 if (decl.inst == inst) {
551 return DeclAndIndex{
552 .decl = decl,
553 .index = i,
554 };
485555 }
486556 }
487557 return null;
......@@ -497,18 +567,18 @@ pub const Module = struct {
497567 try inst_table.ensureCapacity(self.decls.len);
498568
499569 for (self.decls) |decl, decl_i| {
500 try inst_table.putNoClobber(decl, .{ .inst = decl, .index = null });
570 try inst_table.putNoClobber(decl.inst, .{ .inst = decl.inst, .index = null, .name = decl.name });
501571
502 if (decl.cast(Inst.Fn)) |fn_inst| {
572 if (decl.inst.cast(Inst.Fn)) |fn_inst| {
503573 for (fn_inst.positionals.body.instructions) |inst, inst_i| {
504 try inst_table.putNoClobber(inst, .{ .inst = inst, .index = inst_i });
574 try inst_table.putNoClobber(inst, .{ .inst = inst, .index = inst_i, .name = undefined });
505575 }
506576 }
507577 }
508578
509579 for (self.decls) |decl, i| {
510580 try stream.print("@{} ", .{decl.name});
511 try self.writeInstToStream(stream, decl, &inst_table);
581 try self.writeInstToStream(stream, decl.inst, &inst_table);
512582 try stream.writeByte('\n');
513583 }
514584 }
......@@ -516,38 +586,41 @@ pub const Module = struct {
516586 fn writeInstToStream(
517587 self: Module,
518588 stream: var,
519 decl: *Inst,
589 inst: *Inst,
520590 inst_table: *const InstPtrTable,
521591 ) @TypeOf(stream).Error!void {
522592 // TODO I tried implementing this with an inline for loop and hit a compiler bug
523 switch (decl.tag) {
524 .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, decl, inst_table),
525 .call => return self.writeInstToStreamGeneric(stream, .call, decl, inst_table),
526 .declref => return self.writeInstToStreamGeneric(stream, .declref, decl, inst_table),
527 .declval => return self.writeInstToStreamGeneric(stream, .declval, decl, inst_table),
528 .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, decl, inst_table),
529 .str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table),
530 .int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table),
531 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table),
532 .fieldptr => return self.writeInstToStreamGeneric(stream, .fieldptr, decl, inst_table),
533 .deref => return self.writeInstToStreamGeneric(stream, .deref, decl, inst_table),
534 .as => return self.writeInstToStreamGeneric(stream, .as, decl, inst_table),
535 .@"asm" => return self.writeInstToStreamGeneric(stream, .@"asm", decl, inst_table),
536 .@"unreachable" => return self.writeInstToStreamGeneric(stream, .@"unreachable", decl, inst_table),
537 .@"return" => return self.writeInstToStreamGeneric(stream, .@"return", decl, inst_table),
538 .@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", decl, inst_table),
539 .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", decl, inst_table),
540 .ref => return self.writeInstToStreamGeneric(stream, .ref, decl, inst_table),
541 .primitive => return self.writeInstToStreamGeneric(stream, .primitive, decl, inst_table),
542 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, decl, inst_table),
543 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, decl, inst_table),
544 .bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, decl, inst_table),
545 .elemptr => return self.writeInstToStreamGeneric(stream, .elemptr, decl, inst_table),
546 .add => return self.writeInstToStreamGeneric(stream, .add, decl, inst_table),
547 .cmp => return self.writeInstToStreamGeneric(stream, .cmp, decl, inst_table),
548 .condbr => return self.writeInstToStreamGeneric(stream, .condbr, decl, inst_table),
549 .isnull => return self.writeInstToStreamGeneric(stream, .isnull, decl, inst_table),
550 .isnonnull => return self.writeInstToStreamGeneric(stream, .isnonnull, decl, inst_table),
593 switch (inst.tag) {
594 .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, inst, inst_table),
595 .call => return self.writeInstToStreamGeneric(stream, .call, inst, inst_table),
596 .declref => return self.writeInstToStreamGeneric(stream, .declref, inst, inst_table),
597 .declref_str => return self.writeInstToStreamGeneric(stream, .declref_str, inst, inst_table),
598 .declval => return self.writeInstToStreamGeneric(stream, .declval, inst, inst_table),
599 .declval_in_module => return self.writeInstToStreamGeneric(stream, .declval_in_module, inst, inst_table),
600 .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, inst, inst_table),
601 .@"const" => return self.writeInstToStreamGeneric(stream, .@"const", inst, inst_table),
602 .str => return self.writeInstToStreamGeneric(stream, .str, inst, inst_table),
603 .int => return self.writeInstToStreamGeneric(stream, .int, inst, inst_table),
604 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, inst, inst_table),
605 .fieldptr => return self.writeInstToStreamGeneric(stream, .fieldptr, inst, inst_table),
606 .deref => return self.writeInstToStreamGeneric(stream, .deref, inst, inst_table),
607 .as => return self.writeInstToStreamGeneric(stream, .as, inst, inst_table),
608 .@"asm" => return self.writeInstToStreamGeneric(stream, .@"asm", inst, inst_table),
609 .@"unreachable" => return self.writeInstToStreamGeneric(stream, .@"unreachable", inst, inst_table),
610 .@"return" => return self.writeInstToStreamGeneric(stream, .@"return", inst, inst_table),
611 .returnvoid => return self.writeInstToStreamGeneric(stream, .returnvoid, inst, inst_table),
612 .@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", inst, inst_table),
613 .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", inst, inst_table),
614 .primitive => return self.writeInstToStreamGeneric(stream, .primitive, inst, inst_table),
615 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, inst, inst_table),
616 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, inst, inst_table),
617 .bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, inst, inst_table),
618 .elemptr => return self.writeInstToStreamGeneric(stream, .elemptr, inst, inst_table),
619 .add => return self.writeInstToStreamGeneric(stream, .add, inst, inst_table),
620 .cmp => return self.writeInstToStreamGeneric(stream, .cmp, inst, inst_table),
621 .condbr => return self.writeInstToStreamGeneric(stream, .condbr, inst, inst_table),
622 .isnull => return self.writeInstToStreamGeneric(stream, .isnull, inst, inst_table),
623 .isnonnull => return self.writeInstToStreamGeneric(stream, .isnonnull, inst, inst_table),
551624 }
552625 }
553626
......@@ -619,6 +692,8 @@ pub const Module = struct {
619692 bool => return stream.writeByte("01"[@boolToInt(param)]),
620693 []u8, []const u8 => return std.zig.renderStringLiteral(param, stream),
621694 BigIntConst => return stream.print("{}", .{param}),
695 TypedValue => unreachable, // this is a special case
696 *IrModule.Decl => unreachable, // this is a special case
622697 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
623698 }
624699 }
......@@ -628,13 +703,16 @@ pub const Module = struct {
628703 if (info.index) |i| {
629704 try stream.print("%{}", .{info.index});
630705 } else {
631 try stream.print("@{}", .{info.inst.name});
706 try stream.print("@{}", .{info.name});
632707 }
633708 } else if (inst.cast(Inst.DeclVal)) |decl_val| {
634709 try stream.print("@{}", .{decl_val.positionals.name});
710 } else if (inst.cast(Inst.DeclValInModule)) |decl_val| {
711 try stream.print("@{}", .{decl_val.positionals.decl.name});
635712 } else {
636 //try stream.print("?", .{});
637 unreachable;
713 // This should be unreachable in theory, but since ZIR is used for debugging the compiler
714 // we output some debug text instead.
715 try stream.print("?{}?", .{@tagName(inst.tag)});
638716 }
639717 }
640718};
......@@ -673,7 +751,7 @@ const Parser = struct {
673751 arena: std.heap.ArenaAllocator,
674752 i: usize,
675753 source: [:0]const u8,
676 decls: std.ArrayListUnmanaged(*Inst),
754 decls: std.ArrayListUnmanaged(*Decl),
677755 global_name_map: *std.StringHashMap(usize),
678756 error_msg: ?ErrorMsg = null,
679757 unnamed_index: usize,
......@@ -702,12 +780,12 @@ const Parser = struct {
702780 skipSpace(self);
703781 try requireEatBytes(self, "=");
704782 skipSpace(self);
705 const inst = try parseInstruction(self, &body_context, ident);
783 const decl = try parseInstruction(self, &body_context, ident);
706784 const ident_index = body_context.instructions.items.len;
707785 if (try body_context.name_map.put(ident, ident_index)) |_| {
708786 return self.fail("redefinition of identifier '{}'", .{ident});
709787 }
710 try body_context.instructions.append(inst);
788 try body_context.instructions.append(decl.inst);
711789 continue;
712790 },
713791 ' ', '\n' => continue,
......@@ -857,7 +935,7 @@ const Parser = struct {
857935 return error.ParseFailure;
858936 }
859937
860 fn parseInstruction(self: *Parser, body_ctx: ?*Body, name: []const u8) InnerError!*Inst {
938 fn parseInstruction(self: *Parser, body_ctx: ?*Body, name: []const u8) InnerError!*Decl {
861939 const contents_start = self.i;
862940 const fn_name = try skipToAndOver(self, '(');
863941 inline for (@typeInfo(Inst.Tag).Enum.fields) |field| {
......@@ -876,10 +954,9 @@ const Parser = struct {
876954 body_ctx: ?*Body,
877955 inst_name: []const u8,
878956 contents_start: usize,
879 ) InnerError!*Inst {
957 ) InnerError!*Decl {
880958 const inst_specific = try self.arena.allocator.create(InstType);
881959 inst_specific.base = .{
882 .name = inst_name,
883960 .src = self.i,
884961 .tag = InstType.base_tag,
885962 };
......@@ -929,10 +1006,15 @@ const Parser = struct {
9291006 }
9301007 try requireEatBytes(self, ")");
9311008
932 inst_specific.base.contents = self.source[contents_start..self.i];
1009 const decl = try self.arena.allocator.create(Decl);
1010 decl.* = .{
1011 .name = inst_name,
1012 .contents_hash = std.zig.hashSrc(self.source[contents_start..self.i]),
1013 .inst = &inst_specific.base,
1014 };
9331015 //std.debug.warn("parsed {} = '{}'\n", .{ inst_specific.base.name, inst_specific.base.contents });
9341016
935 return &inst_specific.base;
1017 return decl;
9361018 }
9371019
9381020 fn parseParameterGeneric(self: *Parser, comptime T: type, body_ctx: ?*Body) !T {
......@@ -978,6 +1060,8 @@ const Parser = struct {
9781060 *Inst => return parseParameterInst(self, body_ctx),
9791061 []u8, []const u8 => return self.parseStringLiteral(),
9801062 BigIntConst => return self.parseIntegerLiteral(),
1063 TypedValue => return self.fail("'const' is a special instruction; not legal in ZIR text", .{}),
1064 *IrModule.Decl => return self.fail("'declval_in_module' is a special instruction; not legal in ZIR text", .{}),
9811065 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
9821066 }
9831067 return self.fail("TODO parse parameter {}", .{@typeName(T)});
......@@ -1014,7 +1098,6 @@ const Parser = struct {
10141098 const declval = try self.arena.allocator.create(Inst.DeclVal);
10151099 declval.* = .{
10161100 .base = .{
1017 .name = try self.generateName(),
10181101 .src = src,
10191102 .tag = Inst.DeclVal.base_tag,
10201103 },
......@@ -1027,7 +1110,7 @@ const Parser = struct {
10271110 if (local_ref) {
10281111 return body_ctx.?.instructions.items[kv.value];
10291112 } else {
1030 return self.decls.items[kv.value];
1113 return self.decls.items[kv.value].inst;
10311114 }
10321115 }
10331116
......@@ -1046,7 +1129,7 @@ pub fn emit(allocator: *Allocator, old_module: IrModule) !Module {
10461129 .old_module = &old_module,
10471130 .next_auto_name = 0,
10481131 .names = std.StringHashMap(void).init(allocator),
1049 .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Inst).init(allocator),
1132 .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),
10501133 };
10511134 defer ctx.decls.deinit(allocator);
10521135 defer ctx.names.deinit();
......@@ -1065,10 +1148,10 @@ const EmitZIR = struct {
10651148 allocator: *Allocator,
10661149 arena: std.heap.ArenaAllocator,
10671150 old_module: *const IrModule,
1068 decls: std.ArrayListUnmanaged(*Inst),
1151 decls: std.ArrayListUnmanaged(*Decl),
10691152 names: std.StringHashMap(void),
10701153 next_auto_name: usize,
1071 primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Inst),
1154 primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Decl),
10721155
10731156 fn emit(self: *EmitZIR) !void {
10741157 // Put all the Decls in a list and sort them by name to avoid nondeterminism introduced
......@@ -1087,52 +1170,90 @@ const EmitZIR = struct {
10871170 }
10881171 std.sort.sort(*IrModule.Decl, src_decls.items, {}, (struct {
10891172 fn lessThan(context: void, a: *IrModule.Decl, b: *IrModule.Decl) bool {
1090 return a.src < b.src;
1173 return a.src_index < b.src_index;
10911174 }
10921175 }).lessThan);
10931176
10941177 // Emit all the decls.
10951178 for (src_decls.items) |ir_decl| {
1179 switch (ir_decl.analysis) {
1180 .unreferenced => continue,
1181 .complete => {},
1182 .in_progress => unreachable,
1183 .outdated => unreachable,
1184
1185 .sema_failure,
1186 .sema_failure_retryable,
1187 .codegen_failure,
1188 .dependency_failure,
1189 .codegen_failure_retryable,
1190 => if (self.old_module.failed_decls.getValue(ir_decl)) |err_msg| {
1191 const fail_inst = try self.arena.allocator.create(Inst.CompileError);
1192 fail_inst.* = .{
1193 .base = .{
1194 .src = ir_decl.src(),
1195 .tag = Inst.CompileError.base_tag,
1196 },
1197 .positionals = .{
1198 .msg = try self.arena.allocator.dupe(u8, err_msg.msg),
1199 },
1200 .kw_args = .{},
1201 };
1202 const decl = try self.arena.allocator.create(Decl);
1203 decl.* = .{
1204 .name = mem.spanZ(ir_decl.name),
1205 .contents_hash = undefined,
1206 .inst = &fail_inst.base,
1207 };
1208 try self.decls.append(self.allocator, decl);
1209 continue;
1210 },
1211 }
10961212 if (self.old_module.export_owners.getValue(ir_decl)) |exports| {
10971213 for (exports) |module_export| {
1098 const declval = try self.emitDeclVal(ir_decl.src, mem.spanZ(module_export.exported_decl.name));
10991214 const symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name);
11001215 const export_inst = try self.arena.allocator.create(Inst.Export);
11011216 export_inst.* = .{
11021217 .base = .{
1103 .name = try self.autoName(),
11041218 .src = module_export.src,
11051219 .tag = Inst.Export.base_tag,
11061220 },
11071221 .positionals = .{
1108 .symbol_name = symbol_name,
1109 .value = declval,
1222 .symbol_name = symbol_name.inst,
1223 .decl_name = mem.spanZ(module_export.exported_decl.name),
11101224 },
11111225 .kw_args = .{},
11121226 };
1113 try self.decls.append(self.allocator, &export_inst.base);
1227 _ = try self.emitUnnamedDecl(&export_inst.base);
11141228 }
11151229 } else {
1116 const new_decl = try self.emitTypedValue(ir_decl.src, ir_decl.typed_value.most_recent.typed_value);
1230 const new_decl = try self.emitTypedValue(ir_decl.src(), ir_decl.typed_value.most_recent.typed_value);
11171231 new_decl.name = try self.arena.allocator.dupe(u8, mem.spanZ(ir_decl.name));
11181232 }
11191233 }
11201234 }
11211235
1122 fn resolveInst(self: *EmitZIR, inst_table: *std.AutoHashMap(*ir.Inst, *Inst), inst: *ir.Inst) !*Inst {
1236 const ZirBody = struct {
1237 inst_table: *std.AutoHashMap(*ir.Inst, *Inst),
1238 instructions: *std.ArrayList(*Inst),
1239 };
1240
1241 fn resolveInst(self: *EmitZIR, new_body: ZirBody, inst: *ir.Inst) !*Inst {
11231242 if (inst.cast(ir.Inst.Constant)) |const_inst| {
1124 const new_decl = if (const_inst.val.cast(Value.Payload.Function)) |func_pl| blk: {
1243 const new_inst = if (const_inst.val.cast(Value.Payload.Function)) |func_pl| blk: {
11251244 const owner_decl = func_pl.func.owner_decl;
11261245 break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name));
11271246 } else if (const_inst.val.cast(Value.Payload.DeclRef)) |declref| blk: {
1128 break :blk try self.emitDeclRef(inst.src, declref.decl);
1247 const decl_ref = try self.emitDeclRef(inst.src, declref.decl);
1248 try new_body.instructions.append(decl_ref);
1249 break :blk decl_ref;
11291250 } else blk: {
1130 break :blk try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val });
1251 break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst;
11311252 };
1132 try inst_table.putNoClobber(inst, new_decl);
1133 return new_decl;
1253 try new_body.inst_table.putNoClobber(inst, new_inst);
1254 return new_inst;
11341255 } else {
1135 return inst_table.getValue(inst).?;
1256 return new_body.inst_table.getValue(inst).?;
11361257 }
11371258 }
11381259
......@@ -1140,7 +1261,6 @@ const EmitZIR = struct {
11401261 const declval = try self.arena.allocator.create(Inst.DeclVal);
11411262 declval.* = .{
11421263 .base = .{
1143 .name = try self.autoName(),
11441264 .src = src,
11451265 .tag = Inst.DeclVal.base_tag,
11461266 },
......@@ -1150,12 +1270,11 @@ const EmitZIR = struct {
11501270 return &declval.base;
11511271 }
11521272
1153 fn emitComptimeIntVal(self: *EmitZIR, src: usize, val: Value) !*Inst {
1273 fn emitComptimeIntVal(self: *EmitZIR, src: usize, val: Value) !*Decl {
11541274 const big_int_space = try self.arena.allocator.create(Value.BigIntSpace);
11551275 const int_inst = try self.arena.allocator.create(Inst.Int);
11561276 int_inst.* = .{
11571277 .base = .{
1158 .name = try self.autoName(),
11591278 .src = src,
11601279 .tag = Inst.Int.base_tag,
11611280 },
......@@ -1164,34 +1283,29 @@ const EmitZIR = struct {
11641283 },
11651284 .kw_args = .{},
11661285 };
1167 try self.decls.append(self.allocator, &int_inst.base);
1168 return &int_inst.base;
1286 return self.emitUnnamedDecl(&int_inst.base);
11691287 }
11701288
1171 fn emitDeclRef(self: *EmitZIR, src: usize, decl: *IrModule.Decl) !*Inst {
1172 const declval = try self.emitDeclVal(src, mem.spanZ(decl.name));
1173 const ref_inst = try self.arena.allocator.create(Inst.Ref);
1174 ref_inst.* = .{
1289 fn emitDeclRef(self: *EmitZIR, src: usize, module_decl: *IrModule.Decl) !*Inst {
1290 const declref_inst = try self.arena.allocator.create(Inst.DeclRef);
1291 declref_inst.* = .{
11751292 .base = .{
1176 .name = try self.autoName(),
11771293 .src = src,
1178 .tag = Inst.Ref.base_tag,
1294 .tag = Inst.DeclRef.base_tag,
11791295 },
11801296 .positionals = .{
1181 .operand = declval,
1297 .name = mem.spanZ(module_decl.name),
11821298 },
11831299 .kw_args = .{},
11841300 };
1185 try self.decls.append(self.allocator, &ref_inst.base);
1186
1187 return &ref_inst.base;
1301 return &declref_inst.base;
11881302 }
11891303
1190 fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Inst {
1304 fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Decl {
11911305 const allocator = &self.arena.allocator;
11921306 if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| {
11931307 const decl = decl_ref.decl;
1194 return self.emitDeclRef(src, decl);
1308 return try self.emitUnnamedDecl(try self.emitDeclRef(src, decl));
11951309 }
11961310 switch (typed_value.ty.zigTypeTag()) {
11971311 .Pointer => {
......@@ -1218,18 +1332,16 @@ const EmitZIR = struct {
12181332 const as_inst = try self.arena.allocator.create(Inst.As);
12191333 as_inst.* = .{
12201334 .base = .{
1221 .name = try self.autoName(),
12221335 .src = src,
12231336 .tag = Inst.As.base_tag,
12241337 },
12251338 .positionals = .{
1226 .dest_type = try self.emitType(src, typed_value.ty),
1227 .value = try self.emitComptimeIntVal(src, typed_value.val),
1339 .dest_type = (try self.emitType(src, typed_value.ty)).inst,
1340 .value = (try self.emitComptimeIntVal(src, typed_value.val)).inst,
12281341 },
12291342 .kw_args = .{},
12301343 };
1231
1232 return &as_inst.base;
1344 return self.emitUnnamedDecl(&as_inst.base);
12331345 },
12341346 .Type => {
12351347 const ty = typed_value.val.toType();
......@@ -1255,7 +1367,6 @@ const EmitZIR = struct {
12551367 const fail_inst = try self.arena.allocator.create(Inst.CompileError);
12561368 fail_inst.* = .{
12571369 .base = .{
1258 .name = try self.autoName(),
12591370 .src = src,
12601371 .tag = Inst.CompileError.base_tag,
12611372 },
......@@ -1270,7 +1381,6 @@ const EmitZIR = struct {
12701381 const fail_inst = try self.arena.allocator.create(Inst.CompileError);
12711382 fail_inst.* = .{
12721383 .base = .{
1273 .name = try self.autoName(),
12741384 .src = src,
12751385 .tag = Inst.CompileError.base_tag,
12761386 },
......@@ -1283,7 +1393,7 @@ const EmitZIR = struct {
12831393 },
12841394 }
12851395
1286 const fn_type = try self.emitType(src, module_fn.fn_type);
1396 const fn_type = try self.emitType(src, typed_value.ty);
12871397
12881398 const arena_instrs = try self.arena.allocator.alloc(*Inst, instructions.items.len);
12891399 mem.copy(*Inst, arena_instrs, instructions.items);
......@@ -1291,18 +1401,16 @@ const EmitZIR = struct {
12911401 const fn_inst = try self.arena.allocator.create(Inst.Fn);
12921402 fn_inst.* = .{
12931403 .base = .{
1294 .name = try self.autoName(),
12951404 .src = src,
12961405 .tag = Inst.Fn.base_tag,
12971406 },
12981407 .positionals = .{
1299 .fn_type = fn_type,
1408 .fn_type = fn_type.inst,
13001409 .body = .{ .instructions = arena_instrs },
13011410 },
13021411 .kw_args = .{},
13031412 };
1304 try self.decls.append(self.allocator, &fn_inst.base);
1305 return &fn_inst.base;
1413 return self.emitUnnamedDecl(&fn_inst.base);
13061414 },
13071415 .Array => {
13081416 // TODO more checks to make sure this can be emitted as a string literal
......@@ -1318,7 +1426,6 @@ const EmitZIR = struct {
13181426 const str_inst = try self.arena.allocator.create(Inst.Str);
13191427 str_inst.* = .{
13201428 .base = .{
1321 .name = try self.autoName(),
13221429 .src = src,
13231430 .tag = Inst.Str.base_tag,
13241431 },
......@@ -1327,8 +1434,7 @@ const EmitZIR = struct {
13271434 },
13281435 .kw_args = .{},
13291436 };
1330 try self.decls.append(self.allocator, &str_inst.base);
1331 return &str_inst.base;
1437 return self.emitUnnamedDecl(&str_inst.base);
13321438 },
13331439 .Void => return self.emitPrimitive(src, .void_value),
13341440 else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}),
......@@ -1339,7 +1445,6 @@ const EmitZIR = struct {
13391445 const new_inst = try self.arena.allocator.create(T);
13401446 new_inst.* = .{
13411447 .base = .{
1342 .name = try self.autoName(),
13431448 .src = src,
13441449 .tag = T.base_tag,
13451450 },
......@@ -1355,6 +1460,10 @@ const EmitZIR = struct {
13551460 inst_table: *std.AutoHashMap(*ir.Inst, *Inst),
13561461 instructions: *std.ArrayList(*Inst),
13571462 ) Allocator.Error!void {
1463 const new_body = ZirBody{
1464 .inst_table = inst_table,
1465 .instructions = instructions,
1466 };
13581467 for (body.instructions) |inst| {
13591468 const new_inst = switch (inst.tag) {
13601469 .breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),
......@@ -1364,16 +1473,15 @@ const EmitZIR = struct {
13641473
13651474 const args = try self.arena.allocator.alloc(*Inst, old_inst.args.args.len);
13661475 for (args) |*elem, i| {
1367 elem.* = try self.resolveInst(inst_table, old_inst.args.args[i]);
1476 elem.* = try self.resolveInst(new_body, old_inst.args.args[i]);
13681477 }
13691478 new_inst.* = .{
13701479 .base = .{
1371 .name = try self.autoName(),
13721480 .src = inst.src,
13731481 .tag = Inst.Call.base_tag,
13741482 },
13751483 .positionals = .{
1376 .func = try self.resolveInst(inst_table, old_inst.args.func),
1484 .func = try self.resolveInst(new_body, old_inst.args.func),
13771485 .args = args,
13781486 },
13791487 .kw_args = .{},
......@@ -1381,7 +1489,22 @@ const EmitZIR = struct {
13811489 break :blk &new_inst.base;
13821490 },
13831491 .unreach => try self.emitTrivial(inst.src, Inst.Unreachable),
1384 .ret => try self.emitTrivial(inst.src, Inst.Return),
1492 .ret => blk: {
1493 const old_inst = inst.cast(ir.Inst.Ret).?;
1494 const new_inst = try self.arena.allocator.create(Inst.Return);
1495 new_inst.* = .{
1496 .base = .{
1497 .src = inst.src,
1498 .tag = Inst.Return.base_tag,
1499 },
1500 .positionals = .{
1501 .operand = try self.resolveInst(new_body, old_inst.args.operand),
1502 },
1503 .kw_args = .{},
1504 };
1505 break :blk &new_inst.base;
1506 },
1507 .retvoid => try self.emitTrivial(inst.src, Inst.ReturnVoid),
13851508 .constant => unreachable, // excluded from function bodies
13861509 .assembly => blk: {
13871510 const old_inst = inst.cast(ir.Inst.Assembly).?;
......@@ -1389,33 +1512,32 @@ const EmitZIR = struct {
13891512
13901513 const inputs = try self.arena.allocator.alloc(*Inst, old_inst.args.inputs.len);
13911514 for (inputs) |*elem, i| {
1392 elem.* = try self.emitStringLiteral(inst.src, old_inst.args.inputs[i]);
1515 elem.* = (try self.emitStringLiteral(inst.src, old_inst.args.inputs[i])).inst;
13931516 }
13941517
13951518 const clobbers = try self.arena.allocator.alloc(*Inst, old_inst.args.clobbers.len);
13961519 for (clobbers) |*elem, i| {
1397 elem.* = try self.emitStringLiteral(inst.src, old_inst.args.clobbers[i]);
1520 elem.* = (try self.emitStringLiteral(inst.src, old_inst.args.clobbers[i])).inst;
13981521 }
13991522
14001523 const args = try self.arena.allocator.alloc(*Inst, old_inst.args.args.len);
14011524 for (args) |*elem, i| {
1402 elem.* = try self.resolveInst(inst_table, old_inst.args.args[i]);
1525 elem.* = try self.resolveInst(new_body, old_inst.args.args[i]);
14031526 }
14041527
14051528 new_inst.* = .{
14061529 .base = .{
1407 .name = try self.autoName(),
14081530 .src = inst.src,
14091531 .tag = Inst.Asm.base_tag,
14101532 },
14111533 .positionals = .{
1412 .asm_source = try self.emitStringLiteral(inst.src, old_inst.args.asm_source),
1413 .return_type = try self.emitType(inst.src, inst.ty),
1534 .asm_source = (try self.emitStringLiteral(inst.src, old_inst.args.asm_source)).inst,
1535 .return_type = (try self.emitType(inst.src, inst.ty)).inst,
14141536 },
14151537 .kw_args = .{
14161538 .@"volatile" = old_inst.args.is_volatile,
14171539 .output = if (old_inst.args.output) |o|
1418 try self.emitStringLiteral(inst.src, o)
1540 (try self.emitStringLiteral(inst.src, o)).inst
14191541 else
14201542 null,
14211543 .inputs = inputs,
......@@ -1430,12 +1552,11 @@ const EmitZIR = struct {
14301552 const new_inst = try self.arena.allocator.create(Inst.PtrToInt);
14311553 new_inst.* = .{
14321554 .base = .{
1433 .name = try self.autoName(),
14341555 .src = inst.src,
14351556 .tag = Inst.PtrToInt.base_tag,
14361557 },
14371558 .positionals = .{
1438 .ptr = try self.resolveInst(inst_table, old_inst.args.ptr),
1559 .ptr = try self.resolveInst(new_body, old_inst.args.ptr),
14391560 },
14401561 .kw_args = .{},
14411562 };
......@@ -1446,13 +1567,12 @@ const EmitZIR = struct {
14461567 const new_inst = try self.arena.allocator.create(Inst.BitCast);
14471568 new_inst.* = .{
14481569 .base = .{
1449 .name = try self.autoName(),
14501570 .src = inst.src,
14511571 .tag = Inst.BitCast.base_tag,
14521572 },
14531573 .positionals = .{
1454 .dest_type = try self.emitType(inst.src, inst.ty),
1455 .operand = try self.resolveInst(inst_table, old_inst.args.operand),
1574 .dest_type = (try self.emitType(inst.src, inst.ty)).inst,
1575 .operand = try self.resolveInst(new_body, old_inst.args.operand),
14561576 },
14571577 .kw_args = .{},
14581578 };
......@@ -1463,13 +1583,12 @@ const EmitZIR = struct {
14631583 const new_inst = try self.arena.allocator.create(Inst.Cmp);
14641584 new_inst.* = .{
14651585 .base = .{
1466 .name = try self.autoName(),
14671586 .src = inst.src,
14681587 .tag = Inst.Cmp.base_tag,
14691588 },
14701589 .positionals = .{
1471 .lhs = try self.resolveInst(inst_table, old_inst.args.lhs),
1472 .rhs = try self.resolveInst(inst_table, old_inst.args.rhs),
1590 .lhs = try self.resolveInst(new_body, old_inst.args.lhs),
1591 .rhs = try self.resolveInst(new_body, old_inst.args.rhs),
14731592 .op = old_inst.args.op,
14741593 },
14751594 .kw_args = .{},
......@@ -1491,12 +1610,11 @@ const EmitZIR = struct {
14911610 const new_inst = try self.arena.allocator.create(Inst.CondBr);
14921611 new_inst.* = .{
14931612 .base = .{
1494 .name = try self.autoName(),
14951613 .src = inst.src,
14961614 .tag = Inst.CondBr.base_tag,
14971615 },
14981616 .positionals = .{
1499 .condition = try self.resolveInst(inst_table, old_inst.args.condition),
1617 .condition = try self.resolveInst(new_body, old_inst.args.condition),
15001618 .true_body = .{ .instructions = true_body.toOwnedSlice() },
15011619 .false_body = .{ .instructions = false_body.toOwnedSlice() },
15021620 },
......@@ -1509,12 +1627,11 @@ const EmitZIR = struct {
15091627 const new_inst = try self.arena.allocator.create(Inst.IsNull);
15101628 new_inst.* = .{
15111629 .base = .{
1512 .name = try self.autoName(),
15131630 .src = inst.src,
15141631 .tag = Inst.IsNull.base_tag,
15151632 },
15161633 .positionals = .{
1517 .operand = try self.resolveInst(inst_table, old_inst.args.operand),
1634 .operand = try self.resolveInst(new_body, old_inst.args.operand),
15181635 },
15191636 .kw_args = .{},
15201637 };
......@@ -1525,12 +1642,11 @@ const EmitZIR = struct {
15251642 const new_inst = try self.arena.allocator.create(Inst.IsNonNull);
15261643 new_inst.* = .{
15271644 .base = .{
1528 .name = try self.autoName(),
15291645 .src = inst.src,
15301646 .tag = Inst.IsNonNull.base_tag,
15311647 },
15321648 .positionals = .{
1533 .operand = try self.resolveInst(inst_table, old_inst.args.operand),
1649 .operand = try self.resolveInst(new_body, old_inst.args.operand),
15341650 },
15351651 .kw_args = .{},
15361652 };
......@@ -1542,7 +1658,7 @@ const EmitZIR = struct {
15421658 }
15431659 }
15441660
1545 fn emitType(self: *EmitZIR, src: usize, ty: Type) Allocator.Error!*Inst {
1661 fn emitType(self: *EmitZIR, src: usize, ty: Type) Allocator.Error!*Decl {
15461662 switch (ty.tag()) {
15471663 .isize => return self.emitPrimitive(src, .isize),
15481664 .usize => return self.emitPrimitive(src, .usize),
......@@ -1575,26 +1691,24 @@ const EmitZIR = struct {
15751691 ty.fnParamTypes(param_types);
15761692 const emitted_params = try self.arena.allocator.alloc(*Inst, param_types.len);
15771693 for (param_types) |param_type, i| {
1578 emitted_params[i] = try self.emitType(src, param_type);
1694 emitted_params[i] = (try self.emitType(src, param_type)).inst;
15791695 }
15801696
15811697 const fntype_inst = try self.arena.allocator.create(Inst.FnType);
15821698 fntype_inst.* = .{
15831699 .base = .{
1584 .name = try self.autoName(),
15851700 .src = src,
15861701 .tag = Inst.FnType.base_tag,
15871702 },
15881703 .positionals = .{
15891704 .param_types = emitted_params,
1590 .return_type = try self.emitType(src, ty.fnReturnType()),
1705 .return_type = (try self.emitType(src, ty.fnReturnType())).inst,
15911706 },
15921707 .kw_args = .{
15931708 .cc = ty.fnCallingConvention(),
15941709 },
15951710 };
1596 try self.decls.append(self.allocator, &fntype_inst.base);
1597 return &fntype_inst.base;
1711 return self.emitUnnamedDecl(&fntype_inst.base);
15981712 },
15991713 else => std.debug.panic("TODO implement emitType for {}", .{ty}),
16001714 },
......@@ -1613,13 +1727,12 @@ const EmitZIR = struct {
16131727 }
16141728 }
16151729
1616 fn emitPrimitive(self: *EmitZIR, src: usize, tag: Inst.Primitive.Builtin) !*Inst {
1730 fn emitPrimitive(self: *EmitZIR, src: usize, tag: Inst.Primitive.Builtin) !*Decl {
16171731 const gop = try self.primitive_table.getOrPut(tag);
16181732 if (!gop.found_existing) {
16191733 const primitive_inst = try self.arena.allocator.create(Inst.Primitive);
16201734 primitive_inst.* = .{
16211735 .base = .{
1622 .name = try self.autoName(),
16231736 .src = src,
16241737 .tag = Inst.Primitive.base_tag,
16251738 },
......@@ -1628,17 +1741,15 @@ const EmitZIR = struct {
16281741 },
16291742 .kw_args = .{},
16301743 };
1631 try self.decls.append(self.allocator, &primitive_inst.base);
1632 gop.kv.value = &primitive_inst.base;
1744 gop.kv.value = try self.emitUnnamedDecl(&primitive_inst.base);
16331745 }
16341746 return gop.kv.value;
16351747 }
16361748
1637 fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Inst {
1749 fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Decl {
16381750 const str_inst = try self.arena.allocator.create(Inst.Str);
16391751 str_inst.* = .{
16401752 .base = .{
1641 .name = try self.autoName(),
16421753 .src = src,
16431754 .tag = Inst.Str.base_tag,
16441755 },
......@@ -1647,22 +1758,17 @@ const EmitZIR = struct {
16471758 },
16481759 .kw_args = .{},
16491760 };
1650 try self.decls.append(self.allocator, &str_inst.base);
1761 return self.emitUnnamedDecl(&str_inst.base);
1762 }
16511763
1652 const ref_inst = try self.arena.allocator.create(Inst.Ref);
1653 ref_inst.* = .{
1654 .base = .{
1655 .name = try self.autoName(),
1656 .src = src,
1657 .tag = Inst.Ref.base_tag,
1658 },
1659 .positionals = .{
1660 .operand = &str_inst.base,
1661 },
1662 .kw_args = .{},
1764 fn emitUnnamedDecl(self: *EmitZIR, inst: *Inst) !*Decl {
1765 const decl = try self.arena.allocator.create(Decl);
1766 decl.* = .{
1767 .name = try self.autoName(),
1768 .contents_hash = undefined,
1769 .inst = inst,
16631770 };
1664 try self.decls.append(self.allocator, &ref_inst.base);
1665
1666 return &ref_inst.base;
1771 try self.decls.append(self.allocator, decl);
1772 return decl;
16671773 }
16681774};
src/codegen.cpp+18-2
......@@ -5583,8 +5583,12 @@ static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutableGen *executable, Ir
55835583
55845584 bool val_is_undef = value_is_all_undef(g, instruction->byte->value);
55855585 LLVMValueRef fill_char;
5586 if (val_is_undef && ir_want_runtime_safety_scope(g, instruction->base.base.scope)) {
5587 fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
5586 if (val_is_undef) {
5587 if (ir_want_runtime_safety_scope(g, instruction->base.base.scope)) {
5588 fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
5589 } else {
5590 return nullptr;
5591 }
55885592 } else {
55895593 fill_char = ir_llvm_value(g, instruction->byte);
55905594 }
......@@ -7473,6 +7477,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n
74737477 continue;
74747478 }
74757479 ZigValue *field_val = const_val->data.x_struct.fields[i];
7480 if (field_val == nullptr) {
7481 add_node_error(g, type_struct_field->decl_node,
7482 buf_sprintf("compiler bug: generating const value for struct field '%s'",
7483 buf_ptr(type_struct_field->name)));
7484 codegen_report_errors_and_exit(g);
7485 }
74767486 ZigType *field_type = field_val->type;
74777487 assert(field_type != nullptr);
74787488 if ((err = ensure_const_val_repr(nullptr, g, nullptr, field_val, field_type))) {
......@@ -9465,9 +9475,15 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
94659475 const char *libcxx_include_path = buf_ptr(buf_sprintf("%s" OS_SEP "libcxx" OS_SEP "include",
94669476 buf_ptr(g->zig_lib_dir)));
94679477
9478 const char *libcxxabi_include_path = buf_ptr(buf_sprintf("%s" OS_SEP "libcxxabi" OS_SEP "include",
9479 buf_ptr(g->zig_lib_dir)));
9480
94689481 args.append("-isystem");
94699482 args.append(libcxx_include_path);
94709483
9484 args.append("-isystem");
9485 args.append(libcxxabi_include_path);
9486
94719487 if (target_abi_is_musl(g->zig_target->abi)) {
94729488 args.append("-D_LIBCPP_HAS_MUSL_LIBC");
94739489 }
test/stage2/compare_output.zig+115-22
......@@ -1,28 +1,121 @@
11const std = @import("std");
22const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
3// self-hosted does not yet support PE executable files / COFF object files
4// or mach-o files. So we do these test cases cross compiling for x86_64-linux.
5const linux_x64 = std.zig.CrossTarget{
6 .cpu_arch = .x86_64,
7 .os_tag = .linux,
8};
39
410pub fn addCases(ctx: *TestContext) !void {
5 // TODO: re-enable these tests.
6 // https://github.com/ziglang/zig/issues/1364
11 if (std.Target.current.os.tag != .linux or
12 std.Target.current.cpu.arch != .x86_64)
13 {
14 // TODO implement self-hosted PE (.exe file) linking
15 // TODO implement more ZIR so we don't depend on x86_64-linux
16 return;
17 }
718
8 //// hello world
9 //try ctx.testCompareOutputLibC(
10 // \\extern fn puts([*]const u8) void;
11 // \\pub export fn main() c_int {
12 // \\ puts("Hello, world!");
13 // \\ return 0;
14 // \\}
15 //, "Hello, world!" ++ std.cstr.line_sep);
16
17 //// function calling another function
18 //try ctx.testCompareOutputLibC(
19 // \\extern fn puts(s: [*]const u8) void;
20 // \\pub export fn main() c_int {
21 // \\ return foo("OK");
22 // \\}
23 // \\fn foo(s: [*]const u8) c_int {
24 // \\ puts(s);
25 // \\ return 0;
26 // \\}
27 //, "OK" ++ std.cstr.line_sep);
19 {
20 var case = ctx.addExe("hello world with updates", linux_x64);
21 // Regular old hello world
22 case.addCompareOutput(
23 \\export fn _start() noreturn {
24 \\ print();
25 \\
26 \\ exit();
27 \\}
28 \\
29 \\fn print() void {
30 \\ asm volatile ("syscall"
31 \\ :
32 \\ : [number] "{rax}" (1),
33 \\ [arg1] "{rdi}" (1),
34 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
35 \\ [arg3] "{rdx}" (14)
36 \\ : "rcx", "r11", "memory"
37 \\ );
38 \\ return;
39 \\}
40 \\
41 \\fn exit() noreturn {
42 \\ asm volatile ("syscall"
43 \\ :
44 \\ : [number] "{rax}" (231),
45 \\ [arg1] "{rdi}" (0)
46 \\ : "rcx", "r11", "memory"
47 \\ );
48 \\ unreachable;
49 \\}
50 ,
51 "Hello, World!\n",
52 );
53 // Now change the message only
54 case.addCompareOutput(
55 \\export fn _start() noreturn {
56 \\ print();
57 \\
58 \\ exit();
59 \\}
60 \\
61 \\fn print() void {
62 \\ asm volatile ("syscall"
63 \\ :
64 \\ : [number] "{rax}" (1),
65 \\ [arg1] "{rdi}" (1),
66 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
67 \\ [arg3] "{rdx}" (104)
68 \\ : "rcx", "r11", "memory"
69 \\ );
70 \\ return;
71 \\}
72 \\
73 \\fn exit() noreturn {
74 \\ asm volatile ("syscall"
75 \\ :
76 \\ : [number] "{rax}" (231),
77 \\ [arg1] "{rdi}" (0)
78 \\ : "rcx", "r11", "memory"
79 \\ );
80 \\ unreachable;
81 \\}
82 ,
83 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
84 );
85 // Now we print it twice.
86 case.addCompareOutput(
87 \\export fn _start() noreturn {
88 \\ print();
89 \\ print();
90 \\
91 \\ exit();
92 \\}
93 \\
94 \\fn print() void {
95 \\ asm volatile ("syscall"
96 \\ :
97 \\ : [number] "{rax}" (1),
98 \\ [arg1] "{rdi}" (1),
99 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
100 \\ [arg3] "{rdx}" (104)
101 \\ : "rcx", "r11", "memory"
102 \\ );
103 \\ return;
104 \\}
105 \\
106 \\fn exit() noreturn {
107 \\ asm volatile ("syscall"
108 \\ :
109 \\ : [number] "{rax}" (231),
110 \\ [arg1] "{rdi}" (0)
111 \\ : "rcx", "r11", "memory"
112 \\ );
113 \\ unreachable;
114 \\}
115 ,
116 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
117 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
118 \\
119 );
120 }
28121}
test/stage2/compile_errors.zig+3-5
......@@ -27,9 +27,8 @@ pub fn addCases(ctx: *TestContext) !void {
2727 \\ %0 = call(@notafunc, [])
2828 \\})
2929 \\@0 = str("_start")
30 \\@1 = ref(@0)
31 \\@2 = export(@1, @start)
32 , &[_][]const u8{":5:13: error: use of undeclared identifier 'notafunc'"});
30 \\@1 = export(@0, "start")
31 , &[_][]const u8{":5:13: error: decl 'notafunc' not found"});
3332
3433 // TODO: this error should occur at the call site, not the fntype decl
3534 ctx.addZIRError("call naked function", linux_x64,
......@@ -41,8 +40,7 @@ pub fn addCases(ctx: *TestContext) !void {
4140 \\ %0 = call(@s, [])
4241 \\})
4342 \\@0 = str("_start")
44 \\@1 = ref(@0)
45 \\@2 = export(@1, @start)
43 \\@1 = export(@0, "start")
4644 , &[_][]const u8{":4:9: error: unable to call function with naked calling convention"});
4745
4846 // TODO: re-enable these tests.
test/stage2/zir.zig+152-333
......@@ -14,23 +14,21 @@ pub fn addCases(ctx: *TestContext) void {
1414 \\@fnty = fntype([], @void, cc=C)
1515 \\
1616 \\@9 = str("entry")
17 \\@10 = ref(@9)
18 \\@11 = export(@10, @entry)
17 \\@11 = export(@9, "entry")
1918 \\
2019 \\@entry = fn(@fnty, {
21 \\ %11 = return()
20 \\ %11 = returnvoid()
2221 \\})
2322 ,
2423 \\@void = primitive(void)
2524 \\@fnty = fntype([], @void, cc=C)
26 \\@9 = str("entry")
27 \\@10 = ref(@9)
28 \\@unnamed$6 = str("entry")
29 \\@unnamed$7 = ref(@unnamed$6)
30 \\@unnamed$8 = export(@unnamed$7, @entry)
31 \\@unnamed$10 = fntype([], @void, cc=C)
32 \\@entry = fn(@unnamed$10, {
33 \\ %0 = return()
25 \\@9 = declref("9$0")
26 \\@9$0 = str("entry")
27 \\@unnamed$4 = str("entry")
28 \\@unnamed$5 = export(@unnamed$4, "entry")
29 \\@unnamed$6 = fntype([], @void, cc=C)
30 \\@entry = fn(@unnamed$6, {
31 \\ %0 = returnvoid()
3432 \\})
3533 \\
3634 );
......@@ -45,11 +43,10 @@ pub fn addCases(ctx: *TestContext) void {
4543 \\
4644 \\@entry = fn(@fnty, {
4745 \\ %a = str("\x32\x08\x01\x0a")
48 \\ %aref = ref(%a)
49 \\ %eptr0 = elemptr(%aref, @0)
50 \\ %eptr1 = elemptr(%aref, @1)
51 \\ %eptr2 = elemptr(%aref, @2)
52 \\ %eptr3 = elemptr(%aref, @3)
46 \\ %eptr0 = elemptr(%a, @0)
47 \\ %eptr1 = elemptr(%a, @1)
48 \\ %eptr2 = elemptr(%a, @2)
49 \\ %eptr3 = elemptr(%a, @3)
5350 \\ %v0 = deref(%eptr0)
5451 \\ %v1 = deref(%eptr1)
5552 \\ %v2 = deref(%eptr2)
......@@ -61,15 +58,14 @@ pub fn addCases(ctx: *TestContext) void {
6158 \\ %expected = int(69)
6259 \\ %ok = cmp(%result, eq, %expected)
6360 \\ %10 = condbr(%ok, {
64 \\ %11 = return()
61 \\ %11 = returnvoid()
6562 \\ }, {
6663 \\ %12 = breakpoint()
6764 \\ })
6865 \\})
6966 \\
7067 \\@9 = str("entry")
71 \\@10 = ref(@9)
72 \\@11 = export(@10, @entry)
68 \\@11 = export(@9, "entry")
7369 ,
7470 \\@void = primitive(void)
7571 \\@fnty = fntype([], @void, cc=C)
......@@ -77,65 +73,62 @@ pub fn addCases(ctx: *TestContext) void {
7773 \\@1 = int(1)
7874 \\@2 = int(2)
7975 \\@3 = int(3)
80 \\@unnamed$7 = fntype([], @void, cc=C)
81 \\@entry = fn(@unnamed$7, {
82 \\ %0 = return()
76 \\@unnamed$6 = fntype([], @void, cc=C)
77 \\@entry = fn(@unnamed$6, {
78 \\ %0 = returnvoid()
8379 \\})
84 \\@a = str("2\x08\x01\n")
85 \\@9 = str("entry")
86 \\@10 = ref(@9)
87 \\@unnamed$14 = str("entry")
88 \\@unnamed$15 = ref(@unnamed$14)
89 \\@unnamed$16 = export(@unnamed$15, @entry)
80 \\@entry$1 = str("2\x08\x01\n")
81 \\@9 = declref("9$0")
82 \\@9$0 = str("entry")
83 \\@unnamed$11 = str("entry")
84 \\@unnamed$12 = export(@unnamed$11, "entry")
9085 \\
9186 );
9287
9388 {
94 var case = ctx.addZIRMulti("reference cycle with compile error in the cycle", linux_x64);
89 var case = ctx.addObjZIR("reference cycle with compile error in the cycle", linux_x64);
9590 case.addTransform(
9691 \\@void = primitive(void)
9792 \\@fnty = fntype([], @void, cc=C)
9893 \\
9994 \\@9 = str("entry")
100 \\@10 = ref(@9)
101 \\@11 = export(@10, @entry)
95 \\@11 = export(@9, "entry")
10296 \\
10397 \\@entry = fn(@fnty, {
10498 \\ %0 = call(@a, [])
105 \\ %1 = return()
99 \\ %1 = returnvoid()
106100 \\})
107101 \\
108102 \\@a = fn(@fnty, {
109103 \\ %0 = call(@b, [])
110 \\ %1 = return()
104 \\ %1 = returnvoid()
111105 \\})
112106 \\
113107 \\@b = fn(@fnty, {
114108 \\ %0 = call(@a, [])
115 \\ %1 = return()
109 \\ %1 = returnvoid()
116110 \\})
117111 ,
118112 \\@void = primitive(void)
119113 \\@fnty = fntype([], @void, cc=C)
120 \\@9 = str("entry")
121 \\@10 = ref(@9)
122 \\@unnamed$6 = str("entry")
123 \\@unnamed$7 = ref(@unnamed$6)
124 \\@unnamed$8 = export(@unnamed$7, @entry)
125 \\@unnamed$12 = fntype([], @void, cc=C)
126 \\@entry = fn(@unnamed$12, {
114 \\@9 = declref("9$0")
115 \\@9$0 = str("entry")
116 \\@unnamed$4 = str("entry")
117 \\@unnamed$5 = export(@unnamed$4, "entry")
118 \\@unnamed$6 = fntype([], @void, cc=C)
119 \\@entry = fn(@unnamed$6, {
127120 \\ %0 = call(@a, [], modifier=auto)
128 \\ %1 = return()
121 \\ %1 = returnvoid()
129122 \\})
130 \\@unnamed$17 = fntype([], @void, cc=C)
131 \\@a = fn(@unnamed$17, {
123 \\@unnamed$8 = fntype([], @void, cc=C)
124 \\@a = fn(@unnamed$8, {
132125 \\ %0 = call(@b, [], modifier=auto)
133 \\ %1 = return()
126 \\ %1 = returnvoid()
134127 \\})
135 \\@unnamed$22 = fntype([], @void, cc=C)
136 \\@b = fn(@unnamed$22, {
128 \\@unnamed$10 = fntype([], @void, cc=C)
129 \\@b = fn(@unnamed$10, {
137130 \\ %0 = call(@a, [], modifier=auto)
138 \\ %1 = return()
131 \\ %1 = returnvoid()
139132 \\})
140133 \\
141134 );
......@@ -145,27 +138,26 @@ pub fn addCases(ctx: *TestContext) void {
145138 \\@fnty = fntype([], @void, cc=C)
146139 \\
147140 \\@9 = str("entry")
148 \\@10 = ref(@9)
149 \\@11 = export(@10, @entry)
141 \\@11 = export(@9, "entry")
150142 \\
151143 \\@entry = fn(@fnty, {
152144 \\ %0 = call(@a, [])
153 \\ %1 = return()
145 \\ %1 = returnvoid()
154146 \\})
155147 \\
156148 \\@a = fn(@fnty, {
157149 \\ %0 = call(@b, [])
158 \\ %1 = return()
150 \\ %1 = returnvoid()
159151 \\})
160152 \\
161153 \\@b = fn(@fnty, {
162154 \\ %9 = compileerror("message")
163155 \\ %0 = call(@a, [])
164 \\ %1 = return()
156 \\ %1 = returnvoid()
165157 \\})
166158 ,
167159 &[_][]const u8{
168 ":19:21: error: message",
160 ":18:21: error: message",
169161 },
170162 );
171163 // Now we remove the call to `a`. `a` and `b` form a cycle, but no entry points are
......@@ -176,34 +168,32 @@ pub fn addCases(ctx: *TestContext) void {
176168 \\@fnty = fntype([], @void, cc=C)
177169 \\
178170 \\@9 = str("entry")
179 \\@10 = ref(@9)
180 \\@11 = export(@10, @entry)
171 \\@11 = export(@9, "entry")
181172 \\
182173 \\@entry = fn(@fnty, {
183 \\ %1 = return()
174 \\ %0 = returnvoid()
184175 \\})
185176 \\
186177 \\@a = fn(@fnty, {
187178 \\ %0 = call(@b, [])
188 \\ %1 = return()
179 \\ %1 = returnvoid()
189180 \\})
190181 \\
191182 \\@b = fn(@fnty, {
192183 \\ %9 = compileerror("message")
193184 \\ %0 = call(@a, [])
194 \\ %1 = return()
185 \\ %1 = returnvoid()
195186 \\})
196187 ,
197188 \\@void = primitive(void)
198189 \\@fnty = fntype([], @void, cc=C)
199 \\@9 = str("entry")
200 \\@10 = ref(@9)
201 \\@unnamed$6 = str("entry")
202 \\@unnamed$7 = ref(@unnamed$6)
203 \\@unnamed$8 = export(@unnamed$7, @entry)
204 \\@unnamed$10 = fntype([], @void, cc=C)
205 \\@entry = fn(@unnamed$10, {
206 \\ %0 = return()
190 \\@9 = declref("9$2")
191 \\@9$2 = str("entry")
192 \\@unnamed$4 = str("entry")
193 \\@unnamed$5 = export(@unnamed$4, "entry")
194 \\@unnamed$6 = fntype([], @void, cc=C)
195 \\@entry = fn(@unnamed$6, {
196 \\ %0 = returnvoid()
207197 \\})
208198 \\
209199 );
......@@ -217,272 +207,101 @@ pub fn addCases(ctx: *TestContext) void {
217207 return;
218208 }
219209
220 ctx.addZIRCompareOutput(
221 "hello world ZIR, update msg",
222 &[_][]const u8{
223 \\@noreturn = primitive(noreturn)
224 \\@void = primitive(void)
225 \\@usize = primitive(usize)
226 \\@0 = int(0)
227 \\@1 = int(1)
228 \\@2 = int(2)
229 \\@3 = int(3)
230 \\
231 \\@syscall_array = str("syscall")
232 \\@sysoutreg_array = str("={rax}")
233 \\@rax_array = str("{rax}")
234 \\@rdi_array = str("{rdi}")
235 \\@rcx_array = str("rcx")
236 \\@r11_array = str("r11")
237 \\@rdx_array = str("{rdx}")
238 \\@rsi_array = str("{rsi}")
239 \\@memory_array = str("memory")
240 \\@len_array = str("len")
241 \\
242 \\@msg = str("Hello, world!\n")
243 \\
244 \\@start_fnty = fntype([], @noreturn, cc=Naked)
245 \\@start = fn(@start_fnty, {
246 \\ %SYS_exit_group = int(231)
247 \\ %exit_code = as(@usize, @0)
248 \\
249 \\ %syscall = ref(@syscall_array)
250 \\ %sysoutreg = ref(@sysoutreg_array)
251 \\ %rax = ref(@rax_array)
252 \\ %rdi = ref(@rdi_array)
253 \\ %rcx = ref(@rcx_array)
254 \\ %rdx = ref(@rdx_array)
255 \\ %rsi = ref(@rsi_array)
256 \\ %r11 = ref(@r11_array)
257 \\ %memory = ref(@memory_array)
258 \\
259 \\ %SYS_write = as(@usize, @1)
260 \\ %STDOUT_FILENO = as(@usize, @1)
261 \\
262 \\ %msg_ptr = ref(@msg)
263 \\ %msg_addr = ptrtoint(%msg_ptr)
264 \\
265 \\ %len_name = ref(@len_array)
266 \\ %msg_len_ptr = fieldptr(%msg_ptr, %len_name)
267 \\ %msg_len = deref(%msg_len_ptr)
268 \\ %rc_write = asm(%syscall, @usize,
269 \\ volatile=1,
270 \\ output=%sysoutreg,
271 \\ inputs=[%rax, %rdi, %rsi, %rdx],
272 \\ clobbers=[%rcx, %r11, %memory],
273 \\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])
274 \\
275 \\ %rc_exit = asm(%syscall, @usize,
276 \\ volatile=1,
277 \\ output=%sysoutreg,
278 \\ inputs=[%rax, %rdi],
279 \\ clobbers=[%rcx, %r11, %memory],
280 \\ args=[%SYS_exit_group, %exit_code])
281 \\
282 \\ %99 = unreachable()
283 \\});
284 \\
285 \\@9 = str("_start")
286 \\@10 = ref(@9)
287 \\@11 = export(@10, @start)
288 ,
289 \\@noreturn = primitive(noreturn)
290 \\@void = primitive(void)
291 \\@usize = primitive(usize)
292 \\@0 = int(0)
293 \\@1 = int(1)
294 \\@2 = int(2)
295 \\@3 = int(3)
296 \\
297 \\@syscall_array = str("syscall")
298 \\@sysoutreg_array = str("={rax}")
299 \\@rax_array = str("{rax}")
300 \\@rdi_array = str("{rdi}")
301 \\@rcx_array = str("rcx")
302 \\@r11_array = str("r11")
303 \\@rdx_array = str("{rdx}")
304 \\@rsi_array = str("{rsi}")
305 \\@memory_array = str("memory")
306 \\@len_array = str("len")
307 \\
308 \\@msg = str("Hello, world!\n")
309 \\@msg2 = str("HELL WORLD\n")
310 \\
311 \\@start_fnty = fntype([], @noreturn, cc=Naked)
312 \\@start = fn(@start_fnty, {
313 \\ %SYS_exit_group = int(231)
314 \\ %exit_code = as(@usize, @0)
315 \\
316 \\ %syscall = ref(@syscall_array)
317 \\ %sysoutreg = ref(@sysoutreg_array)
318 \\ %rax = ref(@rax_array)
319 \\ %rdi = ref(@rdi_array)
320 \\ %rcx = ref(@rcx_array)
321 \\ %rdx = ref(@rdx_array)
322 \\ %rsi = ref(@rsi_array)
323 \\ %r11 = ref(@r11_array)
324 \\ %memory = ref(@memory_array)
325 \\
326 \\ %SYS_write = as(@usize, @1)
327 \\ %STDOUT_FILENO = as(@usize, @1)
328 \\
329 \\ %msg_ptr = ref(@msg2)
330 \\ %msg_addr = ptrtoint(%msg_ptr)
331 \\
332 \\ %len_name = ref(@len_array)
333 \\ %msg_len_ptr = fieldptr(%msg_ptr, %len_name)
334 \\ %msg_len = deref(%msg_len_ptr)
335 \\ %rc_write = asm(%syscall, @usize,
336 \\ volatile=1,
337 \\ output=%sysoutreg,
338 \\ inputs=[%rax, %rdi, %rsi, %rdx],
339 \\ clobbers=[%rcx, %r11, %memory],
340 \\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])
341 \\
342 \\ %rc_exit = asm(%syscall, @usize,
343 \\ volatile=1,
344 \\ output=%sysoutreg,
345 \\ inputs=[%rax, %rdi],
346 \\ clobbers=[%rcx, %r11, %memory],
347 \\ args=[%SYS_exit_group, %exit_code])
348 \\
349 \\ %99 = unreachable()
350 \\});
351 \\
352 \\@9 = str("_start")
353 \\@10 = ref(@9)
354 \\@11 = export(@10, @start)
355 ,
356 \\@noreturn = primitive(noreturn)
357 \\@void = primitive(void)
358 \\@usize = primitive(usize)
359 \\@0 = int(0)
360 \\@1 = int(1)
361 \\@2 = int(2)
362 \\@3 = int(3)
363 \\
364 \\@syscall_array = str("syscall")
365 \\@sysoutreg_array = str("={rax}")
366 \\@rax_array = str("{rax}")
367 \\@rdi_array = str("{rdi}")
368 \\@rcx_array = str("rcx")
369 \\@r11_array = str("r11")
370 \\@rdx_array = str("{rdx}")
371 \\@rsi_array = str("{rsi}")
372 \\@memory_array = str("memory")
373 \\@len_array = str("len")
374 \\
375 \\@msg = str("Hello, world!\n")
376 \\@msg2 = str("Editing the same msg2 decl but this time with a much longer message which will\ncause the data to need to be relocated in virtual address space.\n")
377 \\
378 \\@start_fnty = fntype([], @noreturn, cc=Naked)
379 \\@start = fn(@start_fnty, {
380 \\ %SYS_exit_group = int(231)
381 \\ %exit_code = as(@usize, @0)
382 \\
383 \\ %syscall = ref(@syscall_array)
384 \\ %sysoutreg = ref(@sysoutreg_array)
385 \\ %rax = ref(@rax_array)
386 \\ %rdi = ref(@rdi_array)
387 \\ %rcx = ref(@rcx_array)
388 \\ %rdx = ref(@rdx_array)
389 \\ %rsi = ref(@rsi_array)
390 \\ %r11 = ref(@r11_array)
391 \\ %memory = ref(@memory_array)
392 \\
393 \\ %SYS_write = as(@usize, @1)
394 \\ %STDOUT_FILENO = as(@usize, @1)
395 \\
396 \\ %msg_ptr = ref(@msg2)
397 \\ %msg_addr = ptrtoint(%msg_ptr)
398 \\
399 \\ %len_name = ref(@len_array)
400 \\ %msg_len_ptr = fieldptr(%msg_ptr, %len_name)
401 \\ %msg_len = deref(%msg_len_ptr)
402 \\ %rc_write = asm(%syscall, @usize,
403 \\ volatile=1,
404 \\ output=%sysoutreg,
405 \\ inputs=[%rax, %rdi, %rsi, %rdx],
406 \\ clobbers=[%rcx, %r11, %memory],
407 \\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])
408 \\
409 \\ %rc_exit = asm(%syscall, @usize,
410 \\ volatile=1,
411 \\ output=%sysoutreg,
412 \\ inputs=[%rax, %rdi],
413 \\ clobbers=[%rcx, %r11, %memory],
414 \\ args=[%SYS_exit_group, %exit_code])
415 \\
416 \\ %99 = unreachable()
417 \\});
418 \\
419 \\@9 = str("_start")
420 \\@10 = ref(@9)
421 \\@11 = export(@10, @start)
422 },
423 &[_][]const u8{
424 \\Hello, world!
425 \\
426 ,
427 \\HELL WORLD
428 \\
429 ,
430 \\Editing the same msg2 decl but this time with a much longer message which will
431 \\cause the data to need to be relocated in virtual address space.
432 \\
433 },
210 ctx.addZIRCompareOutput("hello world ZIR",
211 \\@noreturn = primitive(noreturn)
212 \\@void = primitive(void)
213 \\@usize = primitive(usize)
214 \\@0 = int(0)
215 \\@1 = int(1)
216 \\@2 = int(2)
217 \\@3 = int(3)
218 \\
219 \\@msg = str("Hello, world!\n")
220 \\
221 \\@start_fnty = fntype([], @noreturn, cc=Naked)
222 \\@start = fn(@start_fnty, {
223 \\ %SYS_exit_group = int(231)
224 \\ %exit_code = as(@usize, @0)
225 \\
226 \\ %syscall = str("syscall")
227 \\ %sysoutreg = str("={rax}")
228 \\ %rax = str("{rax}")
229 \\ %rdi = str("{rdi}")
230 \\ %rcx = str("rcx")
231 \\ %rdx = str("{rdx}")
232 \\ %rsi = str("{rsi}")
233 \\ %r11 = str("r11")
234 \\ %memory = str("memory")
235 \\
236 \\ %SYS_write = as(@usize, @1)
237 \\ %STDOUT_FILENO = as(@usize, @1)
238 \\
239 \\ %msg_addr = ptrtoint(@msg)
240 \\
241 \\ %len_name = str("len")
242 \\ %msg_len_ptr = fieldptr(@msg, %len_name)
243 \\ %msg_len = deref(%msg_len_ptr)
244 \\ %rc_write = asm(%syscall, @usize,
245 \\ volatile=1,
246 \\ output=%sysoutreg,
247 \\ inputs=[%rax, %rdi, %rsi, %rdx],
248 \\ clobbers=[%rcx, %r11, %memory],
249 \\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])
250 \\
251 \\ %rc_exit = asm(%syscall, @usize,
252 \\ volatile=1,
253 \\ output=%sysoutreg,
254 \\ inputs=[%rax, %rdi],
255 \\ clobbers=[%rcx, %r11, %memory],
256 \\ args=[%SYS_exit_group, %exit_code])
257 \\
258 \\ %99 = unreachable()
259 \\});
260 \\
261 \\@9 = str("_start")
262 \\@11 = export(@9, "start")
263 ,
264 \\Hello, world!
265 \\
434266 );
435267
436 ctx.addZIRCompareOutput(
437 "function call with no args no return value",
438 &[_][]const u8{
439 \\@noreturn = primitive(noreturn)
440 \\@void = primitive(void)
441 \\@usize = primitive(usize)
442 \\@0 = int(0)
443 \\@1 = int(1)
444 \\@2 = int(2)
445 \\@3 = int(3)
446 \\
447 \\@syscall_array = str("syscall")
448 \\@sysoutreg_array = str("={rax}")
449 \\@rax_array = str("{rax}")
450 \\@rdi_array = str("{rdi}")
451 \\@rcx_array = str("rcx")
452 \\@r11_array = str("r11")
453 \\@memory_array = str("memory")
454 \\
455 \\@exit0_fnty = fntype([], @noreturn)
456 \\@exit0 = fn(@exit0_fnty, {
457 \\ %SYS_exit_group = int(231)
458 \\ %exit_code = as(@usize, @0)
459 \\
460 \\ %syscall = ref(@syscall_array)
461 \\ %sysoutreg = ref(@sysoutreg_array)
462 \\ %rax = ref(@rax_array)
463 \\ %rdi = ref(@rdi_array)
464 \\ %rcx = ref(@rcx_array)
465 \\ %r11 = ref(@r11_array)
466 \\ %memory = ref(@memory_array)
467 \\
468 \\ %rc = asm(%syscall, @usize,
469 \\ volatile=1,
470 \\ output=%sysoutreg,
471 \\ inputs=[%rax, %rdi],
472 \\ clobbers=[%rcx, %r11, %memory],
473 \\ args=[%SYS_exit_group, %exit_code])
474 \\
475 \\ %99 = unreachable()
476 \\});
477 \\
478 \\@start_fnty = fntype([], @noreturn, cc=Naked)
479 \\@start = fn(@start_fnty, {
480 \\ %0 = call(@exit0, [])
481 \\})
482 \\@9 = str("_start")
483 \\@10 = ref(@9)
484 \\@11 = export(@10, @start)
485 },
486 &[_][]const u8{""},
487 );
268 ctx.addZIRCompareOutput("function call with no args no return value",
269 \\@noreturn = primitive(noreturn)
270 \\@void = primitive(void)
271 \\@usize = primitive(usize)
272 \\@0 = int(0)
273 \\@1 = int(1)
274 \\@2 = int(2)
275 \\@3 = int(3)
276 \\
277 \\@exit0_fnty = fntype([], @noreturn)
278 \\@exit0 = fn(@exit0_fnty, {
279 \\ %SYS_exit_group = int(231)
280 \\ %exit_code = as(@usize, @0)
281 \\
282 \\ %syscall = str("syscall")
283 \\ %sysoutreg = str("={rax}")
284 \\ %rax = str("{rax}")
285 \\ %rdi = str("{rdi}")
286 \\ %rcx = str("rcx")
287 \\ %r11 = str("r11")
288 \\ %memory = str("memory")
289 \\
290 \\ %rc = asm(%syscall, @usize,
291 \\ volatile=1,
292 \\ output=%sysoutreg,
293 \\ inputs=[%rax, %rdi],
294 \\ clobbers=[%rcx, %r11, %memory],
295 \\ args=[%SYS_exit_group, %exit_code])
296 \\
297 \\ %99 = unreachable()
298 \\});
299 \\
300 \\@start_fnty = fntype([], @noreturn, cc=Naked)
301 \\@start = fn(@start_fnty, {
302 \\ %0 = call(@exit0, [])
303 \\})
304 \\@9 = str("_start")
305 \\@11 = export(@9, "start")
306 , "");
488307}