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 {...@@ -72,9 +72,22 @@ pub fn build(b: *Builder) !void {
72 if (!only_install_lib_files) {72 if (!only_install_lib_files) {
73 exe.install();73 exe.install();
74 }74 }
75 const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");
75 const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse false;76 const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse false;
76 if (link_libc) exe.linkLibC();77 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
78 b.installDirectory(InstallDirectoryOptions{91 b.installDirectory(InstallDirectoryOptions{
79 .source_dir = "lib",92 .source_dir = "lib",
80 .install_dir = .Lib,93 .install_dir = .Lib,
lib/std/build.zig+3-2
...@@ -1905,10 +1905,11 @@ pub const LibExeObjStep = struct {...@@ -1905,10 +1905,11 @@ pub const LibExeObjStep = struct {
1905 builder.allocator,1905 builder.allocator,
1906 &[_][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", .{self.name}) },1906 &[_][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", .{self.name}) },
1907 );1907 );
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());
1909 try zig_args.append("--pkg-begin");1910 try zig_args.append("--pkg-begin");
1910 try zig_args.append("build_options");1911 try zig_args.append("build_options");
1911 try zig_args.append(builder.pathFromRoot(build_options_file));1912 try zig_args.append(path_from_root);
1912 try zig_args.append("--pkg-end");1913 try zig_args.append("--pkg-end");
1913 }1914 }
19141915
lib/std/zig.zig+38
...@@ -1,4 +1,6 @@...@@ -1,4 +1,6 @@
1const std = @import("std.zig");
1const tokenizer = @import("zig/tokenizer.zig");2const tokenizer = @import("zig/tokenizer.zig");
3
2pub const Token = tokenizer.Token;4pub const Token = tokenizer.Token;
3pub const Tokenizer = tokenizer.Tokenizer;5pub const Tokenizer = tokenizer.Tokenizer;
4pub const parse = @import("zig/parse.zig").parse;6pub const parse = @import("zig/parse.zig").parse;
...@@ -9,6 +11,21 @@ pub const ast = @import("zig/ast.zig");...@@ -9,6 +11,21 @@ pub const ast = @import("zig/ast.zig");
9pub const system = @import("zig/system.zig");11pub const system = @import("zig/system.zig");
10pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;12pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
1113
14pub const SrcHash = [16]u8;
15
16/// If the source is small enough, it is used directly as the hash.
17/// If it is long, blake3 hash is computed.
18pub fn hashSrc(src: []const u8) SrcHash {
19 var out: SrcHash = undefined;
20 if (src.len <= SrcHash.len) {
21 std.mem.copy(u8, &out, src);
22 std.mem.set(u8, out[src.len..], 0);
23 } else {
24 std.crypto.Blake3.hash(src, &out);
25 }
26 return out;
27}
28
12pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {29pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {
13 var line: usize = 0;30 var line: usize = 0;
14 var column: usize = 0;31 var column: usize = 0;
...@@ -26,6 +43,27 @@ pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usi...@@ -26,6 +43,27 @@ pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usi
26 return .{ .line = line, .column = column };43 return .{ .line = line, .column = column };
27}44}
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
29test "" {67test "" {
30 @import("std").meta.refAllDecls(@This());68 @import("std").meta.refAllDecls(@This());
31}69}
lib/std/zig/ast.zig+2
...@@ -2260,6 +2260,8 @@ pub const Node = struct {...@@ -2260,6 +2260,8 @@ pub const Node = struct {
2260 }2260 }
2261 };2261 };
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.
2263 pub const ControlFlowExpression = struct {2265 pub const ControlFlowExpression = struct {
2264 base: Node = Node{ .id = .ControlFlowExpression },2266 base: Node = Node{ .id = .ControlFlowExpression },
2265 ltoken: TokenIndex,2267 ltoken: TokenIndex,
lib/std/zig/parse.zig+1-1
...@@ -3222,7 +3222,7 @@ const Parser = struct {...@@ -3222,7 +3222,7 @@ const Parser = struct {
3222 }3222 }
32233223
3224 /// Op* Child3224 /// 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 {
3226 if (try opParseFn(p)) |first_op| {3226 if (try opParseFn(p)) |first_op| {
3227 var rightmost_op = first_op;3227 var rightmost_op = first_op;
3228 while (true) {3228 while (true) {
src-self-hosted/Module.zig+1457-460
...@@ -15,13 +15,16 @@ const ir = @import("ir.zig");...@@ -15,13 +15,16 @@ const ir = @import("ir.zig");
15const zir = @import("zir.zig");15const zir = @import("zir.zig");
16const Module = @This();16const Module = @This();
17const Inst = ir.Inst;17const Inst = ir.Inst;
18const ast = std.zig.ast;
19const trace = @import("tracy.zig").trace;
1820
19/// General-purpose allocator.21/// General-purpose allocator.
20allocator: *Allocator,22allocator: *Allocator,
21/// Pointer to externally managed resource.23/// Pointer to externally managed resource.
22root_pkg: *Package,24root_pkg: *Package,
23/// Module owns this resource.25/// Module owns this resource.
24root_scope: *Scope.ZIRModule,26/// The `Scope` is either a `Scope.ZIRModule` or `Scope.File`.
27root_scope: *Scope,
25bin_file: link.ElfFile,28bin_file: link.ElfFile,
26bin_file_dir: std.fs.Dir,29bin_file_dir: std.fs.Dir,
27bin_file_path: []const u8,30bin_file_path: []const u8,
...@@ -35,10 +38,10 @@ decl_exports: std.AutoHashMap(*Decl, []*Export),...@@ -35,10 +38,10 @@ decl_exports: std.AutoHashMap(*Decl, []*Export),
35/// This table owns the Export memory.38/// This table owns the Export memory.
36export_owners: std.AutoHashMap(*Decl, []*Export),39export_owners: std.AutoHashMap(*Decl, []*Export),
37/// Maps fully qualified namespaced names to the Decl struct for them.40/// Maps fully qualified namespaced names to the Decl struct for them.
38decl_table: std.AutoHashMap(Decl.Hash, *Decl),41decl_table: DeclTable,
3942
40optimize_mode: std.builtin.Mode,43optimize_mode: std.builtin.Mode,
41link_error_flags: link.ElfFile.ErrorFlags = link.ElfFile.ErrorFlags{},44link_error_flags: link.ElfFile.ErrorFlags = .{},
4245
43work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic),46work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic),
4447
...@@ -49,8 +52,8 @@ work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic),...@@ -49,8 +52,8 @@ work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic),
49/// a Decl can have a failed_decls entry but have analysis status of success.52/// a Decl can have a failed_decls entry but have analysis status of success.
50failed_decls: std.AutoHashMap(*Decl, *ErrorMsg),53failed_decls: std.AutoHashMap(*Decl, *ErrorMsg),
51/// Using a map here for consistency with the other fields here.54/// 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.55/// The ErrorMsg memory is owned by the `Scope`, using Module's allocator.
53failed_files: std.AutoHashMap(*Scope.ZIRModule, *ErrorMsg),56failed_files: std.AutoHashMap(*Scope, *ErrorMsg),
54/// Using a map here for consistency with the other fields here.57/// Using a map here for consistency with the other fields here.
55/// The ErrorMsg memory is owned by the `Export`, using Module's allocator.58/// The ErrorMsg memory is owned by the `Export`, using Module's allocator.
56failed_exports: std.AutoHashMap(*Export, *ErrorMsg),59failed_exports: std.AutoHashMap(*Export, *ErrorMsg),
...@@ -60,15 +63,23 @@ failed_exports: std.AutoHashMap(*Export, *ErrorMsg),...@@ -60,15 +63,23 @@ failed_exports: std.AutoHashMap(*Export, *ErrorMsg),
60/// previous analysis.63/// previous analysis.
61generation: u32 = 0,64generation: u32 = 0,
6265
66next_anon_name_index: usize = 0,
67
63/// Candidates for deletion. After a semantic analysis update completes, this list68/// Candidates for deletion. After a semantic analysis update completes, this list
64/// contains Decls that need to be deleted if they end up having no references to them.69/// 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) {
68 /// Write the machine code for a Decl to the output file.77 /// Write the machine code for a Decl to the output file.
69 codegen_decl: *Decl,78 codegen_decl: *Decl,
70 /// Decl has been determined to be outdated; perform semantic analysis again.79 /// The Decl needs to be analyzed and possibly export itself.
71 re_analyze_decl: *Decl,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,
72};83};
7384
74pub const Export = struct {85pub const Export = struct {
...@@ -99,13 +110,12 @@ pub const Decl = struct {...@@ -99,13 +110,12 @@ pub const Decl = struct {
99 /// mapping them to an address in the output file.110 /// mapping them to an address in the output file.
100 /// Memory owned by this decl, using Module's allocator.111 /// Memory owned by this decl, using Module's allocator.
101 name: [*:0]const u8,112 name: [*:0]const u8,
102 /// The direct parent container of the Decl. This field will need to get more fleshed out when113 /// The direct parent container of the Decl. This is either a `Scope.File` or `Scope.ZIRModule`.
103 /// self-hosted supports proper struct types and Zig AST => ZIR.
104 /// Reference to externally owned memory.114 /// Reference to externally owned memory.
105 scope: *Scope.ZIRModule,115 scope: *Scope,
106 /// Byte offset into the source file that contains this declaration.116 /// The AST Node decl index or ZIR Inst index that contains this declaration.
107 /// This is the base offset that src offsets within this Decl are relative to.117 /// Must be recomputed when the corresponding source file is modified.
108 src: usize,118 src_index: usize,
109 /// The most recent value of the Decl after a successful semantic analysis.119 /// The most recent value of the Decl after a successful semantic analysis.
110 typed_value: union(enum) {120 typed_value: union(enum) {
111 never_succeeded: void,121 never_succeeded: void,
...@@ -116,6 +126,9 @@ pub const Decl = struct {...@@ -116,6 +126,9 @@ pub const Decl = struct {
116 /// analysis of the function body is performed with this value set to `success`. Functions126 /// analysis of the function body is performed with this value set to `success`. Functions
117 /// have their own analysis status field.127 /// have their own analysis status field.
118 analysis: enum {128 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,
119 /// Semantic analysis for this Decl is running right now. This state detects dependency loops.132 /// Semantic analysis for this Decl is running right now. This state detects dependency loops.
120 in_progress,133 in_progress,
121 /// This Decl might be OK but it depends on another one which did not successfully complete134 /// This Decl might be OK but it depends on another one which did not successfully complete
...@@ -125,6 +138,10 @@ pub const Decl = struct {...@@ -125,6 +138,10 @@ pub const Decl = struct {
125 /// There will be a corresponding ErrorMsg in Module.failed_decls.138 /// There will be a corresponding ErrorMsg in Module.failed_decls.
126 sema_failure,139 sema_failure,
127 /// There will be a corresponding ErrorMsg in Module.failed_decls.140 /// 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.
128 codegen_failure,145 codegen_failure,
129 /// There will be a corresponding ErrorMsg in Module.failed_decls.146 /// There will be a corresponding ErrorMsg in Module.failed_decls.
130 /// This indicates the failure was something like running out of disk space,147 /// This indicates the failure was something like running out of disk space,
...@@ -150,7 +167,7 @@ pub const Decl = struct {...@@ -150,7 +167,7 @@ pub const Decl = struct {
150 /// This is populated regardless of semantic analysis and code generation.167 /// This is populated regardless of semantic analysis and code generation.
151 link: link.ElfFile.TextBlock = link.ElfFile.TextBlock.empty,168 link: link.ElfFile.TextBlock = link.ElfFile.TextBlock.empty,
152169
153 contents_hash: Hash,170 contents_hash: std.zig.SrcHash,
154171
155 /// The shallow set of other decls whose typed_value could possibly change if this Decl's172 /// The shallow set of other decls whose typed_value could possibly change if this Decl's
156 /// typed_value is modified.173 /// typed_value is modified.
...@@ -169,28 +186,28 @@ pub const Decl = struct {...@@ -169,28 +186,28 @@ pub const Decl = struct {
169 allocator.destroy(self);186 allocator.destroy(self);
170 }187 }
171188
172 pub const Hash = [16]u8;189 pub fn src(self: Decl) usize {
173190 switch (self.scope.tag) {
174 /// If the name is small enough, it is used directly as the hash.191 .file => {
175 /// If it is long, blake3 hash is computed.192 const file = @fieldParentPtr(Scope.File, "base", self.scope);
176 pub fn hashSimpleName(name: []const u8) Hash {193 const tree = file.contents.tree;
177 var out: Hash = undefined;194 const decl_node = tree.root_node.decls()[self.src_index];
178 if (name.len <= Hash.len) {195 return tree.token_locs[decl_node.firstToken()].start;
179 mem.copy(u8, &out, name);196 },
180 mem.set(u8, out[name.len..], 0);197 .zir_module => {
181 } else {198 const zir_module = @fieldParentPtr(Scope.ZIRModule, "base", self.scope);
182 std.crypto.Blake3.hash(name, &out);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,
183 }206 }
184 return out;
185 }207 }
186208
187 /// Must generate unique bytes with no collisions with other decls.209 pub fn fullyQualifiedNameHash(self: Decl) Scope.NameHash {
188 /// The point of hashing here is only to limit the number of bytes of210 return self.scope.fullyQualifiedNameHash(mem.spanZ(self.name));
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));
194 }211 }
195212
196 pub fn typedValue(self: *Decl) error{AnalysisFail}!TypedValue {213 pub fn typedValue(self: *Decl) error{AnalysisFail}!TypedValue {
...@@ -248,11 +265,9 @@ pub const Decl = struct {...@@ -248,11 +265,9 @@ pub const Decl = struct {
248/// Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.265/// Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
249pub const Fn = struct {266pub const Fn = struct {
250 /// This memory owned by the Decl's TypedValue.Managed arena allocator.267 /// This memory owned by the Decl's TypedValue.Managed arena allocator.
251 fn_type: Type,
252 analysis: union(enum) {268 analysis: union(enum) {
253 /// The value is the source instruction.269 queued: *ZIR,
254 queued: *zir.Inst.Fn,270 in_progress,
255 in_progress: *Analysis,
256 /// There will be a corresponding ErrorMsg in Module.failed_decls271 /// There will be a corresponding ErrorMsg in Module.failed_decls
257 sema_failure,272 sema_failure,
258 /// This Fn might be OK but it depends on another Decl which did not successfully complete273 /// This Fn might be OK but it depends on another Decl which did not successfully complete
...@@ -266,16 +281,20 @@ pub const Fn = struct {...@@ -266,16 +281,20 @@ pub const Fn = struct {
266 /// of Fn analysis.281 /// of Fn analysis.
267 pub const Analysis = struct {282 pub const Analysis = struct {
268 inner_block: Scope.Block,283 inner_block: Scope.Block,
269 /// TODO Performance optimization idea: instead of this inst_table,284 };
270 /// use a field in the zir.Inst instead to track corresponding instructions285
271 inst_table: std.AutoHashMap(*zir.Inst, *Inst),286 /// Contains un-analyzed ZIR instructions generated from Zig source AST.
272 needed_inst_capacity: usize,287 pub const ZIR = struct {
288 body: zir.Module.Body,
289 arena: std.heap.ArenaAllocator.State,
273 };290 };
274};291};
275292
276pub const Scope = struct {293pub const Scope = struct {
277 tag: Tag,294 tag: Tag,
278295
296 pub const NameHash = [16]u8;
297
279 pub fn cast(base: *Scope, comptime T: type) ?*T {298 pub fn cast(base: *Scope, comptime T: type) ?*T {
280 if (base.tag != T.base_tag)299 if (base.tag != T.base_tag)
281 return null;300 return null;
...@@ -289,7 +308,9 @@ pub const Scope = struct {...@@ -289,7 +308,9 @@ pub const Scope = struct {
289 switch (self.tag) {308 switch (self.tag) {
290 .block => return self.cast(Block).?.arena,309 .block => return self.cast(Block).?.arena,
291 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,310 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
311 .gen_zir => return &self.cast(GenZIR).?.arena.allocator,
292 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,312 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
313 .file => unreachable,
293 }314 }
294 }315 }
295316
...@@ -298,18 +319,45 @@ pub const Scope = struct {...@@ -298,18 +319,45 @@ pub const Scope = struct {
298 pub fn decl(self: *Scope) ?*Decl {319 pub fn decl(self: *Scope) ?*Decl {
299 return switch (self.tag) {320 return switch (self.tag) {
300 .block => self.cast(Block).?.decl,321 .block => self.cast(Block).?.decl,
322 .gen_zir => self.cast(GenZIR).?.decl,
301 .decl => self.cast(DeclAnalysis).?.decl,323 .decl => self.cast(DeclAnalysis).?.decl,
302 .zir_module => null,324 .zir_module => null,
325 .file => null,
303 };326 };
304 }327 }
305328
306 /// Asserts the scope has a parent which is a ZIRModule and329 /// Asserts the scope has a parent which is a ZIRModule or File and
307 /// returns it.330 /// returns it.
308 pub fn namespace(self: *Scope) *ZIRModule {331 pub fn namespace(self: *Scope) *Scope {
309 switch (self.tag) {332 switch (self.tag) {
310 .block => return self.cast(Block).?.decl.scope,333 .block => return self.cast(Block).?.decl.scope,
334 .gen_zir => return self.cast(GenZIR).?.decl.scope,
311 .decl => return self.cast(DeclAnalysis).?.decl.scope,335 .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,
313 }361 }
314 }362 }
315363
...@@ -325,10 +373,173 @@ pub const Scope = struct {...@@ -325,10 +373,173 @@ pub const Scope = struct {
325 });373 });
326 }374 }
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
328 pub const Tag = enum {446 pub const Tag = enum {
447 /// .zir source code.
329 zir_module,448 zir_module,
449 /// .zig source code.
450 file,
330 block,451 block,
331 decl,452 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 }
332 };543 };
333544
334 pub const ZIRModule = struct {545 pub const ZIRModule = struct {
...@@ -355,6 +566,11 @@ pub const Scope = struct {...@@ -355,6 +566,11 @@ pub const Scope = struct {
355 loaded_success,566 loaded_success,
356 },567 },
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
358 pub fn unload(self: *ZIRModule, allocator: *Allocator) void {574 pub fn unload(self: *ZIRModule, allocator: *Allocator) void {
359 switch (self.status) {575 switch (self.status) {
360 .never_loaded,576 .never_loaded,
...@@ -366,11 +582,13 @@ pub const Scope = struct {...@@ -366,11 +582,13 @@ pub const Scope = struct {
366 .loaded_success => {582 .loaded_success => {
367 self.contents.module.deinit(allocator);583 self.contents.module.deinit(allocator);
368 allocator.destroy(self.contents.module);584 allocator.destroy(self.contents.module);
585 self.contents = .{ .not_available = {} };
369 self.status = .unloaded_success;586 self.status = .unloaded_success;
370 },587 },
371 .loaded_sema_failure => {588 .loaded_sema_failure => {
372 self.contents.module.deinit(allocator);589 self.contents.module.deinit(allocator);
373 allocator.destroy(self.contents.module);590 allocator.destroy(self.contents.module);
591 self.contents = .{ .not_available = {} };
374 self.status = .unloaded_sema_failure;592 self.status = .unloaded_sema_failure;
375 },593 },
376 }594 }
...@@ -384,14 +602,46 @@ pub const Scope = struct {...@@ -384,14 +602,46 @@ pub const Scope = struct {
384 }602 }
385603
386 pub fn deinit(self: *ZIRModule, allocator: *Allocator) void {604 pub fn deinit(self: *ZIRModule, allocator: *Allocator) void {
605 self.decls.deinit(allocator);
387 self.unload(allocator);606 self.unload(allocator);
388 self.* = undefined;607 self.* = undefined;
389 }608 }
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
391 pub fn dumpSrc(self: *ZIRModule, src: usize) void {619 pub fn dumpSrc(self: *ZIRModule, src: usize) void {
392 const loc = std.zig.findLineColumn(self.source.bytes, src);620 const loc = std.zig.findLineColumn(self.source.bytes, src);
393 std.debug.warn("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });621 std.debug.warn("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
394 }622 }
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 }
395 };645 };
396646
397 /// This is a temporary structure, references to it are valid only647 /// This is a temporary structure, references to it are valid only
...@@ -399,7 +649,7 @@ pub const Scope = struct {...@@ -399,7 +649,7 @@ pub const Scope = struct {
399 pub const Block = struct {649 pub const Block = struct {
400 pub const base_tag: Tag = .block;650 pub const base_tag: Tag = .block;
401 base: Scope = Scope{ .tag = base_tag },651 base: Scope = Scope{ .tag = base_tag },
402 func: *Fn,652 func: ?*Fn,
403 decl: *Decl,653 decl: *Decl,
404 instructions: ArrayListUnmanaged(*Inst),654 instructions: ArrayListUnmanaged(*Inst),
405 /// Points to the arena allocator of DeclAnalysis655 /// Points to the arena allocator of DeclAnalysis
...@@ -414,6 +664,16 @@ pub const Scope = struct {...@@ -414,6 +664,16 @@ pub const Scope = struct {
414 decl: *Decl,664 decl: *Decl,
415 arena: std.heap.ArenaAllocator,665 arena: std.heap.ArenaAllocator,
416 };666 };
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 };
417};677};
418678
419pub const Body = struct {679pub const Body = struct {
...@@ -463,19 +723,10 @@ pub const InitOptions = struct {...@@ -463,19 +723,10 @@ pub const InitOptions = struct {
463 link_mode: ?std.builtin.LinkMode = null,723 link_mode: ?std.builtin.LinkMode = null,
464 object_format: ?std.builtin.ObjectFormat = null,724 object_format: ?std.builtin.ObjectFormat = null,
465 optimize_mode: std.builtin.Mode = .Debug,725 optimize_mode: std.builtin.Mode = .Debug,
726 keep_source_files_loaded: bool = false,
466};727};
467728
468pub fn init(gpa: *Allocator, options: InitOptions) !Module {729pub fn init(gpa: *Allocator, options: InitOptions) !Module {
469 const root_scope = try gpa.create(Scope.ZIRModule);
470 errdefer gpa.destroy(root_scope);
471
472 root_scope.* = .{
473 .sub_file_path = options.root_pkg.root_src_path,
474 .source = .{ .unloaded = {} },
475 .contents = .{ .not_available = {} },
476 .status = .never_loaded,
477 };
478
479 const bin_file_dir = options.bin_file_dir orelse std.fs.cwd();730 const bin_file_dir = options.bin_file_dir orelse std.fs.cwd();
480 var bin_file = try link.openBinFilePath(gpa, bin_file_dir, options.bin_file_path, .{731 var bin_file = try link.openBinFilePath(gpa, bin_file_dir, options.bin_file_path, .{
481 .target = options.target,732 .target = options.target,
...@@ -485,6 +736,32 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {...@@ -485,6 +736,32 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
485 });736 });
486 errdefer bin_file.deinit();737 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
488 return Module{765 return Module{
489 .allocator = gpa,766 .allocator = gpa,
490 .root_pkg = options.root_pkg,767 .root_pkg = options.root_pkg,
...@@ -493,13 +770,14 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {...@@ -493,13 +770,14 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
493 .bin_file_path = options.bin_file_path,770 .bin_file_path = options.bin_file_path,
494 .bin_file = bin_file,771 .bin_file = bin_file,
495 .optimize_mode = options.optimize_mode,772 .optimize_mode = options.optimize_mode,
496 .decl_table = std.AutoHashMap(Decl.Hash, *Decl).init(gpa),773 .decl_table = DeclTable.init(gpa),
497 .decl_exports = std.AutoHashMap(*Decl, []*Export).init(gpa),774 .decl_exports = std.AutoHashMap(*Decl, []*Export).init(gpa),
498 .export_owners = std.AutoHashMap(*Decl, []*Export).init(gpa),775 .export_owners = std.AutoHashMap(*Decl, []*Export).init(gpa),
499 .failed_decls = std.AutoHashMap(*Decl, *ErrorMsg).init(gpa),776 .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),
501 .failed_exports = std.AutoHashMap(*Export, *ErrorMsg).init(gpa),778 .failed_exports = std.AutoHashMap(*Export, *ErrorMsg).init(gpa),
502 .work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa),779 .work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa),
780 .keep_source_files_loaded = options.keep_source_files_loaded,
503 };781 };
504}782}
505783
...@@ -551,10 +829,7 @@ pub fn deinit(self: *Module) void {...@@ -551,10 +829,7 @@ pub fn deinit(self: *Module) void {
551 }829 }
552 self.export_owners.deinit();830 self.export_owners.deinit();
553 }831 }
554 {832 self.root_scope.destroy(allocator);
555 self.root_scope.deinit(allocator);
556 allocator.destroy(self.root_scope);
557 }
558 self.* = undefined;833 self.* = undefined;
559}834}
560835
...@@ -571,19 +846,31 @@ pub fn target(self: Module) std.Target {...@@ -571,19 +846,31 @@ pub fn target(self: Module) std.Target {
571846
572/// Detect changes to source files, perform semantic analysis, and update the output files.847/// Detect changes to source files, perform semantic analysis, and update the output files.
573pub fn update(self: *Module) !void {848pub fn update(self: *Module) !void {
849 const tracy = trace(@src());
850 defer tracy.end();
851
574 self.generation += 1;852 self.generation += 1;
575853
576 // TODO Use the cache hash file system to detect which source files changed.854 // TODO Use the cache hash file system to detect which source files changed.
577 // Here we simulate a full cache miss.855 // Until then we simulate a full cache miss. Source files could have been loaded for any reason;
578 // Analyze the root source file now.856 // to force a refresh we unload now.
579 // Source files could have been loaded for any reason; to force a refresh we unload now.857 if (self.root_scope.cast(Scope.File)) |zig_file| {
580 self.root_scope.unload(self.allocator);858 zig_file.unload(self.allocator);
581 self.analyzeRoot(self.root_scope) catch |err| switch (err) {859 self.analyzeRootSrcFile(zig_file) catch |err| switch (err) {
582 error.AnalysisFail => {860 error.AnalysisFail => {
583 assert(self.totalErrorCount() != 0);861 assert(self.totalErrorCount() != 0);
584 },862 },
585 else => |e| return e,863 else => |e| return e,
586 };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
588 try self.performAllTheWork();875 try self.performAllTheWork();
589876
...@@ -596,14 +883,16 @@ pub fn update(self: *Module) !void {...@@ -596,14 +883,16 @@ pub fn update(self: *Module) !void {
596 try self.deleteDecl(decl);883 try self.deleteDecl(decl);
597 }884 }
598885
886 self.link_error_flags = self.bin_file.error_flags;
887
599 // If there are any errors, we anticipate the source files being loaded888 // If there are any errors, we anticipate the source files being loaded
600 // to report error messages. Otherwise we unload all source files to save memory.889 // to report error messages. Otherwise we unload all source files to save memory.
601 if (self.totalErrorCount() == 0) {890 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();
603 }895 }
604
605 try self.bin_file.flush();
606 self.link_error_flags = self.bin_file.error_flags;
607}896}
608897
609/// Having the file open for writing is problematic as far as executing the898/// Having the file open for writing is problematic as far as executing the
...@@ -619,10 +908,10 @@ pub fn makeBinFileWritable(self: *Module) !void {...@@ -619,10 +908,10 @@ pub fn makeBinFileWritable(self: *Module) !void {
619}908}
620909
621pub fn totalErrorCount(self: *Module) usize {910pub fn totalErrorCount(self: *Module) usize {
622 return self.failed_decls.size +911 const total = self.failed_decls.size +
623 self.failed_files.size +912 self.failed_files.size +
624 self.failed_exports.size +913 self.failed_exports.size;
625 @boolToInt(self.link_error_flags.no_entry_point_found);914 return if (total == 0) @boolToInt(self.link_error_flags.no_entry_point_found) else total;
626}915}
627916
628pub fn getAllErrorsAlloc(self: *Module) !AllErrors {917pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
...@@ -637,8 +926,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {...@@ -637,8 +926,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
637 while (it.next()) |kv| {926 while (it.next()) |kv| {
638 const scope = kv.key;927 const scope = kv.key;
639 const err_msg = kv.value;928 const err_msg = kv.value;
640 const source = try self.getSource(scope);929 const source = try scope.getSource(self);
641 try AllErrors.add(&arena, &errors, scope.sub_file_path, source, err_msg.*);930 try AllErrors.add(&arena, &errors, scope.subFilePath(), source, err_msg.*);
642 }931 }
643 }932 }
644 {933 {
...@@ -646,8 +935,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {...@@ -646,8 +935,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
646 while (it.next()) |kv| {935 while (it.next()) |kv| {
647 const decl = kv.key;936 const decl = kv.key;
648 const err_msg = kv.value;937 const err_msg = kv.value;
649 const source = try self.getSource(decl.scope);938 const source = try decl.scope.getSource(self);
650 try AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg.*);939 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
651 }940 }
652 }941 }
653 {942 {
...@@ -655,12 +944,12 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {...@@ -655,12 +944,12 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
655 while (it.next()) |kv| {944 while (it.next()) |kv| {
656 const decl = kv.key.owner_decl;945 const decl = kv.key.owner_decl;
657 const err_msg = kv.value;946 const err_msg = kv.value;
658 const source = try self.getSource(decl.scope);947 const source = try decl.scope.getSource(self);
659 try AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg.*);948 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
660 }949 }
661 }950 }
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) {
664 try errors.append(.{953 try errors.append(.{
665 .src_path = self.root_pkg.root_src_path,954 .src_path = self.root_pkg.root_src_path,
666 .line = 0,955 .line = 0,
...@@ -683,12 +972,14 @@ const InnerError = error{ OutOfMemory, AnalysisFail };...@@ -683,12 +972,14 @@ const InnerError = error{ OutOfMemory, AnalysisFail };
683pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {972pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
684 while (self.work_queue.readItem()) |work_item| switch (work_item) {973 while (self.work_queue.readItem()) |work_item| switch (work_item) {
685 .codegen_decl => |decl| switch (decl.analysis) {974 .codegen_decl => |decl| switch (decl.analysis) {
975 .unreferenced => unreachable,
686 .in_progress => unreachable,976 .in_progress => unreachable,
687 .outdated => unreachable,977 .outdated => unreachable,
688978
689 .sema_failure,979 .sema_failure,
690 .codegen_failure,980 .codegen_failure,
691 .dependency_failure,981 .dependency_failure,
982 .sema_failure_retryable,
692 => continue,983 => continue,
693984
694 .complete, .codegen_failure_retryable => {985 .complete, .codegen_failure_retryable => {
...@@ -696,12 +987,10 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {...@@ -696,12 +987,10 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
696 switch (payload.func.analysis) {987 switch (payload.func.analysis) {
697 .queued => self.analyzeFnBody(decl, payload.func) catch |err| switch (err) {988 .queued => self.analyzeFnBody(decl, payload.func) catch |err| switch (err) {
698 error.AnalysisFail => {989 error.AnalysisFail => {
699 if (payload.func.analysis == .queued) {990 assert(payload.func.analysis != .in_progress);
700 payload.func.analysis = .dependency_failure;
701 }
702 continue;991 continue;
703 },992 },
704 else => |e| return e,993 error.OutOfMemory => return error.OutOfMemory,
705 },994 },
706 .in_progress => unreachable,995 .in_progress => unreachable,
707 .sema_failure, .dependency_failure => continue,996 .sema_failure, .dependency_failure => continue,
...@@ -720,7 +1009,7 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {...@@ -720,7 +1009,7 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
720 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);1009 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
721 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(1010 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
722 self.allocator,1011 self.allocator,
723 decl.src,1012 decl.src(),
724 "unable to codegen: {}",1013 "unable to codegen: {}",
725 .{@errorName(err)},1014 .{@errorName(err)},
726 ));1015 ));
...@@ -729,41 +1018,560 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {...@@ -729,41 +1018,560 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
729 };1018 };
730 },1019 },
731 },1020 },
732 .re_analyze_decl => |decl| switch (decl.analysis) {1021 .analyze_decl => |decl| {
733 .in_progress => unreachable,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,1030fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
736 .codegen_failure,1031 const tracy = trace(@src());
737 .dependency_failure,1032 defer tracy.end();
738 .complete,
739 .codegen_failure_retryable,
740 => continue,
7411033
742 .outdated => {1034 const subsequent_analysis = switch (decl.analysis) {
743 const zir_module = self.getSrcModule(decl.scope) catch |err| switch (err) {1035 .in_progress => unreachable,
744 error.OutOfMemory => return error.OutOfMemory,1036
745 else => {1037 .sema_failure,
746 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);1038 .sema_failure_retryable,
747 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(1039 .codegen_failure,
748 self.allocator,1040 .dependency_failure,
749 decl.src,1041 .codegen_failure_retryable,
750 "unable to load source file '{}': {}",1042 => return error.AnalysisFail,
751 .{ decl.scope.sub_file_path, @errorName(err) },1043
752 ));1044 .complete, .outdated => blk: {
753 decl.analysis = .codegen_failure_retryable;1045 if (decl.generation == self.generation) {
754 continue;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);
755 },1109 },
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),
756 };1207 };
757 const decl_name = mem.spanZ(decl.name);1208 errdefer gen_scope.arena.deinit();
758 // We already detected deletions, so we know this will be found.1209 defer gen_scope.instructions.deinit();
759 const src_decl = zir_module.findDecl(decl_name).?;1210
760 self.reAnalyzeDecl(decl, src_decl) catch |err| switch (err) {1211 const body_block = body_node.cast(ast.Node.Block).?;
761 error.OutOfMemory => return error.OutOfMemory,1212
762 error.AnalysisFail => continue,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,
763 };1221 };
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;
765 },1274 },
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,
766 };1379 };
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;
767}1575}
7681576
769fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {1577fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {
...@@ -775,28 +1583,11 @@ fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void...@@ -775,28 +1583,11 @@ fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void
775 } else {1583 } else {
776 depender.dependencies.appendAssumeCapacity(dependee);1584 depender.dependencies.appendAssumeCapacity(dependee);
777 }1585 }
7781586
779 for (dependee.dependants.items) |item| {1587 for (dependee.dependants.items) |item| {
780 if (item == depender) break; // Already in the set.1588 if (item == depender) break; // Already in the set.
781 } else {1589 } else {
782 dependee.dependants.appendAssumeCapacity(depender);1590 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,
800 }1591 }
801}1592}
8021593
...@@ -805,7 +1596,7 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {...@@ -805,7 +1596,7 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
805 .never_loaded, .unloaded_success => {1596 .never_loaded, .unloaded_success => {
806 try self.failed_files.ensureCapacity(self.failed_files.size + 1);1597 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
810 var keep_zir_module = false;1601 var keep_zir_module = false;
811 const zir_module = try self.allocator.create(zir.Module);1602 const zir_module = try self.allocator.create(zir.Module);
...@@ -816,7 +1607,7 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {...@@ -816,7 +1607,7 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
8161607
817 if (zir_module.error_msg) |src_err_msg| {1608 if (zir_module.error_msg) |src_err_msg| {
818 self.failed_files.putAssumeCapacityNoClobber(1609 self.failed_files.putAssumeCapacityNoClobber(
819 root_scope,1610 &root_scope.base,
820 try ErrorMsg.create(self.allocator, src_err_msg.byte_offset, "{}", .{src_err_msg.msg}),1611 try ErrorMsg.create(self.allocator, src_err_msg.byte_offset, "{}", .{src_err_msg.msg}),
821 );1612 );
822 root_scope.status = .unloaded_parse_failure;1613 root_scope.status = .unloaded_parse_failure;
...@@ -838,90 +1629,189 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {...@@ -838,90 +1629,189 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
838 }1629 }
839}1630}
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
842 switch (root_scope.status) {1636 switch (root_scope.status) {
843 .never_loaded => {1637 .never_loaded, .unloaded_success => {
844 const src_module = try self.getSrcModule(root_scope);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 use1640 const source = try root_scope.getSource(self);
847 // appendAssumeCapacity.
848 try self.work_queue.ensureUnusedCapacity(src_module.decls.len);
8491641
850 for (src_module.decls) |decl| {1642 var keep_tree = false;
851 if (decl.cast(zir.Inst.Export)) |export_inst| {1643 const tree = try std.zig.parse(self.allocator, source);
852 _ = try self.resolveDecl(&root_scope.base, &export_inst.base);1644 defer if (!keep_tree) tree.deinit();
853 }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;
854 }1662 }
1663
1664 root_scope.status = .loaded_success;
1665 root_scope.contents = .{ .tree = tree };
1666 keep_tree = true;
1667
1668 return tree;
855 },1669 },
8561670
857 .unloaded_parse_failure,1671 .unloaded_parse_failure => return error.AnalysisFail,
858 .unloaded_sema_failure,1672
859 .unloaded_success,1673 .loaded_success => return root_scope.contents.tree,
860 .loaded_sema_failure,1674 }
861 .loaded_success,1675}
862 => {1676
863 const src_module = try self.getSrcModule(root_scope);1677fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
8641678 // We may be analyzing it for the first time, or this may be
865 var exports_to_resolve = std.ArrayList(*zir.Inst).init(self.allocator);1679 // an incremental update. This code handles both cases.
866 defer exports_to_resolve.deinit();1680 const tree = try self.getAstTree(root_scope);
8671681 const decls = tree.root_node.decls();
868 // Keep track of the decls that we expect to see in this file so that1682
869 // we know which ones have been deleted.1683 try self.work_queue.ensureUnusedCapacity(decls.len);
870 var deleted_decls = std.AutoHashMap(*Decl, void).init(self.allocator);1684 try root_scope.decls.ensureCapacity(self.allocator, decls.len);
871 defer deleted_decls.deinit();1685
872 try deleted_decls.ensureCapacity(self.decl_table.size);1686 // Keep track of the decls that we expect to see in this file so that
873 {1687 // we know which ones have been deleted.
874 var it = self.decl_table.iterator();1688 var deleted_decls = std.AutoHashMap(*Decl, void).init(self.allocator);
875 while (it.next()) |kv| {1689 defer deleted_decls.deinit();
876 deleted_decls.putAssumeCapacityNoClobber(kv.value, {});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;
877 }1713 }
878 }1714 } else {
8791715 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
880 for (src_module.decls) |src_decl| {1716 root_scope.decls.appendAssumeCapacity(new_decl);
881 const name_hash = Decl.hashSimpleName(src_decl.name);1717 if (fn_proto.extern_export_inline_token) |maybe_export_token| {
882 if (self.decl_table.get(name_hash)) |kv| {1718 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
883 const decl = kv.value;1719 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
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;
891 }1720 }
892 } else if (src_decl.cast(zir.Inst.Export)) |export_inst| {
893 try exports_to_resolve.append(&export_inst.base);
894 }1721 }
895 }1722 }
896 {1723 }
897 // Handle explicitly deleted decls from the source code. Not to be confused1724 // TODO also look for global variable declarations
898 // with when we delete decls because they are no longer referenced.1725 // TODO also look for comptime blocks and exported globals
899 var it = deleted_decls.iterator();1726 }
900 while (it.next()) |kv| {1727 {
901 //std.debug.warn("noticed '{}' deleted from source\n", .{kv.key.name});1728 // Handle explicitly deleted decls from the source code. Not to be confused
902 try self.deleteDecl(kv.key);1729 // with when we delete decls because they are no longer referenced.
903 }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;
904 }1770 }
905 for (exports_to_resolve.items) |export_inst| {1771 } else {
906 _ = try self.resolveDecl(&root_scope.base, export_inst);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);
907 }1782 }
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 }
909 }1796 }
910}1797}
9111798
912fn deleteDecl(self: *Module, decl: *Decl) !void {1799fn deleteDecl(self: *Module, decl: *Decl) !void {
913 try self.deletion_set.ensureCapacity(self.allocator, self.deletion_set.items.len + decl.dependencies.items.len);1800 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
915 //std.debug.warn("deleting decl '{}'\n", .{decl.name});1806 //std.debug.warn("deleting decl '{}'\n", .{decl.name});
916 const name_hash = decl.fullyQualifiedNameHash();1807 const name_hash = decl.fullyQualifiedNameHash();
917 self.decl_table.removeAssertDiscard(name_hash);1808 self.decl_table.removeAssertDiscard(name_hash);
918 // Remove itself from its dependencies, because we are about to destroy the decl pointer.1809 // Remove itself from its dependencies, because we are about to destroy the decl pointer.
919 for (decl.dependencies.items) |dep| {1810 for (decl.dependencies.items) |dep| {
920 dep.removeDependant(decl);1811 dep.removeDependant(decl);
921 if (dep.dependants.items.len == 0) {1812 if (dep.dependants.items.len == 0 and !dep.deletion_flag) {
922 // We don't recursively perform a deletion here, because during the update,1813 // We don't recursively perform a deletion here, because during the update,
923 // another reference to it may turn up.1814 // another reference to it may turn up.
924 assert(!dep.deletion_flag);
925 dep.deletion_flag = true;1815 dep.deletion_flag = true;
926 self.deletion_set.appendAssumeCapacity(dep);1816 self.deletion_set.appendAssumeCapacity(dep);
927 }1817 }
...@@ -974,83 +1864,89 @@ fn deleteDeclExports(self: *Module, decl: *Decl) void {...@@ -974,83 +1864,89 @@ fn deleteDeclExports(self: *Module, decl: *Decl) void {
974}1864}
9751865
976fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {1866fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {
1867 const tracy = trace(@src());
1868 defer tracy.end();
1869
977 // Use the Decl's arena for function memory.1870 // Use the Decl's arena for function memory.
978 var arena = decl.typed_value.most_recent.arena.?.promote(self.allocator);1871 var arena = decl.typed_value.most_recent.arena.?.promote(self.allocator);
979 defer decl.typed_value.most_recent.arena.?.* = arena.state;1872 defer decl.typed_value.most_recent.arena.?.* = arena.state;
980 var analysis: Fn.Analysis = .{1873 var inner_block: Scope.Block = .{
981 .inner_block = .{1874 .func = func,
982 .func = func,1875 .decl = decl,
983 .decl = decl,1876 .instructions = .{},
984 .instructions = .{},1877 .arena = &arena.allocator,
985 .arena = &arena.allocator,
986 },
987 .needed_inst_capacity = 0,
988 .inst_table = std.AutoHashMap(*zir.Inst, *Inst).init(self.allocator),
989 };1878 };
990 defer analysis.inner_block.instructions.deinit(self.allocator);1879 defer inner_block.instructions.deinit(self.allocator);
991 defer analysis.inst_table.deinit();
9921880
993 const fn_inst = func.analysis.queued;1881 const fn_zir = func.analysis.queued;
994 func.analysis = .{ .in_progress = &analysis };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 = .{1888 const instructions = try arena.allocator.dupe(*Inst, inner_block.instructions.items);
999 .success = .{1889 func.analysis = .{ .success = .{ .instructions = instructions } };
1000 .instructions = try arena.allocator.dupe(*Inst, analysis.inner_block.instructions.items),1890 //std.debug.warn("set {} to success\n", .{decl.name});
1001 },
1002 };
1003}1891}
10041892
1005fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!void {1893fn markOutdatedDecl(self: *Module, decl: *Decl) !void {
1006 switch (decl.analysis) {1894 //std.debug.warn("mark {} outdated\n", .{decl.name});
1007 .in_progress => unreachable,1895 try self.work_queue.writeItem(.{ .analyze_decl = decl });
1008 .dependency_failure,1896 if (self.failed_decls.remove(decl)) |entry| {
1009 .sema_failure,1897 entry.value.destroy(self.allocator);
1010 .codegen_failure,
1011 .codegen_failure_retryable,
1012 .complete,
1013 => return,
1014
1015 .outdated => {}, // Decl re-analysis
1016 }1898 }
1017 //std.debug.warn("re-analyzing {}\n", .{decl.name});1899 decl.analysis = .outdated;
1018 decl.src = old_inst.src;1900}
10191901
1020 // The exports this Decl performs will be re-discovered, so we remove them here1902fn allocateNewDecl(
1021 // prior to re-analysis.1903 self: *Module,
1022 self.deleteDeclExports(decl);1904 scope: *Scope,
1023 // Dependencies will be re-discovered, so we remove them here prior to re-analysis.1905 src_index: usize,
1024 for (decl.dependencies.items) |dep| {1906 contents_hash: std.zig.SrcHash,
1025 dep.removeDependant(decl);1907) !*Decl {
1026 if (dep.dependants.items.len == 0) {1908 const new_decl = try self.allocator.create(Decl);
1027 // We don't perform a deletion here, because this Decl or another one1909 new_decl.* = .{
1028 // may end up referencing it before the update is complete.1910 .name = "",
1029 assert(!dep.deletion_flag);1911 .scope = scope.namespace(),
1030 dep.deletion_flag = true;1912 .src_index = src_index,
1031 try self.deletion_set.append(self.allocator, dep);1913 .typed_value = .{ .never_succeeded = {} },
1032 }1914 .analysis = .unreferenced,
1033 }1915 .deletion_flag = false,
1034 decl.dependencies.shrink(self.allocator, 0);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 {
1035 var decl_scope: Scope.DeclAnalysis = .{1940 var decl_scope: Scope.DeclAnalysis = .{
1036 .decl = decl,1941 .decl = decl,
1037 .arena = std.heap.ArenaAllocator.init(self.allocator),1942 .arena = std.heap.ArenaAllocator.init(self.allocator),
1038 };1943 };
1039 errdefer decl_scope.arena.deinit();1944 errdefer decl_scope.arena.deinit();
10401945
1041 const typed_value = self.analyzeInstConst(&decl_scope.base, old_inst) catch |err| switch (err) {1946 decl.analysis = .in_progress;
1042 error.OutOfMemory => return error.OutOfMemory,1947
1043 error.AnalysisFail => {1948 const typed_value = try self.analyzeConstInst(&decl_scope.base, src_decl.inst);
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 };
1052 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);1949 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);
1053 arena_state.* = decl_scope.arena.state;
10541950
1055 var prev_type_has_bits = false;1951 var prev_type_has_bits = false;
1056 var type_changed = true;1952 var type_changed = true;
...@@ -1061,6 +1957,8 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi...@@ -1061,6 +1957,8 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi
10611957
1062 tvm.deinit(self.allocator);1958 tvm.deinit(self.allocator);
1063 }1959 }
1960
1961 arena_state.* = decl_scope.arena.state;
1064 decl.typed_value = .{1962 decl.typed_value = .{
1065 .most_recent = .{1963 .most_recent = .{
1066 .typed_value = typed_value,1964 .typed_value = typed_value,
...@@ -1079,137 +1977,66 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi...@@ -1079,137 +1977,66 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi
1079 self.bin_file.freeDecl(decl);1977 self.bin_file.freeDecl(decl);
1080 }1978 }
10811979
1082 // If the decl is a function, and the type is the same, we do not need1980 return type_changed;
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 }
1101}1981}
11021982
1103fn markOutdatedDecl(self: *Module, decl: *Decl) !void {1983fn resolveZirDecl(self: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!*Decl {
1104 //std.debug.warn("mark {} outdated\n", .{decl.name});1984 const zir_module = self.root_scope.cast(Scope.ZIRModule).?;
1105 try self.work_queue.writeItem(.{ .re_analyze_decl = decl });1985 const entry = zir_module.contents.module.findDecl(src_decl.name).?;
1106 if (self.failed_decls.remove(decl)) |entry| {1986 return self.resolveZirDeclHavingIndex(scope, src_decl, entry.index);
1107 entry.value.destroy(self.allocator);
1108 }
1109 decl.analysis = .outdated;
1110}1987}
11111988
1112fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl {1989fn resolveZirDeclHavingIndex(self: *Module, scope: *Scope, src_decl: *zir.Decl, src_index: usize) InnerError!*Decl {
1113 const hash = Decl.hashSimpleName(old_inst.name);1990 const name_hash = scope.namespace().fullyQualifiedNameHash(src_decl.name);
1114 if (self.decl_table.get(hash)) |kv| {1991 const decl = self.decl_table.getValue(name_hash).?;
1115 const decl = kv.value;1992 decl.src_index = src_index;
1116 try self.reAnalyzeDecl(decl, old_inst);1993 try self.ensureDeclAnalyzed(decl);
1117 return decl;1994 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 }
1181}1995}
11821996
1183/// Declares a dependency on the decl.1997/// Declares a dependency on the decl.
1184fn resolveCompleteDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl {1998fn resolveCompleteZirDecl(self: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!*Decl {
1185 const decl = try self.resolveDecl(scope, old_inst);1999 const decl = try self.resolveZirDecl(scope, src_decl);
1186 switch (decl.analysis) {2000 switch (decl.analysis) {
2001 .unreferenced => unreachable,
1187 .in_progress => unreachable,2002 .in_progress => unreachable,
1188 .outdated => unreachable,2003 .outdated => unreachable,
11892004
1190 .dependency_failure,2005 .dependency_failure,
1191 .sema_failure,2006 .sema_failure,
2007 .sema_failure_retryable,
1192 .codegen_failure,2008 .codegen_failure,
1193 .codegen_failure_retryable,2009 .codegen_failure_retryable,
1194 => return error.AnalysisFail,2010 => return error.AnalysisFail,
11952011
1196 .complete => {},2012 .complete => {},
1197 }2013 }
1198 if (scope.decl()) |scope_decl| {
1199 try self.declareDeclDependency(scope_decl, decl);
1200 }
1201 return decl;2014 return decl;
1202}2015}
12032016
2017/// TODO Look into removing this function. The body is only needed for .zir files, not .zig files.
1204fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {2018fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
1205 if (scope.cast(Scope.Block)) |block| {2019 if (old_inst.analyzed_inst) |inst| return inst;
1206 if (block.func.analysis.in_progress.inst_table.get(old_inst)) |kv| {2020
1207 return kv.value;2021 // If this assert trips, the instruction that was referenced did not get properly
1208 }2022 // analyzed before it was referenced.
1209 }2023 const zir_module = scope.namespace().cast(Scope.ZIRModule).?;
12102024 const entry = if (old_inst.cast(zir.Inst.DeclVal)) |declval| blk: {
1211 const decl = try self.resolveCompleteDecl(scope, old_inst);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);
1212 const decl_ref = try self.analyzeDeclRef(scope, old_inst.src, decl);2036 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.
1213 return self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src);2040 return self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src);
1214}2041}
12152042
...@@ -1258,21 +2085,16 @@ fn resolveType(self: *Module, scope: *Scope, old_inst: *zir.Inst) !Type {...@@ -1258,21 +2085,16 @@ fn resolveType(self: *Module, scope: *Scope, old_inst: *zir.Inst) !Type {
1258 return val.toType();2085 return val.toType();
1259}2086}
12602087
1261fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) InnerError!void {2088fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const u8, exported_decl: *Decl) !void {
1262 try self.decl_exports.ensureCapacity(self.decl_exports.size + 1);2089 try self.ensureDeclAnalyzed(exported_decl);
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);
1266 const typed_value = exported_decl.typed_value.most_recent.typed_value;2090 const typed_value = exported_decl.typed_value.most_recent.typed_value;
1267 switch (typed_value.ty.zigTypeTag()) {2091 switch (typed_value.ty.zigTypeTag()) {
1268 .Fn => {},2092 .Fn => {},
1269 else => return self.fail(2093 else => return self.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}),
1270 scope,
1271 export_inst.positionals.value.src,
1272 "unable to export type '{}'",
1273 .{typed_value.ty},
1274 ),
1275 }2094 }
2095 try self.decl_exports.ensureCapacity(self.decl_exports.size + 1);
2096 try self.export_owners.ensureCapacity(self.export_owners.size + 1);
2097
1276 const new_export = try self.allocator.create(Export);2098 const new_export = try self.allocator.create(Export);
1277 errdefer self.allocator.destroy(new_export);2099 errdefer self.allocator.destroy(new_export);
12782100
...@@ -1280,7 +2102,7 @@ fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) In...@@ -1280,7 +2102,7 @@ fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) In
12802102
1281 new_export.* = .{2103 new_export.* = .{
1282 .options = .{ .name = symbol_name },2104 .options = .{ .name = symbol_name },
1283 .src = export_inst.base.src,2105 .src = src,
1284 .link = .{},2106 .link = .{},
1285 .owner_decl = owner_decl,2107 .owner_decl = owner_decl,
1286 .exported_decl = exported_decl,2108 .exported_decl = exported_decl,
...@@ -1311,7 +2133,7 @@ fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) In...@@ -1311,7 +2133,7 @@ fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) In
1311 try self.failed_exports.ensureCapacity(self.failed_exports.size + 1);2133 try self.failed_exports.ensureCapacity(self.failed_exports.size + 1);
1312 self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create(2134 self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create(
1313 self.allocator,2135 self.allocator,
1314 export_inst.base.src,2136 src,
1315 "unable to export: {}",2137 "unable to export: {}",
1316 .{@errorName(err)},2138 .{@errorName(err)},
1317 ));2139 ));
...@@ -1320,7 +2142,6 @@ fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) In...@@ -1320,7 +2142,6 @@ fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) In
1320 };2142 };
1321}2143}
13222144
1323/// TODO should not need the cast on the last parameter at the callsites
1324fn addNewInstArgs(2145fn addNewInstArgs(
1325 self: *Module,2146 self: *Module,
1326 block: *Scope.Block,2147 block: *Scope.Block,
...@@ -1334,6 +2155,46 @@ fn addNewInstArgs(...@@ -1334,6 +2155,46 @@ fn addNewInstArgs(
1334 return &inst.base;2155 return &inst.base;
1335}2156}
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
1337fn addNewInst(self: *Module, block: *Scope.Block, src: usize, ty: Type, comptime T: type) !*T {2198fn addNewInst(self: *Module, block: *Scope.Block, src: usize, ty: Type, comptime T: type) !*T {
1338 const inst = try block.arena.create(T);2199 const inst = try block.arena.create(T);
1339 inst.* = .{2200 inst.* = .{
...@@ -1361,19 +2222,6 @@ fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue)...@@ -1361,19 +2222,6 @@ fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue)
1361 return &const_inst.base;2222 return &const_inst.base;
1362}2223}
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
1377fn constType(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {2225fn constType(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {
1378 return self.constInst(scope, src, .{2226 return self.constInst(scope, src, .{
1379 .ty = Type.initTag(.type),2227 .ty = Type.initTag(.type),
...@@ -1388,6 +2236,13 @@ fn constVoid(self: *Module, scope: *Scope, src: usize) !*Inst {...@@ -1388,6 +2236,13 @@ fn constVoid(self: *Module, scope: *Scope, src: usize) !*Inst {
1388 });2236 });
1389}2237}
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
1391fn constUndef(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {2246fn constUndef(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {
1392 return self.constInst(scope, src, .{2247 return self.constInst(scope, src, .{
1393 .ty = ty,2248 .ty = ty,
...@@ -1451,7 +2306,7 @@ fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigI...@@ -1451,7 +2306,7 @@ fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigI
1451 });2306 });
1452}2307}
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 {
1455 const new_inst = try self.analyzeInst(scope, old_inst);2310 const new_inst = try self.analyzeInst(scope, old_inst);
1456 return TypedValue{2311 return TypedValue{
1457 .ty = new_inst.ty,2312 .ty = new_inst.ty,
...@@ -1459,20 +2314,24 @@ fn analyzeInstConst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerErro...@@ -1459,20 +2314,24 @@ fn analyzeInstConst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerErro
1459 };2314 };
1460}2315}
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
1462fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {2324fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
1463 switch (old_inst.tag) {2325 switch (old_inst.tag) {
1464 .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?),2326 .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?),
1465 .call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?),2327 .call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?),
1466 .compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?),2328 .compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?),
2329 .@"const" => return self.analyzeInstConst(scope, old_inst.cast(zir.Inst.Const).?),
1467 .declref => return self.analyzeInstDeclRef(scope, old_inst.cast(zir.Inst.DeclRef).?),2330 .declref => return self.analyzeInstDeclRef(scope, old_inst.cast(zir.Inst.DeclRef).?),
2331 .declref_str => return self.analyzeInstDeclRefStr(scope, old_inst.cast(zir.Inst.DeclRefStr).?),
1468 .declval => return self.analyzeInstDeclVal(scope, old_inst.cast(zir.Inst.DeclVal).?),2332 .declval => return self.analyzeInstDeclVal(scope, old_inst.cast(zir.Inst.DeclVal).?),
1469 .str => {2333 .declval_in_module => return self.analyzeInstDeclValInModule(scope, old_inst.cast(zir.Inst.DeclValInModule).?),
1470 const bytes = old_inst.cast(zir.Inst.Str).?.positionals.bytes;2334 .str => return self.analyzeInstStr(scope, old_inst.cast(zir.Inst.Str).?),
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 },
1476 .int => {2335 .int => {
1477 const big_int = old_inst.cast(zir.Inst.Int).?.positionals.int;2336 const big_int = old_inst.cast(zir.Inst.Int).?.positionals.int;
1478 return self.constIntBig(scope, old_inst.src, Type.initTag(.comptime_int), big_int);2337 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...@@ -1484,13 +2343,10 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
1484 .@"asm" => return self.analyzeInstAsm(scope, old_inst.cast(zir.Inst.Asm).?),2343 .@"asm" => return self.analyzeInstAsm(scope, old_inst.cast(zir.Inst.Asm).?),
1485 .@"unreachable" => return self.analyzeInstUnreachable(scope, old_inst.cast(zir.Inst.Unreachable).?),2344 .@"unreachable" => return self.analyzeInstUnreachable(scope, old_inst.cast(zir.Inst.Unreachable).?),
1486 .@"return" => return self.analyzeInstRet(scope, old_inst.cast(zir.Inst.Return).?),2345 .@"return" => return self.analyzeInstRet(scope, old_inst.cast(zir.Inst.Return).?),
2346 .returnvoid => return self.analyzeInstRetVoid(scope, old_inst.cast(zir.Inst.ReturnVoid).?),
1487 .@"fn" => return self.analyzeInstFn(scope, old_inst.cast(zir.Inst.Fn).?),2347 .@"fn" => return self.analyzeInstFn(scope, old_inst.cast(zir.Inst.Fn).?),
1488 .@"export" => {2348 .@"export" => return self.analyzeInstExport(scope, old_inst.cast(zir.Inst.Export).?),
1489 try self.analyzeExport(scope, old_inst.cast(zir.Inst.Export).?);
1490 return self.constVoid(scope, old_inst.src);
1491 },
1492 .primitive => return self.analyzeInstPrimitive(scope, old_inst.cast(zir.Inst.Primitive).?),2349 .primitive => return self.analyzeInstPrimitive(scope, old_inst.cast(zir.Inst.Primitive).?),
1493 .ref => return self.analyzeInstRef(scope, old_inst.cast(zir.Inst.Ref).?),
1494 .fntype => return self.analyzeInstFnType(scope, old_inst.cast(zir.Inst.FnType).?),2350 .fntype => return self.analyzeInstFnType(scope, old_inst.cast(zir.Inst.FnType).?),
1495 .intcast => return self.analyzeInstIntCast(scope, old_inst.cast(zir.Inst.IntCast).?),2351 .intcast => return self.analyzeInstIntCast(scope, old_inst.cast(zir.Inst.IntCast).?),
1496 .bitcast => return self.analyzeInstBitCast(scope, old_inst.cast(zir.Inst.BitCast).?),2352 .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...@@ -1503,39 +2359,104 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
1503 }2359 }
1504}2360}
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
1506fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.CompileError) InnerError!*Inst {2435fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.CompileError) InnerError!*Inst {
1507 return self.fail(scope, inst.base.src, "{}", .{inst.positionals.msg});2436 return self.fail(scope, inst.base.src, "{}", .{inst.positionals.msg});
1508}2437}
15092438
1510fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoint) InnerError!*Inst {2439fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoint) InnerError!*Inst {
1511 const b = try self.requireRuntimeBlock(scope, inst.base.src);2440 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, {});
1513}2442}
15142443
1515fn analyzeInstRef(self: *Module, scope: *Scope, inst: *zir.Inst.Ref) InnerError!*Inst {2444fn analyzeInstDeclRefStr(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr) InnerError!*Inst {
1516 const decl = try self.resolveCompleteDecl(scope, inst.positionals.operand);2445 const decl_name = try self.resolveConstString(scope, inst.positionals.name);
1517 return self.analyzeDeclRef(scope, inst.base.src, decl);2446 return self.analyzeDeclRefByName(scope, inst.base.src, decl_name);
1518}2447}
15192448
1520fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst {2449fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst {
1521 const decl_name = try self.resolveConstString(scope, inst.positionals.name);2450 return self.analyzeDeclRefByName(scope, inst.base.src, 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);
1529}2451}
15302452
1531fn analyzeDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Decl {2453fn analyzeDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Decl {
1532 const decl_name = inst.positionals.name;2454 const decl_name = inst.positionals.name;
1533 // This will need to get more fleshed out when there are proper structs & namespaces.2455 const zir_module = scope.namespace().cast(Scope.ZIRModule).?;
1534 const zir_module = scope.namespace();
1535 const src_decl = zir_module.contents.module.findDecl(decl_name) orelse2456 const src_decl = zir_module.contents.module.findDecl(decl_name) orelse
1536 return self.fail(scope, inst.base.src, "use of undeclared identifier '{}'", .{decl_name});2457 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
1540 return decl;2461 return decl;
1541}2462}
...@@ -1546,18 +2467,46 @@ fn analyzeInstDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) Inn...@@ -1546,18 +2467,46 @@ fn analyzeInstDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) Inn
1546 return self.analyzeDeref(scope, inst.base.src, ptr, inst.base.src);2467 return self.analyzeDeref(scope, inst.base.src, ptr, inst.base.src);
1547}2468}
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
1549fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {2476fn 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
1550 const decl_tv = try decl.typedValue();2492 const decl_tv = try decl.typedValue();
1551 const ty_payload = try scope.arena().create(Type.Payload.SingleConstPointer);2493 const ty_payload = try scope.arena().create(Type.Payload.SingleConstPointer);
1552 ty_payload.* = .{ .pointee_type = decl_tv.ty };2494 ty_payload.* = .{ .pointee_type = decl_tv.ty };
1553 const val_payload = try scope.arena().create(Value.Payload.DeclRef);2495 const val_payload = try scope.arena().create(Value.Payload.DeclRef);
1554 val_payload.* = .{ .decl = decl };2496 val_payload.* = .{ .decl = decl };
2497
1555 return self.constInst(scope, src, .{2498 return self.constInst(scope, src, .{
1556 .ty = Type.initPayload(&ty_payload.base),2499 .ty = Type.initPayload(&ty_payload.base),
1557 .val = Value.initPayload(&val_payload.base),2500 .val = Value.initPayload(&val_payload.base),
1558 });2501 });
1559}2502}
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
1561fn analyzeInstCall(self: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {2510fn analyzeInstCall(self: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
1562 const func = try self.resolveInst(scope, inst.positionals.func);2511 const func = try self.resolveInst(scope, inst.positionals.func);
1563 if (func.ty.zigTypeTag() != .Fn)2512 if (func.ty.zigTypeTag() != .Fn)
...@@ -1616,7 +2565,7 @@ fn analyzeInstCall(self: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerErro...@@ -1616,7 +2565,7 @@ fn analyzeInstCall(self: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerErro
1616 }2565 }
16172566
1618 const b = try self.requireRuntimeBlock(scope, inst.base.src);2567 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, .{
1620 .func = func,2569 .func = func,
1621 .args = casted_args,2570 .args = casted_args,
1622 });2571 });
...@@ -1624,10 +2573,22 @@ fn analyzeInstCall(self: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerErro...@@ -1624,10 +2573,22 @@ fn analyzeInstCall(self: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerErro
16242573
1625fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst {2574fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst {
1626 const fn_type = try self.resolveType(scope, fn_inst.positionals.fn_type);2575 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 };
1627 const new_func = try scope.arena().create(Fn);2589 const new_func = try scope.arena().create(Fn);
1628 new_func.* = .{2590 new_func.* = .{
1629 .fn_type = fn_type,2591 .analysis = .{ .queued = fn_zir },
1630 .analysis = .{ .queued = fn_inst },
1631 .owner_decl = scope.decl().?,2592 .owner_decl = scope.decl().?,
1632 };2593 };
1633 const fn_payload = try scope.arena().create(Value.Payload.Function);2594 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...@@ -1648,6 +2609,13 @@ fn analyzeInstFnType(self: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inn
1648 return self.constType(scope, fntype.base.src, Type.initTag(.fn_noreturn_no_args));2609 return self.constType(scope, fntype.base.src, Type.initTag(.fn_noreturn_no_args));
1649 }2610 }
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
1651 if (return_type.zigTypeTag() == .NoReturn and2619 if (return_type.zigTypeTag() == .NoReturn and
1652 fntype.positionals.param_types.len == 0 and2620 fntype.positionals.param_types.len == 0 and
1653 fntype.kw_args.cc == .Naked)2621 fntype.kw_args.cc == .Naked)
...@@ -1683,7 +2651,7 @@ fn analyzeInstPtrToInt(self: *Module, scope: *Scope, ptrtoint: *zir.Inst.PtrToIn...@@ -1683,7 +2651,7 @@ fn analyzeInstPtrToInt(self: *Module, scope: *Scope, ptrtoint: *zir.Inst.PtrToIn
1683 // TODO handle known-pointer-address2651 // TODO handle known-pointer-address
1684 const b = try self.requireRuntimeBlock(scope, ptrtoint.base.src);2652 const b = try self.requireRuntimeBlock(scope, ptrtoint.base.src);
1685 const ty = Type.initTag(.usize);2653 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 });
1687}2655}
16882656
1689fn analyzeInstFieldPtr(self: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr) InnerError!*Inst {2657fn 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...@@ -1875,7 +2843,7 @@ fn analyzeInstAsm(self: *Module, scope: *Scope, assembly: *zir.Inst.Asm) InnerEr
1875 }2843 }
18762844
1877 const b = try self.requireRuntimeBlock(scope, assembly.base.src);2845 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, .{
1879 .asm_source = asm_source,2847 .asm_source = asm_source,
1880 .is_volatile = assembly.kw_args.@"volatile",2848 .is_volatile = assembly.kw_args.@"volatile",
1881 .output = output,2849 .output = output,
...@@ -1911,20 +2879,12 @@ fn analyzeInstCmp(self: *Module, scope: *Scope, inst: *zir.Inst.Cmp) InnerError!...@@ -1911,20 +2879,12 @@ fn analyzeInstCmp(self: *Module, scope: *Scope, inst: *zir.Inst.Cmp) InnerError!
1911 }2879 }
1912 const b = try self.requireRuntimeBlock(scope, inst.base.src);2880 const b = try self.requireRuntimeBlock(scope, inst.base.src);
1913 switch (op) {2881 switch (op) {
1914 .eq => return self.addNewInstArgs(2882 .eq => return self.addNewInstArgs(b, inst.base.src, Type.initTag(.bool), Inst.IsNull, .{
1915 b,2883 .operand = opt_operand,
1916 inst.base.src,2884 }),
1917 Type.initTag(.bool),2885 .neq => return self.addNewInstArgs(b, inst.base.src, Type.initTag(.bool), Inst.IsNonNull, .{
1918 Inst.IsNull,2886 .operand = opt_operand,
1919 Inst.Args(Inst.IsNull){ .operand = opt_operand },2887 }),
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 ),
1928 else => unreachable,2888 else => unreachable,
1929 }2889 }
1930 } else if (is_equality_cmp and2890 } else if (is_equality_cmp and
...@@ -2019,23 +2979,19 @@ fn analyzeInstUnreachable(self: *Module, scope: *Scope, unreach: *zir.Inst.Unrea...@@ -2019,23 +2979,19 @@ fn analyzeInstUnreachable(self: *Module, scope: *Scope, unreach: *zir.Inst.Unrea
2019}2979}
20202980
2021fn analyzeInstRet(self: *Module, scope: *Scope, inst: *zir.Inst.Return) InnerError!*Inst {2981fn 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 {
2022 const b = try self.requireRuntimeBlock(scope, inst.base.src);2988 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, {});
2024}2990}
20252991
2026fn analyzeBody(self: *Module, scope: *Scope, body: zir.Module.Body) !void {2992fn analyzeBody(self: *Module, scope: *Scope, body: zir.Module.Body) !void {
2027 if (scope.cast(Scope.Block)) |b| {2993 for (body.instructions) |src_inst| {
2028 const analysis = b.func.analysis.in_progress;2994 src_inst.analyzed_inst = try self.analyzeInst(scope, src_inst);
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 }
2039 }2995 }
2040}2996}
20412997
...@@ -2118,7 +3074,7 @@ fn cmpNumeric(...@@ -2118,7 +3074,7 @@ fn cmpNumeric(
2118 };3074 };
2119 const casted_lhs = try self.coerce(scope, dest_type, lhs);3075 const casted_lhs = try self.coerce(scope, dest_type, lhs);
2120 const casted_rhs = try self.coerce(scope, dest_type, rhs);3076 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, .{
2122 .lhs = casted_lhs,3078 .lhs = casted_lhs,
2123 .rhs = casted_rhs,3079 .rhs = casted_rhs,
2124 .op = op,3080 .op = op,
...@@ -2222,7 +3178,7 @@ fn cmpNumeric(...@@ -2222,7 +3178,7 @@ fn cmpNumeric(
2222 const casted_lhs = try self.coerce(scope, dest_type, lhs);3178 const casted_lhs = try self.coerce(scope, dest_type, lhs);
2223 const casted_rhs = try self.coerce(scope, dest_type, lhs);3179 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, .{
2226 .lhs = casted_lhs,3182 .lhs = casted_lhs,
2227 .rhs = casted_rhs,3183 .rhs = casted_rhs,
2228 .op = op,3184 .op = op,
...@@ -2299,7 +3255,7 @@ fn bitcast(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {...@@ -2299,7 +3255,7 @@ fn bitcast(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
2299 }3255 }
2300 // TODO validate the type size and other compile errors3256 // TODO validate the type size and other compile errors
2301 const b = try self.requireRuntimeBlock(scope, inst.src);3257 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 });
2303}3259}
23043260
2305fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {3261fn 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...@@ -2316,6 +3272,30 @@ fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, a
2316 return self.failWithOwnedErrorMsg(scope, src, err_msg);3272 return self.failWithOwnedErrorMsg(scope, src, err_msg);
2317}3273}
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
2319fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *ErrorMsg) InnerError {3299fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *ErrorMsg) InnerError {
2320 {3300 {
2321 errdefer err_msg.destroy(self.allocator);3301 errdefer err_msg.destroy(self.allocator);
...@@ -2326,18 +3306,31 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err...@@ -2326,18 +3306,31 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err
2326 .decl => {3306 .decl => {
2327 const decl = scope.cast(Scope.DeclAnalysis).?.decl;3307 const decl = scope.cast(Scope.DeclAnalysis).?.decl;
2328 decl.analysis = .sema_failure;3308 decl.analysis = .sema_failure;
3309 decl.generation = self.generation;
2329 self.failed_decls.putAssumeCapacityNoClobber(decl, err_msg);3310 self.failed_decls.putAssumeCapacityNoClobber(decl, err_msg);
2330 },3311 },
2331 .block => {3312 .block => {
2332 const block = scope.cast(Scope.Block).?;3313 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 }
2334 self.failed_decls.putAssumeCapacityNoClobber(block.decl, err_msg);3320 self.failed_decls.putAssumeCapacityNoClobber(block.decl, err_msg);
2335 },3321 },
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 },
2336 .zir_module => {3328 .zir_module => {
2337 const zir_module = scope.cast(Scope.ZIRModule).?;3329 const zir_module = scope.cast(Scope.ZIRModule).?;
2338 zir_module.status = .loaded_sema_failure;3330 zir_module.status = .loaded_sema_failure;
2339 self.failed_files.putAssumeCapacityNoClobber(zir_module, err_msg);3331 self.failed_files.putAssumeCapacityNoClobber(scope, err_msg);
2340 },3332 },
3333 .file => unreachable,
2341 }3334 }
2342 return error.AnalysisFail;3335 return error.AnalysisFail;
2343}3336}
...@@ -2385,3 +3378,7 @@ pub const ErrorMsg = struct {...@@ -2385,3 +3378,7 @@ pub const ErrorMsg = struct {
2385 self.* = undefined;3378 self.* = undefined;
2386 }3379 }
2387};3380};
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 {...@@ -21,3 +21,11 @@ pub const Managed = struct {
21 self.* = undefined;21 self.* = undefined;
22 }22 }
23};23};
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");...@@ -10,6 +10,7 @@ const Module = @import("Module.zig");
10const ErrorMsg = Module.ErrorMsg;10const ErrorMsg = Module.ErrorMsg;
11const Target = std.Target;11const Target = std.Target;
12const Allocator = mem.Allocator;12const Allocator = mem.Allocator;
13const trace = @import("tracy.zig").trace;
1314
14pub const Result = union(enum) {15pub const Result = union(enum) {
15 /// The `code` parameter passed to `generateSymbol` has the value appended.16 /// The `code` parameter passed to `generateSymbol` has the value appended.
...@@ -29,6 +30,9 @@ pub fn generateSymbol(...@@ -29,6 +30,9 @@ pub fn generateSymbol(
29 /// A Decl that this symbol depends on had a semantic analysis failure.30 /// A Decl that this symbol depends on had a semantic analysis failure.
30 AnalysisFail,31 AnalysisFail,
31}!Result {32}!Result {
33 const tracy = trace(@src());
34 defer tracy.end();
35
32 switch (typed_value.ty.zigTypeTag()) {36 switch (typed_value.ty.zigTypeTag()) {
33 .Fn => {37 .Fn => {
34 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;38 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
...@@ -178,6 +182,7 @@ const Function = struct {...@@ -178,6 +182,7 @@ const Function = struct {
178 .ptrtoint => return self.genPtrToInt(inst.cast(ir.Inst.PtrToInt).?),182 .ptrtoint => return self.genPtrToInt(inst.cast(ir.Inst.PtrToInt).?),
179 .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?),183 .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?),
180 .ret => return self.genRet(inst.cast(ir.Inst.Ret).?),184 .ret => return self.genRet(inst.cast(ir.Inst.Ret).?),
185 .retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?),
181 .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?),186 .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?),
182 .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?),187 .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?),
183 .isnull => return self.genIsNull(inst.cast(ir.Inst.IsNull).?),188 .isnull => return self.genIsNull(inst.cast(ir.Inst.IsNull).?),
...@@ -213,7 +218,7 @@ const Function = struct {...@@ -213,7 +218,7 @@ const Function = struct {
213 try self.code.resize(self.code.items.len + 7);218 try self.code.resize(self.code.items.len + 7);
214 self.code.items[self.code.items.len - 7 ..][0..3].* = [3]u8{ 0xff, 0x14, 0x25 };219 self.code.items[self.code.items.len - 7 ..][0..3].* = [3]u8{ 0xff, 0x14, 0x25 };
215 mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], got_addr);220 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();
217 switch (return_type.zigTypeTag()) {222 switch (return_type.zigTypeTag()) {
218 .Void => return MCValue{ .none = {} },223 .Void => return MCValue{ .none = {} },
219 .NoReturn => return MCValue{ .unreach = {} },224 .NoReturn => return MCValue{ .unreach = {} },
...@@ -230,16 +235,28 @@ const Function = struct {...@@ -230,16 +235,28 @@ const Function = struct {
230 }235 }
231 }236 }
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 }
234 switch (self.target.cpu.arch) {242 switch (self.target.cpu.arch) {
235 .i386, .x86_64 => {243 .i386, .x86_64 => {
236 try self.code.append(0xc3); // ret244 try self.code.append(0xc3); // ret
237 },245 },
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}),
239 }247 }
240 return .unreach;248 return .unreach;
241 }249 }
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
243 fn genCmp(self: *Function, inst: *ir.Inst.Cmp) !MCValue {260 fn genCmp(self: *Function, inst: *ir.Inst.Cmp) !MCValue {
244 switch (self.target.cpu.arch) {261 switch (self.target.cpu.arch) {
245 else => return self.fail(inst.base.src, "TODO implement cmp for {}", .{self.target.cpu.arch}),262 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 {...@@ -26,6 +26,7 @@ pub const Inst = struct {
26 isnull,26 isnull,
27 ptrtoint,27 ptrtoint,
28 ret,28 ret,
29 retvoid,
29 unreach,30 unreach,
30 };31 };
3132
...@@ -146,6 +147,14 @@ pub const Inst = struct {...@@ -146,6 +147,14 @@ pub const Inst = struct {
146 pub const Ret = struct {147 pub const Ret = struct {
147 pub const base_tag = Tag.ret;148 pub const base_tag = Tag.ret;
148 base: Inst,149 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,
149 args: void,158 args: void,
150 };159 };
151160
src-self-hosted/link.zig+12-13
...@@ -369,7 +369,7 @@ pub const ElfFile = struct {...@@ -369,7 +369,7 @@ pub const ElfFile = struct {
369 const file_size = self.options.program_code_size_hint;369 const file_size = self.options.program_code_size_hint;
370 const p_align = 0x1000;370 const p_align = 0x1000;
371 const off = self.findFreeSpace(file_size, p_align);371 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 });
373 try self.program_headers.append(self.allocator, .{373 try self.program_headers.append(self.allocator, .{
374 .p_type = elf.PT_LOAD,374 .p_type = elf.PT_LOAD,
375 .p_offset = off,375 .p_offset = off,
...@@ -390,7 +390,7 @@ pub const ElfFile = struct {...@@ -390,7 +390,7 @@ pub const ElfFile = struct {
390 // page align.390 // page align.
391 const p_align = 0x1000;391 const p_align = 0x1000;
392 const off = self.findFreeSpace(file_size, p_align);392 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 });
394 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.394 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
395 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something395 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
396 // else in virtual memory.396 // else in virtual memory.
...@@ -412,7 +412,7 @@ pub const ElfFile = struct {...@@ -412,7 +412,7 @@ pub const ElfFile = struct {
412 assert(self.shstrtab.items.len == 0);412 assert(self.shstrtab.items.len == 0);
413 try self.shstrtab.append(self.allocator, 0); // need a 0 at position 0413 try self.shstrtab.append(self.allocator, 0); // need a 0 at position 0
414 const off = self.findFreeSpace(self.shstrtab.items.len, 1);414 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 });
416 try self.sections.append(self.allocator, .{416 try self.sections.append(self.allocator, .{
417 .sh_name = try self.makeString(".shstrtab"),417 .sh_name = try self.makeString(".shstrtab"),
418 .sh_type = elf.SHT_STRTAB,418 .sh_type = elf.SHT_STRTAB,
...@@ -470,7 +470,7 @@ pub const ElfFile = struct {...@@ -470,7 +470,7 @@ pub const ElfFile = struct {
470 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);470 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
471 const file_size = self.options.symbol_count_hint * each_size;471 const file_size = self.options.symbol_count_hint * each_size;
472 const off = self.findFreeSpace(file_size, min_align);472 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
475 try self.sections.append(self.allocator, .{475 try self.sections.append(self.allocator, .{
476 .sh_name = try self.makeString(".symtab"),476 .sh_name = try self.makeString(".symtab"),
...@@ -586,7 +586,7 @@ pub const ElfFile = struct {...@@ -586,7 +586,7 @@ pub const ElfFile = struct {
586 shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1);586 shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1);
587 }587 }
588 shstrtab_sect.sh_size = needed_size;588 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
591 try self.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);591 try self.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
592 if (!self.shdr_table_dirty) {592 if (!self.shdr_table_dirty) {
...@@ -632,7 +632,7 @@ pub const ElfFile = struct {...@@ -632,7 +632,7 @@ pub const ElfFile = struct {
632632
633 for (buf) |*shdr, i| {633 for (buf) |*shdr, i| {
634 shdr.* = self.sections.items[i];634 shdr.* = self.sections.items[i];
635 //std.debug.warn("writing section {}\n", .{shdr.*});635 //std.log.debug(.link, "writing section {}\n", .{shdr.*});
636 if (foreign_endian) {636 if (foreign_endian) {
637 bswapAllFields(elf.Elf64_Shdr, shdr);637 bswapAllFields(elf.Elf64_Shdr, shdr);
638 }638 }
...@@ -956,10 +956,10 @@ pub const ElfFile = struct {...@@ -956,10 +956,10 @@ pub const ElfFile = struct {
956 try self.offset_table_free_list.ensureCapacity(self.allocator, self.local_symbols.items.len);956 try self.offset_table_free_list.ensureCapacity(self.allocator, self.local_symbols.items.len);
957957
958 if (self.local_symbol_free_list.popOrNull()) |i| {958 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});
960 decl.link.local_sym_index = i;960 decl.link.local_sym_index = i;
961 } else {961 } 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});
963 decl.link.local_sym_index = @intCast(u32, self.local_symbols.items.len);963 decl.link.local_sym_index = @intCast(u32, self.local_symbols.items.len);
964 _ = self.local_symbols.addOneAssumeCapacity();964 _ = self.local_symbols.addOneAssumeCapacity();
965 }965 }
...@@ -1002,7 +1002,7 @@ pub const ElfFile = struct {...@@ -1002,7 +1002,7 @@ pub const ElfFile = struct {
1002 defer code_buffer.deinit();1002 defer code_buffer.deinit();
10031003
1004 const typed_value = decl.typed_value.most_recent.typed_value;1004 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)) {
1006 .externally_managed => |x| x,1006 .externally_managed => |x| x,
1007 .appended => code_buffer.items,1007 .appended => code_buffer.items,
1008 .fail => |em| {1008 .fail => |em| {
...@@ -1027,11 +1027,11 @@ pub const ElfFile = struct {...@@ -1027,11 +1027,11 @@ pub const ElfFile = struct {
1027 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);1027 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
1028 if (need_realloc) {1028 if (need_realloc) {
1029 const vaddr = try self.growTextBlock(&decl.link, code.len, required_alignment);1029 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 });
1031 if (vaddr != local_sym.st_value) {1031 if (vaddr != local_sym.st_value) {
1032 local_sym.st_value = vaddr;1032 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", .{});
1035 self.offset_table.items[decl.link.offset_table_index] = vaddr;1035 self.offset_table.items[decl.link.offset_table_index] = vaddr;
1036 try self.writeOffsetTableEntry(decl.link.offset_table_index);1036 try self.writeOffsetTableEntry(decl.link.offset_table_index);
1037 }1037 }
...@@ -1049,7 +1049,7 @@ pub const ElfFile = struct {...@@ -1049,7 +1049,7 @@ pub const ElfFile = struct {
1049 const decl_name = mem.spanZ(decl.name);1049 const decl_name = mem.spanZ(decl.name);
1050 const name_str_index = try self.makeString(decl_name);1050 const name_str_index = try self.makeString(decl_name);
1051 const vaddr = try self.allocateTextBlock(&decl.link, code.len, required_alignment);1051 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 });
1053 errdefer self.freeTextBlock(&decl.link);1053 errdefer self.freeTextBlock(&decl.link);
10541054
1055 local_sym.* = .{1055 local_sym.* = .{
...@@ -1307,7 +1307,6 @@ pub const ElfFile = struct {...@@ -1307,7 +1307,6 @@ pub const ElfFile = struct {
1307 .p32 => @sizeOf(elf.Elf32_Sym),1307 .p32 => @sizeOf(elf.Elf32_Sym),
1308 .p64 => @sizeOf(elf.Elf64_Sym),1308 .p64 => @sizeOf(elf.Elf64_Sym),
1309 };1309 };
1310 //std.debug.warn("symtab start=0x{x} end=0x{x}\n", .{ syms_sect.sh_offset, syms_sect.sh_offset + needed_size });
1311 const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();1310 const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
1312 const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size;1311 const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size;
1313 switch (self.ptr_width) {1312 switch (self.ptr_width) {
src-self-hosted/main.zig+30-16
...@@ -38,6 +38,29 @@ const usage =...@@ -38,6 +38,29 @@ const usage =
38 \\38 \\
39;39;
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
41pub fn main() !void {64pub fn main() !void {
42 // TODO general purpose allocator in the zig std lib65 // TODO general purpose allocator in the zig std lib
43 const gpa = if (std.builtin.link_libc) std.heap.c_allocator else std.heap.page_allocator;66 const gpa = if (std.builtin.link_libc) std.heap.c_allocator else std.heap.page_allocator;
...@@ -86,7 +109,7 @@ const usage_build_generic =...@@ -86,7 +109,7 @@ const usage_build_generic =
86 \\ zig build-obj <options> [files]109 \\ zig build-obj <options> [files]
87 \\110 \\
88 \\Supported file types:111 \\Supported file types:
89 \\ (planned) .zig Zig source code112 \\ .zig Zig source code
90 \\ .zir Zig Intermediate Representation code113 \\ .zir Zig Intermediate Representation code
91 \\ (planned) .o ELF object file114 \\ (planned) .o ELF object file
92 \\ (planned) .o MACH-O (macOS) object file115 \\ (planned) .o MACH-O (macOS) object file
...@@ -407,21 +430,7 @@ fn buildOutputType(...@@ -407,21 +430,7 @@ fn buildOutputType(
407 std.debug.warn("-fno-emit-bin not supported yet", .{});430 std.debug.warn("-fno-emit-bin not supported yet", .{});
408 process.exit(1);431 process.exit(1);
409 },432 },
410 .yes_default_path => switch (output_mode) {433 .yes_default_path => try std.zig.binNameAlloc(arena, root_name, target_info.target, output_mode, link_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 },
425 .yes => |p| p,434 .yes => |p| p,
426 };435 };
427436
...@@ -450,6 +459,7 @@ fn buildOutputType(...@@ -450,6 +459,7 @@ fn buildOutputType(
450 .link_mode = link_mode,459 .link_mode = link_mode,
451 .object_format = object_format,460 .object_format = object_format,
452 .optimize_mode = build_mode,461 .optimize_mode = build_mode,
462 .keep_source_files_loaded = zir_out_path != null,
453 });463 });
454 defer module.deinit();464 defer module.deinit();
455465
...@@ -487,7 +497,9 @@ fn buildOutputType(...@@ -487,7 +497,9 @@ fn buildOutputType(
487}497}
488498
489fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !void {499fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !void {
500 var timer = try std.time.Timer.start();
490 try module.update();501 try module.update();
502 const update_nanos = timer.read();
491503
492 var errors = try module.getAllErrorsAlloc();504 var errors = try module.getAllErrorsAlloc();
493 defer errors.deinit(module.allocator);505 defer errors.deinit(module.allocator);
...@@ -501,6 +513,8 @@ fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !vo...@@ -501,6 +513,8 @@ fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !vo
501 full_err_msg.msg,513 full_err_msg.msg,
502 });514 });
503 }515 }
516 } else {
517 std.log.info(.compiler, "Update completed in {} ms\n", .{update_nanos / std.time.ns_per_ms});
504 }518 }
505519
506 if (zir_out_path) |zop| {520 if (zir_out_path) |zop| {
src-self-hosted/test.zig+146-156
...@@ -21,32 +21,7 @@ const ErrorMsg = struct {...@@ -21,32 +21,7 @@ const ErrorMsg = struct {
21};21};
2222
23pub const TestContext = struct {23pub const TestContext = struct {
24 // TODO: remove these. They are deprecated.24 zir_cases: std.ArrayList(Case),
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 };
5025
51 pub const ZIRUpdate = struct {26 pub const ZIRUpdate = struct {
52 /// The input to the current update. We simulate an incremental update27 /// The input to the current update. We simulate an incremental update
...@@ -57,58 +32,55 @@ pub const TestContext = struct {...@@ -57,58 +32,55 @@ pub const TestContext = struct {
57 /// you can keep it mostly consistent, with small changes, testing the32 /// you can keep it mostly consistent, with small changes, testing the
58 /// effects of the incremental compilation.33 /// effects of the incremental compilation.
59 src: [:0]const u8,34 src: [:0]const u8,
60 case: union(ZIRUpdateType) {35 case: union(enum) {
61 /// The expected output ZIR36 /// A transformation update transforms the input ZIR and tests against
37 /// the expected output ZIR.
62 Transformation: [:0]const u8,38 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.
63 /// A slice containing the expected errors *in sequential order*.41 /// A slice containing the expected errors *in sequential order*.
64 Error: []const ErrorMsg,42 Error: []const ErrorMsg,
6543 /// An execution update compiles and runs the input ZIR, feeding in
66 /// Input to feed to the program, and expected outputs.44 /// provided input and ensuring that the stdout match what is expected.
67 ///45 Execution: []const u8,
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,
84 },46 },
85 };47 };
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,
88 /// compile it, ensure that compilation fails, and more. The same Module is50 /// compile it, ensure that compilation fails, and more. The same Module is
89 /// used for each update, so each update's source is treated as a single file51 /// used for each update, so each update's source is treated as a single file
90 /// being updated by the test harness and incrementally compiled.52 /// being updated by the test harness and incrementally compiled.
91 pub const ZIRCase = struct {53 pub const Case = struct {
92 name: []const u8,54 name: []const u8,
93 /// The platform the ZIR targets. For non-native platforms, an emulator55 /// The platform the ZIR targets. For non-native platforms, an emulator
94 /// such as QEMU is required for tests to complete.56 /// such as QEMU is required for tests to complete.
95 target: std.zig.CrossTarget,57 target: std.zig.CrossTarget,
96 updates: std.ArrayList(ZIRUpdate),58 updates: std.ArrayList(ZIRUpdate),
59 output_mode: std.builtin.OutputMode,
60 /// Either ".zir" or ".zig"
61 extension: [4]u8,
9762
98 /// Adds a subcase in which the module is updated with new ZIR, and the63 /// Adds a subcase in which the module is updated with new ZIR, and the
99 /// resulting ZIR is validated.64 /// 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 {
101 self.updates.append(.{66 self.updates.append(.{
102 .src = src,67 .src = src,
103 .case = .{ .Transformation = result },68 .case = .{ .Transformation = result },
104 }) catch unreachable;69 }) catch unreachable;
105 }70 }
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
107 /// Adds a subcase in which the module is updated with invalid ZIR, and79 /// Adds a subcase in which the module is updated with invalid ZIR, and
108 /// ensures that compilation fails for the expected reasons.80 /// ensures that compilation fails for the expected reasons.
109 ///81 ///
110 /// Errors must be specified in sequential order.82 /// 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 {
112 var array = self.updates.allocator.alloc(ErrorMsg, errors.len) catch unreachable;84 var array = self.updates.allocator.alloc(ErrorMsg, errors.len) catch unreachable;
113 for (errors) |e, i| {85 for (errors) |e, i| {
114 if (e[0] != ':') {86 if (e[0] != ':') {
...@@ -146,15 +118,65 @@ pub const TestContext = struct {...@@ -146,15 +118,65 @@ pub const TestContext = struct {
146 }118 }
147 };119 };
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(
150 ctx: *TestContext,138 ctx: *TestContext,
151 name: []const u8,139 name: []const u8,
152 target: std.zig.CrossTarget,140 target: std.zig.CrossTarget,
153 ) *ZIRCase {141 ) *Case {
154 const case = ZIRCase{142 const case = Case{
155 .name = name,143 .name = name,
156 .target = target,144 .target = target,
157 .updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),145 .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".*,
158 };180 };
159 ctx.zir_cases.append(case) catch unreachable;181 ctx.zir_cases.append(case) catch unreachable;
160 return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];182 return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
...@@ -163,14 +185,21 @@ pub const TestContext = struct {...@@ -163,14 +185,21 @@ pub const TestContext = struct {
163 pub fn addZIRCompareOutput(185 pub fn addZIRCompareOutput(
164 ctx: *TestContext,186 ctx: *TestContext,
165 name: []const u8,187 name: []const u8,
166 src_list: []const []const u8,188 src: [:0]const u8,
167 expected_stdout_list: []const []const u8,189 expected_stdout: []const u8,
168 ) void {190 ) void {
169 ctx.zir_cmp_output_cases.append(.{191 var c = ctx.addExeZIR(name, .{});
170 .name = name,192 c.addCompareOutput(src, expected_stdout);
171 .src_list = src_list,193 }
172 .expected_stdout_list = expected_stdout_list,194
173 }) catch unreachable;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);
174 }203 }
175204
176 pub fn addZIRTransform(205 pub fn addZIRTransform(
...@@ -180,7 +209,7 @@ pub const TestContext = struct {...@@ -180,7 +209,7 @@ pub const TestContext = struct {
180 src: [:0]const u8,209 src: [:0]const u8,
181 result: [:0]const u8,210 result: [:0]const u8,
182 ) void {211 ) void {
183 var c = ctx.addZIRMulti(name, target);212 var c = ctx.addObjZIR(name, target);
184 c.addTransform(src, result);213 c.addTransform(src, result);
185 }214 }
186215
...@@ -191,20 +220,18 @@ pub const TestContext = struct {...@@ -191,20 +220,18 @@ pub const TestContext = struct {
191 src: [:0]const u8,220 src: [:0]const u8,
192 expected_errors: []const []const u8,221 expected_errors: []const []const u8,
193 ) void {222 ) void {
194 var c = ctx.addZIRMulti(name, target);223 var c = ctx.addObjZIR(name, target);
195 c.addError(src, expected_errors);224 c.addError(src, expected_errors);
196 }225 }
197226
198 fn init() TestContext {227 fn init() TestContext {
199 const allocator = std.heap.page_allocator;228 const allocator = std.heap.page_allocator;
200 return .{229 return .{
201 .zir_cmp_output_cases = std.ArrayList(ZIRCompareOutputCase).init(allocator),230 .zir_cases = std.ArrayList(Case).init(allocator),
202 .zir_cases = std.ArrayList(ZIRCase).init(allocator),
203 };231 };
204 }232 }
205233
206 fn deinit(self: *TestContext) void {234 fn deinit(self: *TestContext) void {
207 self.zir_cmp_output_cases.deinit();
208 for (self.zir_cases.items) |c| {235 for (self.zir_cases.items) |c| {
209 for (c.updates.items) |u| {236 for (c.updates.items) |u| {
210 if (u.case == .Error) {237 if (u.case == .Error) {
...@@ -226,30 +253,32 @@ pub const TestContext = struct {...@@ -226,30 +253,32 @@ pub const TestContext = struct {
226253
227 for (self.zir_cases.items) |case| {254 for (self.zir_cases.items) |case| {
228 std.testing.base_allocator_instance.reset();255 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 function257 var prg_node = root_node.start(case.name, case.updates.items.len);
235 for (self.zir_cmp_output_cases.items) |case| {258 prg_node.activate();
236 std.testing.base_allocator_instance.reset();259 defer prg_node.end();
237 try self.runOneZIRCmpOutputCase(std.testing.allocator, root_node, case, native_info.target);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);
238 try std.testing.allocator_instance.validate();266 try std.testing.allocator_instance.validate();
239 }267 }
240 }268 }
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 {
243 var tmp = std.testing.tmpDir(.{});271 var tmp = std.testing.tmpDir(.{});
244 defer tmp.cleanup();272 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);
247 const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);277 const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);
248 defer root_pkg.destroy();278 defer root_pkg.destroy();
249279
250 var prg_node = root_node.start(case.name, case.updates.items.len);280 const bin_name = try std.zig.binNameAlloc(allocator, root_name, target, case.output_mode, null);
251 prg_node.activate();281 defer allocator.free(bin_name);
252 defer prg_node.end();
253282
254 var module = try Module.init(allocator, .{283 var module = try Module.init(allocator, .{
255 .target = target,284 .target = target,
...@@ -259,16 +288,17 @@ pub const TestContext = struct {...@@ -259,16 +288,17 @@ pub const TestContext = struct {
259 // TODO: support tests for object file building, and library builds288 // TODO: support tests for object file building, and library builds
260 // and linking. This will require a rework to support multi-file289 // and linking. This will require a rework to support multi-file
261 // tests.290 // tests.
262 .output_mode = .Obj,291 .output_mode = case.output_mode,
263 // TODO: support testing optimizations292 // TODO: support testing optimizations
264 .optimize_mode = .Debug,293 .optimize_mode = .Debug,
265 .bin_file_dir = tmp.dir,294 .bin_file_dir = tmp.dir,
266 .bin_file_path = "test_case.o",295 .bin_file_path = bin_name,
267 .root_pkg = root_pkg,296 .root_pkg = root_pkg,
297 .keep_source_files_loaded = true,
268 });298 });
269 defer module.deinit();299 defer module.deinit();
270300
271 for (case.updates.items) |update| {301 for (case.updates.items) |update, update_index| {
272 var update_node = prg_node.start("update", 4);302 var update_node = prg_node.start("update", 4);
273 update_node.activate();303 update_node.activate();
274 defer update_node.end();304 defer update_node.end();
...@@ -280,6 +310,7 @@ pub const TestContext = struct {...@@ -280,6 +310,7 @@ pub const TestContext = struct {
280310
281 var module_node = update_node.start("parse/analysis/codegen", null);311 var module_node = update_node.start("parse/analysis/codegen", null);
282 module_node.activate();312 module_node.activate();
313 try module.makeBinFileWritable();
283 try module.update();314 try module.update();
284 module_node.end();315 module_node.end();
285316
...@@ -328,82 +359,41 @@ pub const TestContext = struct {...@@ -328,82 +359,41 @@ pub const TestContext = struct {
328 }359 }
329 }360 }
330 },361 },
331362 .Execution => |expected_stdout| {
332 else => return error.unimplemented,363 var exec_result = x: {
333 }364 var exec_node = update_node.start("execute", null);
334 }365 exec_node.activate();
335 }366 defer exec_node.end();
336367
337 fn runOneZIRCmpOutputCase(368 try module.makeBinFileExecutable();
338 self: *TestContext,369
339 allocator: *Allocator,370 const exe_path = try std.fmt.allocPrint(allocator, "." ++ std.fs.path.sep_str ++ "{}", .{bin_name});
340 root_node: *std.Progress.Node,371 defer allocator.free(exe_path);
341 case: ZIRCompareOutputCase,372
342 target: std.Target,373 break :x try std.ChildProcess.exec(.{
343 ) !void {374 .allocator = allocator,
344 var tmp = std.testing.tmpDir(.{});375 .argv = &[_][]const u8{exe_path},
345 defer tmp.cleanup();376 .cwd_dir = tmp.dir,
346377 });
347 const tmp_src_path = "test-case.zir";378 };
348 const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);379 defer allocator.free(exec_result.stdout);
349 defer root_pkg.destroy();380 defer allocator.free(exec_result.stderr);
350381 switch (exec_result.term) {
351 var prg_node = root_node.start(case.name, case.src_list.len);382 .Exited => |code| {
352 prg_node.activate();383 if (code != 0) {
353 defer prg_node.end();384 std.debug.warn("elf file exited with code {}\n", .{code});
354385 return error.BinaryBadExitCode;
355 var module = try Module.init(allocator, .{386 }
356 .target = target,387 },
357 .output_mode = .Exe,388 else => return error.BinaryCrashed,
358 .optimize_mode = .Debug,389 }
359 .bin_file_dir = tmp.dir,390 if (!std.mem.eql(u8, expected_stdout, exec_result.stdout)) {
360 .bin_file_path = "a.out",391 std.debug.panic(
361 .root_pkg = root_pkg,392 "update index {}, mismatched stdout\n====Expected (len={}):====\n{}\n====Actual (len={}):====\n{}\n========\n",
362 });393 .{ update_index, expected_stdout.len, expected_stdout, exec_result.stdout.len, exec_result.stdout },
363 defer module.deinit();394 );
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;
397 }395 }
398 },396 },
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 );
407 }397 }
408 }398 }
409 }399 }
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 {...@@ -54,6 +54,7 @@ pub const Type = extern union {
54 .@"undefined" => return .Undefined,54 .@"undefined" => return .Undefined,
5555
56 .fn_noreturn_no_args => return .Fn,56 .fn_noreturn_no_args => return .Fn,
57 .fn_void_no_args => return .Fn,
57 .fn_naked_noreturn_no_args => return .Fn,58 .fn_naked_noreturn_no_args => return .Fn,
58 .fn_ccc_void_no_args => return .Fn,59 .fn_ccc_void_no_args => return .Fn,
5960
...@@ -112,6 +113,12 @@ pub const Type = extern union {...@@ -112,6 +113,12 @@ pub const Type = extern union {
112 .Undefined => return true,113 .Undefined => return true,
113 .Null => return true,114 .Null => return true,
114 .Pointer => {115 .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 }
115 const is_slice_a = isSlice(a);122 const is_slice_a = isSlice(a);
116 const is_slice_b = isSlice(b);123 const is_slice_b = isSlice(b);
117 if (is_slice_a != is_slice_b)124 if (is_slice_a != is_slice_b)
...@@ -163,6 +170,77 @@ pub const Type = extern union {...@@ -163,6 +170,77 @@ pub const Type = extern union {
163 }170 }
164 }171 }
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
166 pub fn format(244 pub fn format(
167 self: Type,245 self: Type,
168 comptime fmt: []const u8,246 comptime fmt: []const u8,
...@@ -206,6 +284,7 @@ pub const Type = extern union {...@@ -206,6 +284,7 @@ pub const Type = extern union {
206284
207 .const_slice_u8 => return out_stream.writeAll("[]const u8"),285 .const_slice_u8 => return out_stream.writeAll("[]const u8"),
208 .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),286 .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),
287 .fn_void_no_args => return out_stream.writeAll("fn() void"),
209 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),288 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
210 .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),289 .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),
211 .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),290 .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
...@@ -269,6 +348,7 @@ pub const Type = extern union {...@@ -269,6 +348,7 @@ pub const Type = extern union {
269 .@"null" => return Value.initTag(.null_type),348 .@"null" => return Value.initTag(.null_type),
270 .@"undefined" => return Value.initTag(.undefined_type),349 .@"undefined" => return Value.initTag(.undefined_type),
271 .fn_noreturn_no_args => return Value.initTag(.fn_noreturn_no_args_type),350 .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),
272 .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type),352 .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type),
273 .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),353 .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),
274 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),354 .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 {...@@ -303,6 +383,7 @@ pub const Type = extern union {
303 .bool,383 .bool,
304 .anyerror,384 .anyerror,
305 .fn_noreturn_no_args,385 .fn_noreturn_no_args,
386 .fn_void_no_args,
306 .fn_naked_noreturn_no_args,387 .fn_naked_noreturn_no_args,
307 .fn_ccc_void_no_args,388 .fn_ccc_void_no_args,
308 .single_const_pointer_to_comptime_int,389 .single_const_pointer_to_comptime_int,
...@@ -333,6 +414,7 @@ pub const Type = extern union {...@@ -333,6 +414,7 @@ pub const Type = extern union {
333 .i8,414 .i8,
334 .bool,415 .bool,
335 .fn_noreturn_no_args, // represents machine code; not a pointer416 .fn_noreturn_no_args, // represents machine code; not a pointer
417 .fn_void_no_args, // represents machine code; not a pointer
336 .fn_naked_noreturn_no_args, // represents machine code; not a pointer418 .fn_naked_noreturn_no_args, // represents machine code; not a pointer
337 .fn_ccc_void_no_args, // represents machine code; not a pointer419 .fn_ccc_void_no_args, // represents machine code; not a pointer
338 .array_u8_sentinel_0,420 .array_u8_sentinel_0,
...@@ -420,6 +502,7 @@ pub const Type = extern union {...@@ -420,6 +502,7 @@ pub const Type = extern union {
420 .array_u8_sentinel_0,502 .array_u8_sentinel_0,
421 .const_slice_u8,503 .const_slice_u8,
422 .fn_noreturn_no_args,504 .fn_noreturn_no_args,
505 .fn_void_no_args,
423 .fn_naked_noreturn_no_args,506 .fn_naked_noreturn_no_args,
424 .fn_ccc_void_no_args,507 .fn_ccc_void_no_args,
425 .int_unsigned,508 .int_unsigned,
...@@ -466,6 +549,7 @@ pub const Type = extern union {...@@ -466,6 +549,7 @@ pub const Type = extern union {
466 .single_const_pointer,549 .single_const_pointer,
467 .single_const_pointer_to_comptime_int,550 .single_const_pointer_to_comptime_int,
468 .fn_noreturn_no_args,551 .fn_noreturn_no_args,
552 .fn_void_no_args,
469 .fn_naked_noreturn_no_args,553 .fn_naked_noreturn_no_args,
470 .fn_ccc_void_no_args,554 .fn_ccc_void_no_args,
471 .int_unsigned,555 .int_unsigned,
...@@ -509,6 +593,7 @@ pub const Type = extern union {...@@ -509,6 +593,7 @@ pub const Type = extern union {
509 .array,593 .array,
510 .array_u8_sentinel_0,594 .array_u8_sentinel_0,
511 .fn_noreturn_no_args,595 .fn_noreturn_no_args,
596 .fn_void_no_args,
512 .fn_naked_noreturn_no_args,597 .fn_naked_noreturn_no_args,
513 .fn_ccc_void_no_args,598 .fn_ccc_void_no_args,
514 .int_unsigned,599 .int_unsigned,
...@@ -553,6 +638,7 @@ pub const Type = extern union {...@@ -553,6 +638,7 @@ pub const Type = extern union {
553 .@"null",638 .@"null",
554 .@"undefined",639 .@"undefined",
555 .fn_noreturn_no_args,640 .fn_noreturn_no_args,
641 .fn_void_no_args,
556 .fn_naked_noreturn_no_args,642 .fn_naked_noreturn_no_args,
557 .fn_ccc_void_no_args,643 .fn_ccc_void_no_args,
558 .int_unsigned,644 .int_unsigned,
...@@ -597,6 +683,7 @@ pub const Type = extern union {...@@ -597,6 +683,7 @@ pub const Type = extern union {
597 .@"null",683 .@"null",
598 .@"undefined",684 .@"undefined",
599 .fn_noreturn_no_args,685 .fn_noreturn_no_args,
686 .fn_void_no_args,
600 .fn_naked_noreturn_no_args,687 .fn_naked_noreturn_no_args,
601 .fn_ccc_void_no_args,688 .fn_ccc_void_no_args,
602 .single_const_pointer,689 .single_const_pointer,
...@@ -642,6 +729,7 @@ pub const Type = extern union {...@@ -642,6 +729,7 @@ pub const Type = extern union {
642 .@"null",729 .@"null",
643 .@"undefined",730 .@"undefined",
644 .fn_noreturn_no_args,731 .fn_noreturn_no_args,
732 .fn_void_no_args,
645 .fn_naked_noreturn_no_args,733 .fn_naked_noreturn_no_args,
646 .fn_ccc_void_no_args,734 .fn_ccc_void_no_args,
647 .single_const_pointer,735 .single_const_pointer,
...@@ -675,6 +763,7 @@ pub const Type = extern union {...@@ -675,6 +763,7 @@ pub const Type = extern union {
675 .@"null",763 .@"null",
676 .@"undefined",764 .@"undefined",
677 .fn_noreturn_no_args,765 .fn_noreturn_no_args,
766 .fn_void_no_args,
678 .fn_naked_noreturn_no_args,767 .fn_naked_noreturn_no_args,
679 .fn_ccc_void_no_args,768 .fn_ccc_void_no_args,
680 .array,769 .array,
...@@ -721,6 +810,7 @@ pub const Type = extern union {...@@ -721,6 +810,7 @@ pub const Type = extern union {
721 .@"null",810 .@"null",
722 .@"undefined",811 .@"undefined",
723 .fn_noreturn_no_args,812 .fn_noreturn_no_args,
813 .fn_void_no_args,
724 .fn_naked_noreturn_no_args,814 .fn_naked_noreturn_no_args,
725 .fn_ccc_void_no_args,815 .fn_ccc_void_no_args,
726 .array,816 .array,
...@@ -777,6 +867,7 @@ pub const Type = extern union {...@@ -777,6 +867,7 @@ pub const Type = extern union {
777 pub fn fnParamLen(self: Type) usize {867 pub fn fnParamLen(self: Type) usize {
778 return switch (self.tag()) {868 return switch (self.tag()) {
779 .fn_noreturn_no_args => 0,869 .fn_noreturn_no_args => 0,
870 .fn_void_no_args => 0,
780 .fn_naked_noreturn_no_args => 0,871 .fn_naked_noreturn_no_args => 0,
781 .fn_ccc_void_no_args => 0,872 .fn_ccc_void_no_args => 0,
782873
...@@ -823,6 +914,7 @@ pub const Type = extern union {...@@ -823,6 +914,7 @@ pub const Type = extern union {
823 pub fn fnParamTypes(self: Type, types: []Type) void {914 pub fn fnParamTypes(self: Type, types: []Type) void {
824 switch (self.tag()) {915 switch (self.tag()) {
825 .fn_noreturn_no_args => return,916 .fn_noreturn_no_args => return,
917 .fn_void_no_args => return,
826 .fn_naked_noreturn_no_args => return,918 .fn_naked_noreturn_no_args => return,
827 .fn_ccc_void_no_args => return,919 .fn_ccc_void_no_args => return,
828920
...@@ -869,7 +961,10 @@ pub const Type = extern union {...@@ -869,7 +961,10 @@ pub const Type = extern union {
869 return switch (self.tag()) {961 return switch (self.tag()) {
870 .fn_noreturn_no_args => Type.initTag(.noreturn),962 .fn_noreturn_no_args => Type.initTag(.noreturn),
871 .fn_naked_noreturn_no_args => Type.initTag(.noreturn),963 .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
874 .f16,969 .f16,
875 .f32,970 .f32,
...@@ -913,6 +1008,7 @@ pub const Type = extern union {...@@ -913,6 +1008,7 @@ pub const Type = extern union {
913 pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {1008 pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {
914 return switch (self.tag()) {1009 return switch (self.tag()) {
915 .fn_noreturn_no_args => .Unspecified,1010 .fn_noreturn_no_args => .Unspecified,
1011 .fn_void_no_args => .Unspecified,
916 .fn_naked_noreturn_no_args => .Naked,1012 .fn_naked_noreturn_no_args => .Naked,
917 .fn_ccc_void_no_args => .C,1013 .fn_ccc_void_no_args => .C,
9181014
...@@ -958,6 +1054,7 @@ pub const Type = extern union {...@@ -958,6 +1054,7 @@ pub const Type = extern union {
958 pub fn fnIsVarArgs(self: Type) bool {1054 pub fn fnIsVarArgs(self: Type) bool {
959 return switch (self.tag()) {1055 return switch (self.tag()) {
960 .fn_noreturn_no_args => false,1056 .fn_noreturn_no_args => false,
1057 .fn_void_no_args => false,
961 .fn_naked_noreturn_no_args => false,1058 .fn_naked_noreturn_no_args => false,
962 .fn_ccc_void_no_args => false,1059 .fn_ccc_void_no_args => false,
9631060
...@@ -1033,6 +1130,7 @@ pub const Type = extern union {...@@ -1033,6 +1130,7 @@ pub const Type = extern union {
1033 .@"null",1130 .@"null",
1034 .@"undefined",1131 .@"undefined",
1035 .fn_noreturn_no_args,1132 .fn_noreturn_no_args,
1133 .fn_void_no_args,
1036 .fn_naked_noreturn_no_args,1134 .fn_naked_noreturn_no_args,
1037 .fn_ccc_void_no_args,1135 .fn_ccc_void_no_args,
1038 .array,1136 .array,
...@@ -1070,6 +1168,7 @@ pub const Type = extern union {...@@ -1070,6 +1168,7 @@ pub const Type = extern union {
1070 .type,1168 .type,
1071 .anyerror,1169 .anyerror,
1072 .fn_noreturn_no_args,1170 .fn_noreturn_no_args,
1171 .fn_void_no_args,
1073 .fn_naked_noreturn_no_args,1172 .fn_naked_noreturn_no_args,
1074 .fn_ccc_void_no_args,1173 .fn_ccc_void_no_args,
1075 .single_const_pointer_to_comptime_int,1174 .single_const_pointer_to_comptime_int,
...@@ -1126,6 +1225,7 @@ pub const Type = extern union {...@@ -1126,6 +1225,7 @@ pub const Type = extern union {
1126 .type,1225 .type,
1127 .anyerror,1226 .anyerror,
1128 .fn_noreturn_no_args,1227 .fn_noreturn_no_args,
1228 .fn_void_no_args,
1129 .fn_naked_noreturn_no_args,1229 .fn_naked_noreturn_no_args,
1130 .fn_ccc_void_no_args,1230 .fn_ccc_void_no_args,
1131 .single_const_pointer_to_comptime_int,1231 .single_const_pointer_to_comptime_int,
...@@ -1180,6 +1280,7 @@ pub const Type = extern union {...@@ -1180,6 +1280,7 @@ pub const Type = extern union {
1180 @"null",1280 @"null",
1181 @"undefined",1281 @"undefined",
1182 fn_noreturn_no_args,1282 fn_noreturn_no_args,
1283 fn_void_no_args,
1183 fn_naked_noreturn_no_args,1284 fn_naked_noreturn_no_args,
1184 fn_ccc_void_no_args,1285 fn_ccc_void_no_args,
1185 single_const_pointer_to_comptime_int,1286 single_const_pointer_to_comptime_int,
src-self-hosted/value.zig+117-7
...@@ -49,6 +49,7 @@ pub const Value = extern union {...@@ -49,6 +49,7 @@ pub const Value = extern union {
49 null_type,49 null_type,
50 undefined_type,50 undefined_type,
51 fn_noreturn_no_args_type,51 fn_noreturn_no_args_type,
52 fn_void_no_args_type,
52 fn_naked_noreturn_no_args_type,53 fn_naked_noreturn_no_args_type,
53 fn_ccc_void_no_args_type,54 fn_ccc_void_no_args_type,
54 single_const_pointer_to_comptime_int_type,55 single_const_pointer_to_comptime_int_type,
...@@ -78,8 +79,8 @@ pub const Value = extern union {...@@ -78,8 +79,8 @@ pub const Value = extern union {
78 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;79 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
79 };80 };
8081
81 pub fn initTag(comptime small_tag: Tag) Value {82 pub fn initTag(small_tag: Tag) Value {
82 comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);83 assert(@enumToInt(small_tag) < Tag.no_payload_count);
83 return .{ .tag_if_small_enough = @enumToInt(small_tag) };84 return .{ .tag_if_small_enough = @enumToInt(small_tag) };
84 }85 }
8586
...@@ -107,6 +108,109 @@ pub const Value = extern union {...@@ -107,6 +108,109 @@ pub const Value = extern union {
107 return @fieldParentPtr(T, "base", self.ptr_otherwise);108 return @fieldParentPtr(T, "base", self.ptr_otherwise);
108 }109 }
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
110 pub fn format(214 pub fn format(
111 self: Value,215 self: Value,
112 comptime fmt: []const u8,216 comptime fmt: []const u8,
...@@ -144,6 +248,7 @@ pub const Value = extern union {...@@ -144,6 +248,7 @@ pub const Value = extern union {
144 .null_type => return out_stream.writeAll("@TypeOf(null)"),248 .null_type => return out_stream.writeAll("@TypeOf(null)"),
145 .undefined_type => return out_stream.writeAll("@TypeOf(undefined)"),249 .undefined_type => return out_stream.writeAll("@TypeOf(undefined)"),
146 .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"),250 .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"),
251 .fn_void_no_args_type => return out_stream.writeAll("fn() void"),
147 .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),252 .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
148 .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),253 .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
149 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),254 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
...@@ -229,6 +334,7 @@ pub const Value = extern union {...@@ -229,6 +334,7 @@ pub const Value = extern union {
229 .null_type => Type.initTag(.@"null"),334 .null_type => Type.initTag(.@"null"),
230 .undefined_type => Type.initTag(.@"undefined"),335 .undefined_type => Type.initTag(.@"undefined"),
231 .fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args),336 .fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args),
337 .fn_void_no_args_type => Type.initTag(.fn_void_no_args),
232 .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),338 .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),
233 .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),339 .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),
234 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),340 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
...@@ -286,6 +392,7 @@ pub const Value = extern union {...@@ -286,6 +392,7 @@ pub const Value = extern union {
286 .null_type,392 .null_type,
287 .undefined_type,393 .undefined_type,
288 .fn_noreturn_no_args_type,394 .fn_noreturn_no_args_type,
395 .fn_void_no_args_type,
289 .fn_naked_noreturn_no_args_type,396 .fn_naked_noreturn_no_args_type,
290 .fn_ccc_void_no_args_type,397 .fn_ccc_void_no_args_type,
291 .single_const_pointer_to_comptime_int_type,398 .single_const_pointer_to_comptime_int_type,
...@@ -345,6 +452,7 @@ pub const Value = extern union {...@@ -345,6 +452,7 @@ pub const Value = extern union {
345 .null_type,452 .null_type,
346 .undefined_type,453 .undefined_type,
347 .fn_noreturn_no_args_type,454 .fn_noreturn_no_args_type,
455 .fn_void_no_args_type,
348 .fn_naked_noreturn_no_args_type,456 .fn_naked_noreturn_no_args_type,
349 .fn_ccc_void_no_args_type,457 .fn_ccc_void_no_args_type,
350 .single_const_pointer_to_comptime_int_type,458 .single_const_pointer_to_comptime_int_type,
...@@ -405,6 +513,7 @@ pub const Value = extern union {...@@ -405,6 +513,7 @@ pub const Value = extern union {
405 .null_type,513 .null_type,
406 .undefined_type,514 .undefined_type,
407 .fn_noreturn_no_args_type,515 .fn_noreturn_no_args_type,
516 .fn_void_no_args_type,
408 .fn_naked_noreturn_no_args_type,517 .fn_naked_noreturn_no_args_type,
409 .fn_ccc_void_no_args_type,518 .fn_ccc_void_no_args_type,
410 .single_const_pointer_to_comptime_int_type,519 .single_const_pointer_to_comptime_int_type,
...@@ -470,6 +579,7 @@ pub const Value = extern union {...@@ -470,6 +579,7 @@ pub const Value = extern union {
470 .null_type,579 .null_type,
471 .undefined_type,580 .undefined_type,
472 .fn_noreturn_no_args_type,581 .fn_noreturn_no_args_type,
582 .fn_void_no_args_type,
473 .fn_naked_noreturn_no_args_type,583 .fn_naked_noreturn_no_args_type,
474 .fn_ccc_void_no_args_type,584 .fn_ccc_void_no_args_type,
475 .single_const_pointer_to_comptime_int_type,585 .single_const_pointer_to_comptime_int_type,
...@@ -564,6 +674,7 @@ pub const Value = extern union {...@@ -564,6 +674,7 @@ pub const Value = extern union {
564 .null_type,674 .null_type,
565 .undefined_type,675 .undefined_type,
566 .fn_noreturn_no_args_type,676 .fn_noreturn_no_args_type,
677 .fn_void_no_args_type,
567 .fn_naked_noreturn_no_args_type,678 .fn_naked_noreturn_no_args_type,
568 .fn_ccc_void_no_args_type,679 .fn_ccc_void_no_args_type,
569 .single_const_pointer_to_comptime_int_type,680 .single_const_pointer_to_comptime_int_type,
...@@ -620,6 +731,7 @@ pub const Value = extern union {...@@ -620,6 +731,7 @@ pub const Value = extern union {
620 .null_type,731 .null_type,
621 .undefined_type,732 .undefined_type,
622 .fn_noreturn_no_args_type,733 .fn_noreturn_no_args_type,
734 .fn_void_no_args_type,
623 .fn_naked_noreturn_no_args_type,735 .fn_naked_noreturn_no_args_type,
624 .fn_ccc_void_no_args_type,736 .fn_ccc_void_no_args_type,
625 .single_const_pointer_to_comptime_int_type,737 .single_const_pointer_to_comptime_int_type,
...@@ -721,6 +833,7 @@ pub const Value = extern union {...@@ -721,6 +833,7 @@ pub const Value = extern union {
721 .null_type,833 .null_type,
722 .undefined_type,834 .undefined_type,
723 .fn_noreturn_no_args_type,835 .fn_noreturn_no_args_type,
836 .fn_void_no_args_type,
724 .fn_naked_noreturn_no_args_type,837 .fn_naked_noreturn_no_args_type,
725 .fn_ccc_void_no_args_type,838 .fn_ccc_void_no_args_type,
726 .single_const_pointer_to_comptime_int_type,839 .single_const_pointer_to_comptime_int_type,
...@@ -783,6 +896,7 @@ pub const Value = extern union {...@@ -783,6 +896,7 @@ pub const Value = extern union {
783 .null_type,896 .null_type,
784 .undefined_type,897 .undefined_type,
785 .fn_noreturn_no_args_type,898 .fn_noreturn_no_args_type,
899 .fn_void_no_args_type,
786 .fn_naked_noreturn_no_args_type,900 .fn_naked_noreturn_no_args_type,
787 .fn_ccc_void_no_args_type,901 .fn_ccc_void_no_args_type,
788 .single_const_pointer_to_comptime_int_type,902 .single_const_pointer_to_comptime_int_type,
...@@ -862,6 +976,7 @@ pub const Value = extern union {...@@ -862,6 +976,7 @@ pub const Value = extern union {
862 .null_type,976 .null_type,
863 .undefined_type,977 .undefined_type,
864 .fn_noreturn_no_args_type,978 .fn_noreturn_no_args_type,
979 .fn_void_no_args_type,
865 .fn_naked_noreturn_no_args_type,980 .fn_naked_noreturn_no_args_type,
866 .fn_ccc_void_no_args_type,981 .fn_ccc_void_no_args_type,
867 .single_const_pointer_to_comptime_int_type,982 .single_const_pointer_to_comptime_int_type,
...@@ -929,11 +1044,6 @@ pub const Value = extern union {...@@ -929,11 +1044,6 @@ pub const Value = extern union {
929 len: u64,1044 len: u64,
930 };1045 };
9311046
932 pub const SingleConstPtrType = struct {
933 base: Payload = Payload{ .tag = .single_const_ptr_type },
934 elem_type: *Type,
935 };
936
937 /// Represents a pointer to another immutable value.1047 /// Represents a pointer to another immutable value.
938 pub const RefVal = struct {1048 pub const RefVal = struct {
939 base: Payload = Payload{ .tag = .ref_val },1049 base: Payload = Payload{ .tag = .ref_val },
src-self-hosted/zir.zig+287-181
...@@ -12,27 +12,43 @@ const TypedValue = @import("TypedValue.zig");...@@ -12,27 +12,43 @@ const TypedValue = @import("TypedValue.zig");
12const ir = @import("ir.zig");12const ir = @import("ir.zig");
13const IrModule = @import("Module.zig");13const 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
15/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for26/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for
16/// in-memory, analyzed instructions with types and values.27/// in-memory, analyzed instructions with types and values.
17pub const Inst = struct {28pub const Inst = struct {
18 tag: Tag,29 tag: Tag,
19 /// Byte offset into the source.30 /// Byte offset into the source.
20 src: usize,31 src: usize,
21 name: []const u8,32 /// Pre-allocated field for mapping ZIR text instructions to post-analysis instructions.
2233 analyzed_inst: ?*ir.Inst = null,
23 /// Slice into the source of the part after the = and before the next instruction.
24 contents: []const u8 = &[0]u8{},
2534
26 /// These names are used directly as the instruction names in the text format.35 /// These names are used directly as the instruction names in the text format.
27 pub const Tag = enum {36 pub const Tag = enum {
28 breakpoint,37 breakpoint,
29 call,38 call,
30 compileerror,39 compileerror,
40 /// Special case, has no textual representation.
41 @"const",
31 /// Represents a pointer to a global decl by name.42 /// Represents a pointer to a global decl by name.
32 declref,43 declref,
44 /// Represents a pointer to a global decl by string name.
45 declref_str,
33 /// The syntax `@foo` is equivalent to `declval("foo")`.46 /// The syntax `@foo` is equivalent to `declval("foo")`.
34 /// declval is equivalent to declref followed by deref.47 /// declval is equivalent to declref followed by deref.
35 declval,48 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.
36 str,52 str,
37 int,53 int,
38 ptrtoint,54 ptrtoint,
...@@ -42,11 +58,11 @@ pub const Inst = struct {...@@ -42,11 +58,11 @@ pub const Inst = struct {
42 @"asm",58 @"asm",
43 @"unreachable",59 @"unreachable",
44 @"return",60 @"return",
61 returnvoid,
45 @"fn",62 @"fn",
63 fntype,
46 @"export",64 @"export",
47 primitive,65 primitive,
48 ref,
49 fntype,
50 intcast,66 intcast,
51 bitcast,67 bitcast,
52 elemptr,68 elemptr,
...@@ -62,8 +78,11 @@ pub const Inst = struct {...@@ -62,8 +78,11 @@ pub const Inst = struct {
62 .breakpoint => Breakpoint,78 .breakpoint => Breakpoint,
63 .call => Call,79 .call => Call,
64 .declref => DeclRef,80 .declref => DeclRef,
81 .declref_str => DeclRefStr,
65 .declval => DeclVal,82 .declval => DeclVal,
83 .declval_in_module => DeclValInModule,
66 .compileerror => CompileError,84 .compileerror => CompileError,
85 .@"const" => Const,
67 .str => Str,86 .str => Str,
68 .int => Int,87 .int => Int,
69 .ptrtoint => PtrToInt,88 .ptrtoint => PtrToInt,
...@@ -73,10 +92,10 @@ pub const Inst = struct {...@@ -73,10 +92,10 @@ pub const Inst = struct {
73 .@"asm" => Asm,92 .@"asm" => Asm,
74 .@"unreachable" => Unreachable,93 .@"unreachable" => Unreachable,
75 .@"return" => Return,94 .@"return" => Return,
95 .returnvoid => ReturnVoid,
76 .@"fn" => Fn,96 .@"fn" => Fn,
77 .@"export" => Export,97 .@"export" => Export,
78 .primitive => Primitive,98 .primitive => Primitive,
79 .ref => Ref,
80 .fntype => FnType,99 .fntype => FnType,
81 .intcast => IntCast,100 .intcast => IntCast,
82 .bitcast => BitCast,101 .bitcast => BitCast,
...@@ -121,6 +140,16 @@ pub const Inst = struct {...@@ -121,6 +140,16 @@ pub const Inst = struct {
121 pub const base_tag = Tag.declref;140 pub const base_tag = Tag.declref;
122 base: Inst,141 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
124 positionals: struct {153 positionals: struct {
125 name: *Inst,154 name: *Inst,
126 },155 },
...@@ -137,6 +166,16 @@ pub const Inst = struct {...@@ -137,6 +166,16 @@ pub const Inst = struct {
137 kw_args: struct {},166 kw_args: struct {},
138 };167 };
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
140 pub const CompileError = struct {179 pub const CompileError = struct {
141 pub const base_tag = Tag.compileerror;180 pub const base_tag = Tag.compileerror;
142 base: Inst,181 base: Inst,
...@@ -147,6 +186,16 @@ pub const Inst = struct {...@@ -147,6 +186,16 @@ pub const Inst = struct {
147 kw_args: struct {},186 kw_args: struct {},
148 };187 };
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
150 pub const Str = struct {199 pub const Str = struct {
151 pub const base_tag = Tag.str;200 pub const base_tag = Tag.str;
152 base: Inst,201 base: Inst,
...@@ -168,6 +217,7 @@ pub const Inst = struct {...@@ -168,6 +217,7 @@ pub const Inst = struct {
168 };217 };
169218
170 pub const PtrToInt = struct {219 pub const PtrToInt = struct {
220 pub const builtin_name = "@ptrToInt";
171 pub const base_tag = Tag.ptrtoint;221 pub const base_tag = Tag.ptrtoint;
172 base: Inst,222 base: Inst,
173223
...@@ -238,6 +288,16 @@ pub const Inst = struct {...@@ -238,6 +288,16 @@ pub const Inst = struct {
238 pub const base_tag = Tag.@"return";288 pub const base_tag = Tag.@"return";
239 base: Inst,289 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
241 positionals: struct {},301 positionals: struct {},
242 kw_args: struct {},302 kw_args: struct {},
243 };303 };
...@@ -253,23 +313,26 @@ pub const Inst = struct {...@@ -253,23 +313,26 @@ pub const Inst = struct {
253 kw_args: struct {},313 kw_args: struct {},
254 };314 };
255315
256 pub const Export = struct {316 pub const FnType = struct {
257 pub const base_tag = Tag.@"export";317 pub const base_tag = Tag.fntype;
258 base: Inst,318 base: Inst,
259319
260 positionals: struct {320 positionals: struct {
261 symbol_name: *Inst,321 param_types: []*Inst,
262 value: *Inst,322 return_type: *Inst,
323 },
324 kw_args: struct {
325 cc: std.builtin.CallingConvention = .Unspecified,
263 },326 },
264 kw_args: struct {},
265 };327 };
266328
267 pub const Ref = struct {329 pub const Export = struct {
268 pub const base_tag = Tag.ref;330 pub const base_tag = Tag.@"export";
269 base: Inst,331 base: Inst,
270332
271 positionals: struct {333 positionals: struct {
272 operand: *Inst,334 symbol_name: *Inst,
335 decl_name: []const u8,
273 },336 },
274 kw_args: struct {},337 kw_args: struct {},
275 };338 };
...@@ -348,19 +411,6 @@ pub const Inst = struct {...@@ -348,19 +411,6 @@ pub const Inst = struct {
348 };411 };
349 };412 };
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
364 pub const IntCast = struct {414 pub const IntCast = struct {
365 pub const base_tag = Tag.intcast;415 pub const base_tag = Tag.intcast;
366 base: Inst,416 base: Inst,
...@@ -456,7 +506,7 @@ pub const ErrorMsg = struct {...@@ -456,7 +506,7 @@ pub const ErrorMsg = struct {
456};506};
457507
458pub const Module = struct {508pub const Module = struct {
459 decls: []*Inst,509 decls: []*Decl,
460 arena: std.heap.ArenaAllocator,510 arena: std.heap.ArenaAllocator,
461 error_msg: ?ErrorMsg = null,511 error_msg: ?ErrorMsg = null,
462512
...@@ -475,13 +525,33 @@ pub const Module = struct {...@@ -475,13 +525,33 @@ pub const Module = struct {
475 self.writeToStream(std.heap.page_allocator, std.io.getStdErr().outStream()) catch {};525 self.writeToStream(std.heap.page_allocator, std.io.getStdErr().outStream()) catch {};
476 }526 }
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
480 /// TODO Look into making a table to speed this up.535 /// TODO Look into making a table to speed this up.
481 pub fn findDecl(self: Module, name: []const u8) ?*Inst {536 pub fn findDecl(self: Module, name: []const u8) ?DeclAndIndex {
482 for (self.decls) |decl| {537 for (self.decls) |decl, i| {
483 if (mem.eql(u8, decl.name, name)) {538 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 };
485 }555 }
486 }556 }
487 return null;557 return null;
...@@ -497,18 +567,18 @@ pub const Module = struct {...@@ -497,18 +567,18 @@ pub const Module = struct {
497 try inst_table.ensureCapacity(self.decls.len);567 try inst_table.ensureCapacity(self.decls.len);
498568
499 for (self.decls) |decl, decl_i| {569 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| {
503 for (fn_inst.positionals.body.instructions) |inst, inst_i| {573 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 });
505 }575 }
506 }576 }
507 }577 }
508578
509 for (self.decls) |decl, i| {579 for (self.decls) |decl, i| {
510 try stream.print("@{} ", .{decl.name});580 try stream.print("@{} ", .{decl.name});
511 try self.writeInstToStream(stream, decl, &inst_table);581 try self.writeInstToStream(stream, decl.inst, &inst_table);
512 try stream.writeByte('\n');582 try stream.writeByte('\n');
513 }583 }
514 }584 }
...@@ -516,38 +586,41 @@ pub const Module = struct {...@@ -516,38 +586,41 @@ pub const Module = struct {
516 fn writeInstToStream(586 fn writeInstToStream(
517 self: Module,587 self: Module,
518 stream: var,588 stream: var,
519 decl: *Inst,589 inst: *Inst,
520 inst_table: *const InstPtrTable,590 inst_table: *const InstPtrTable,
521 ) @TypeOf(stream).Error!void {591 ) @TypeOf(stream).Error!void {
522 // TODO I tried implementing this with an inline for loop and hit a compiler bug592 // TODO I tried implementing this with an inline for loop and hit a compiler bug
523 switch (decl.tag) {593 switch (inst.tag) {
524 .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, decl, inst_table),594 .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, inst, inst_table),
525 .call => return self.writeInstToStreamGeneric(stream, .call, decl, inst_table),595 .call => return self.writeInstToStreamGeneric(stream, .call, inst, inst_table),
526 .declref => return self.writeInstToStreamGeneric(stream, .declref, decl, inst_table),596 .declref => return self.writeInstToStreamGeneric(stream, .declref, inst, inst_table),
527 .declval => return self.writeInstToStreamGeneric(stream, .declval, decl, inst_table),597 .declref_str => return self.writeInstToStreamGeneric(stream, .declref_str, inst, inst_table),
528 .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, decl, inst_table),598 .declval => return self.writeInstToStreamGeneric(stream, .declval, inst, inst_table),
529 .str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table),599 .declval_in_module => return self.writeInstToStreamGeneric(stream, .declval_in_module, inst, inst_table),
530 .int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table),600 .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, inst, inst_table),
531 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table),601 .@"const" => return self.writeInstToStreamGeneric(stream, .@"const", inst, inst_table),
532 .fieldptr => return self.writeInstToStreamGeneric(stream, .fieldptr, decl, inst_table),602 .str => return self.writeInstToStreamGeneric(stream, .str, inst, inst_table),
533 .deref => return self.writeInstToStreamGeneric(stream, .deref, decl, inst_table),603 .int => return self.writeInstToStreamGeneric(stream, .int, inst, inst_table),
534 .as => return self.writeInstToStreamGeneric(stream, .as, decl, inst_table),604 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, inst, inst_table),
535 .@"asm" => return self.writeInstToStreamGeneric(stream, .@"asm", decl, inst_table),605 .fieldptr => return self.writeInstToStreamGeneric(stream, .fieldptr, inst, inst_table),
536 .@"unreachable" => return self.writeInstToStreamGeneric(stream, .@"unreachable", decl, inst_table),606 .deref => return self.writeInstToStreamGeneric(stream, .deref, inst, inst_table),
537 .@"return" => return self.writeInstToStreamGeneric(stream, .@"return", decl, inst_table),607 .as => return self.writeInstToStreamGeneric(stream, .as, inst, inst_table),
538 .@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", decl, inst_table),608 .@"asm" => return self.writeInstToStreamGeneric(stream, .@"asm", inst, inst_table),
539 .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", decl, inst_table),609 .@"unreachable" => return self.writeInstToStreamGeneric(stream, .@"unreachable", inst, inst_table),
540 .ref => return self.writeInstToStreamGeneric(stream, .ref, decl, inst_table),610 .@"return" => return self.writeInstToStreamGeneric(stream, .@"return", inst, inst_table),
541 .primitive => return self.writeInstToStreamGeneric(stream, .primitive, decl, inst_table),611 .returnvoid => return self.writeInstToStreamGeneric(stream, .returnvoid, inst, inst_table),
542 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, decl, inst_table),612 .@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", inst, inst_table),
543 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, decl, inst_table),613 .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", inst, inst_table),
544 .bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, decl, inst_table),614 .primitive => return self.writeInstToStreamGeneric(stream, .primitive, inst, inst_table),
545 .elemptr => return self.writeInstToStreamGeneric(stream, .elemptr, decl, inst_table),615 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, inst, inst_table),
546 .add => return self.writeInstToStreamGeneric(stream, .add, decl, inst_table),616 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, inst, inst_table),
547 .cmp => return self.writeInstToStreamGeneric(stream, .cmp, decl, inst_table),617 .bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, inst, inst_table),
548 .condbr => return self.writeInstToStreamGeneric(stream, .condbr, decl, inst_table),618 .elemptr => return self.writeInstToStreamGeneric(stream, .elemptr, inst, inst_table),
549 .isnull => return self.writeInstToStreamGeneric(stream, .isnull, decl, inst_table),619 .add => return self.writeInstToStreamGeneric(stream, .add, inst, inst_table),
550 .isnonnull => return self.writeInstToStreamGeneric(stream, .isnonnull, decl, 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),
551 }624 }
552 }625 }
553626
...@@ -619,6 +692,8 @@ pub const Module = struct {...@@ -619,6 +692,8 @@ pub const Module = struct {
619 bool => return stream.writeByte("01"[@boolToInt(param)]),692 bool => return stream.writeByte("01"[@boolToInt(param)]),
620 []u8, []const u8 => return std.zig.renderStringLiteral(param, stream),693 []u8, []const u8 => return std.zig.renderStringLiteral(param, stream),
621 BigIntConst => return stream.print("{}", .{param}),694 BigIntConst => return stream.print("{}", .{param}),
695 TypedValue => unreachable, // this is a special case
696 *IrModule.Decl => unreachable, // this is a special case
622 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),697 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
623 }698 }
624 }699 }
...@@ -628,13 +703,16 @@ pub const Module = struct {...@@ -628,13 +703,16 @@ pub const Module = struct {
628 if (info.index) |i| {703 if (info.index) |i| {
629 try stream.print("%{}", .{info.index});704 try stream.print("%{}", .{info.index});
630 } else {705 } else {
631 try stream.print("@{}", .{info.inst.name});706 try stream.print("@{}", .{info.name});
632 }707 }
633 } else if (inst.cast(Inst.DeclVal)) |decl_val| {708 } else if (inst.cast(Inst.DeclVal)) |decl_val| {
634 try stream.print("@{}", .{decl_val.positionals.name});709 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});
635 } else {712 } else {
636 //try stream.print("?", .{});713 // This should be unreachable in theory, but since ZIR is used for debugging the compiler
637 unreachable;714 // we output some debug text instead.
715 try stream.print("?{}?", .{@tagName(inst.tag)});
638 }716 }
639 }717 }
640};718};
...@@ -673,7 +751,7 @@ const Parser = struct {...@@ -673,7 +751,7 @@ const Parser = struct {
673 arena: std.heap.ArenaAllocator,751 arena: std.heap.ArenaAllocator,
674 i: usize,752 i: usize,
675 source: [:0]const u8,753 source: [:0]const u8,
676 decls: std.ArrayListUnmanaged(*Inst),754 decls: std.ArrayListUnmanaged(*Decl),
677 global_name_map: *std.StringHashMap(usize),755 global_name_map: *std.StringHashMap(usize),
678 error_msg: ?ErrorMsg = null,756 error_msg: ?ErrorMsg = null,
679 unnamed_index: usize,757 unnamed_index: usize,
...@@ -702,12 +780,12 @@ const Parser = struct {...@@ -702,12 +780,12 @@ const Parser = struct {
702 skipSpace(self);780 skipSpace(self);
703 try requireEatBytes(self, "=");781 try requireEatBytes(self, "=");
704 skipSpace(self);782 skipSpace(self);
705 const inst = try parseInstruction(self, &body_context, ident);783 const decl = try parseInstruction(self, &body_context, ident);
706 const ident_index = body_context.instructions.items.len;784 const ident_index = body_context.instructions.items.len;
707 if (try body_context.name_map.put(ident, ident_index)) |_| {785 if (try body_context.name_map.put(ident, ident_index)) |_| {
708 return self.fail("redefinition of identifier '{}'", .{ident});786 return self.fail("redefinition of identifier '{}'", .{ident});
709 }787 }
710 try body_context.instructions.append(inst);788 try body_context.instructions.append(decl.inst);
711 continue;789 continue;
712 },790 },
713 ' ', '\n' => continue,791 ' ', '\n' => continue,
...@@ -857,7 +935,7 @@ const Parser = struct {...@@ -857,7 +935,7 @@ const Parser = struct {
857 return error.ParseFailure;935 return error.ParseFailure;
858 }936 }
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 {
861 const contents_start = self.i;939 const contents_start = self.i;
862 const fn_name = try skipToAndOver(self, '(');940 const fn_name = try skipToAndOver(self, '(');
863 inline for (@typeInfo(Inst.Tag).Enum.fields) |field| {941 inline for (@typeInfo(Inst.Tag).Enum.fields) |field| {
...@@ -876,10 +954,9 @@ const Parser = struct {...@@ -876,10 +954,9 @@ const Parser = struct {
876 body_ctx: ?*Body,954 body_ctx: ?*Body,
877 inst_name: []const u8,955 inst_name: []const u8,
878 contents_start: usize,956 contents_start: usize,
879 ) InnerError!*Inst {957 ) InnerError!*Decl {
880 const inst_specific = try self.arena.allocator.create(InstType);958 const inst_specific = try self.arena.allocator.create(InstType);
881 inst_specific.base = .{959 inst_specific.base = .{
882 .name = inst_name,
883 .src = self.i,960 .src = self.i,
884 .tag = InstType.base_tag,961 .tag = InstType.base_tag,
885 };962 };
...@@ -929,10 +1006,15 @@ const Parser = struct {...@@ -929,10 +1006,15 @@ const Parser = struct {
929 }1006 }
930 try requireEatBytes(self, ")");1007 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 };
933 //std.debug.warn("parsed {} = '{}'\n", .{ inst_specific.base.name, inst_specific.base.contents });1015 //std.debug.warn("parsed {} = '{}'\n", .{ inst_specific.base.name, inst_specific.base.contents });
9341016
935 return &inst_specific.base;1017 return decl;
936 }1018 }
9371019
938 fn parseParameterGeneric(self: *Parser, comptime T: type, body_ctx: ?*Body) !T {1020 fn parseParameterGeneric(self: *Parser, comptime T: type, body_ctx: ?*Body) !T {
...@@ -978,6 +1060,8 @@ const Parser = struct {...@@ -978,6 +1060,8 @@ const Parser = struct {
978 *Inst => return parseParameterInst(self, body_ctx),1060 *Inst => return parseParameterInst(self, body_ctx),
979 []u8, []const u8 => return self.parseStringLiteral(),1061 []u8, []const u8 => return self.parseStringLiteral(),
980 BigIntConst => return self.parseIntegerLiteral(),1062 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", .{}),
981 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),1065 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
982 }1066 }
983 return self.fail("TODO parse parameter {}", .{@typeName(T)});1067 return self.fail("TODO parse parameter {}", .{@typeName(T)});
...@@ -1014,7 +1098,6 @@ const Parser = struct {...@@ -1014,7 +1098,6 @@ const Parser = struct {
1014 const declval = try self.arena.allocator.create(Inst.DeclVal);1098 const declval = try self.arena.allocator.create(Inst.DeclVal);
1015 declval.* = .{1099 declval.* = .{
1016 .base = .{1100 .base = .{
1017 .name = try self.generateName(),
1018 .src = src,1101 .src = src,
1019 .tag = Inst.DeclVal.base_tag,1102 .tag = Inst.DeclVal.base_tag,
1020 },1103 },
...@@ -1027,7 +1110,7 @@ const Parser = struct {...@@ -1027,7 +1110,7 @@ const Parser = struct {
1027 if (local_ref) {1110 if (local_ref) {
1028 return body_ctx.?.instructions.items[kv.value];1111 return body_ctx.?.instructions.items[kv.value];
1029 } else {1112 } else {
1030 return self.decls.items[kv.value];1113 return self.decls.items[kv.value].inst;
1031 }1114 }
1032 }1115 }
10331116
...@@ -1046,7 +1129,7 @@ pub fn emit(allocator: *Allocator, old_module: IrModule) !Module {...@@ -1046,7 +1129,7 @@ pub fn emit(allocator: *Allocator, old_module: IrModule) !Module {
1046 .old_module = &old_module,1129 .old_module = &old_module,
1047 .next_auto_name = 0,1130 .next_auto_name = 0,
1048 .names = std.StringHashMap(void).init(allocator),1131 .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),
1050 };1133 };
1051 defer ctx.decls.deinit(allocator);1134 defer ctx.decls.deinit(allocator);
1052 defer ctx.names.deinit();1135 defer ctx.names.deinit();
...@@ -1065,10 +1148,10 @@ const EmitZIR = struct {...@@ -1065,10 +1148,10 @@ const EmitZIR = struct {
1065 allocator: *Allocator,1148 allocator: *Allocator,
1066 arena: std.heap.ArenaAllocator,1149 arena: std.heap.ArenaAllocator,
1067 old_module: *const IrModule,1150 old_module: *const IrModule,
1068 decls: std.ArrayListUnmanaged(*Inst),1151 decls: std.ArrayListUnmanaged(*Decl),
1069 names: std.StringHashMap(void),1152 names: std.StringHashMap(void),
1070 next_auto_name: usize,1153 next_auto_name: usize,
1071 primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Inst),1154 primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Decl),
10721155
1073 fn emit(self: *EmitZIR) !void {1156 fn emit(self: *EmitZIR) !void {
1074 // Put all the Decls in a list and sort them by name to avoid nondeterminism introduced1157 // Put all the Decls in a list and sort them by name to avoid nondeterminism introduced
...@@ -1087,52 +1170,90 @@ const EmitZIR = struct {...@@ -1087,52 +1170,90 @@ const EmitZIR = struct {
1087 }1170 }
1088 std.sort.sort(*IrModule.Decl, src_decls.items, {}, (struct {1171 std.sort.sort(*IrModule.Decl, src_decls.items, {}, (struct {
1089 fn lessThan(context: void, a: *IrModule.Decl, b: *IrModule.Decl) bool {1172 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;
1091 }1174 }
1092 }).lessThan);1175 }).lessThan);
10931176
1094 // Emit all the decls.1177 // Emit all the decls.
1095 for (src_decls.items) |ir_decl| {1178 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 }
1096 if (self.old_module.export_owners.getValue(ir_decl)) |exports| {1212 if (self.old_module.export_owners.getValue(ir_decl)) |exports| {
1097 for (exports) |module_export| {1213 for (exports) |module_export| {
1098 const declval = try self.emitDeclVal(ir_decl.src, mem.spanZ(module_export.exported_decl.name));
1099 const symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name);1214 const symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name);
1100 const export_inst = try self.arena.allocator.create(Inst.Export);1215 const export_inst = try self.arena.allocator.create(Inst.Export);
1101 export_inst.* = .{1216 export_inst.* = .{
1102 .base = .{1217 .base = .{
1103 .name = try self.autoName(),
1104 .src = module_export.src,1218 .src = module_export.src,
1105 .tag = Inst.Export.base_tag,1219 .tag = Inst.Export.base_tag,
1106 },1220 },
1107 .positionals = .{1221 .positionals = .{
1108 .symbol_name = symbol_name,1222 .symbol_name = symbol_name.inst,
1109 .value = declval,1223 .decl_name = mem.spanZ(module_export.exported_decl.name),
1110 },1224 },
1111 .kw_args = .{},1225 .kw_args = .{},
1112 };1226 };
1113 try self.decls.append(self.allocator, &export_inst.base);1227 _ = try self.emitUnnamedDecl(&export_inst.base);
1114 }1228 }
1115 } else {1229 } 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);
1117 new_decl.name = try self.arena.allocator.dupe(u8, mem.spanZ(ir_decl.name));1231 new_decl.name = try self.arena.allocator.dupe(u8, mem.spanZ(ir_decl.name));
1118 }1232 }
1119 }1233 }
1120 }1234 }
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 {
1123 if (inst.cast(ir.Inst.Constant)) |const_inst| {1242 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: {
1125 const owner_decl = func_pl.func.owner_decl;1244 const owner_decl = func_pl.func.owner_decl;
1126 break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name));1245 break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name));
1127 } else if (const_inst.val.cast(Value.Payload.DeclRef)) |declref| blk: {1246 } 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;
1129 } else blk: {1250 } 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;
1131 };1252 };
1132 try inst_table.putNoClobber(inst, new_decl);1253 try new_body.inst_table.putNoClobber(inst, new_inst);
1133 return new_decl;1254 return new_inst;
1134 } else {1255 } else {
1135 return inst_table.getValue(inst).?;1256 return new_body.inst_table.getValue(inst).?;
1136 }1257 }
1137 }1258 }
11381259
...@@ -1140,7 +1261,6 @@ const EmitZIR = struct {...@@ -1140,7 +1261,6 @@ const EmitZIR = struct {
1140 const declval = try self.arena.allocator.create(Inst.DeclVal);1261 const declval = try self.arena.allocator.create(Inst.DeclVal);
1141 declval.* = .{1262 declval.* = .{
1142 .base = .{1263 .base = .{
1143 .name = try self.autoName(),
1144 .src = src,1264 .src = src,
1145 .tag = Inst.DeclVal.base_tag,1265 .tag = Inst.DeclVal.base_tag,
1146 },1266 },
...@@ -1150,12 +1270,11 @@ const EmitZIR = struct {...@@ -1150,12 +1270,11 @@ const EmitZIR = struct {
1150 return &declval.base;1270 return &declval.base;
1151 }1271 }
11521272
1153 fn emitComptimeIntVal(self: *EmitZIR, src: usize, val: Value) !*Inst {1273 fn emitComptimeIntVal(self: *EmitZIR, src: usize, val: Value) !*Decl {
1154 const big_int_space = try self.arena.allocator.create(Value.BigIntSpace);1274 const big_int_space = try self.arena.allocator.create(Value.BigIntSpace);
1155 const int_inst = try self.arena.allocator.create(Inst.Int);1275 const int_inst = try self.arena.allocator.create(Inst.Int);
1156 int_inst.* = .{1276 int_inst.* = .{
1157 .base = .{1277 .base = .{
1158 .name = try self.autoName(),
1159 .src = src,1278 .src = src,
1160 .tag = Inst.Int.base_tag,1279 .tag = Inst.Int.base_tag,
1161 },1280 },
...@@ -1164,34 +1283,29 @@ const EmitZIR = struct {...@@ -1164,34 +1283,29 @@ const EmitZIR = struct {
1164 },1283 },
1165 .kw_args = .{},1284 .kw_args = .{},
1166 };1285 };
1167 try self.decls.append(self.allocator, &int_inst.base);1286 return self.emitUnnamedDecl(&int_inst.base);
1168 return &int_inst.base;
1169 }1287 }
11701288
1171 fn emitDeclRef(self: *EmitZIR, src: usize, decl: *IrModule.Decl) !*Inst {1289 fn emitDeclRef(self: *EmitZIR, src: usize, module_decl: *IrModule.Decl) !*Inst {
1172 const declval = try self.emitDeclVal(src, mem.spanZ(decl.name));1290 const declref_inst = try self.arena.allocator.create(Inst.DeclRef);
1173 const ref_inst = try self.arena.allocator.create(Inst.Ref);1291 declref_inst.* = .{
1174 ref_inst.* = .{
1175 .base = .{1292 .base = .{
1176 .name = try self.autoName(),
1177 .src = src,1293 .src = src,
1178 .tag = Inst.Ref.base_tag,1294 .tag = Inst.DeclRef.base_tag,
1179 },1295 },
1180 .positionals = .{1296 .positionals = .{
1181 .operand = declval,1297 .name = mem.spanZ(module_decl.name),
1182 },1298 },
1183 .kw_args = .{},1299 .kw_args = .{},
1184 };1300 };
1185 try self.decls.append(self.allocator, &ref_inst.base);1301 return &declref_inst.base;
1186
1187 return &ref_inst.base;
1188 }1302 }
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 {
1191 const allocator = &self.arena.allocator;1305 const allocator = &self.arena.allocator;
1192 if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| {1306 if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| {
1193 const decl = decl_ref.decl;1307 const decl = decl_ref.decl;
1194 return self.emitDeclRef(src, decl);1308 return try self.emitUnnamedDecl(try self.emitDeclRef(src, decl));
1195 }1309 }
1196 switch (typed_value.ty.zigTypeTag()) {1310 switch (typed_value.ty.zigTypeTag()) {
1197 .Pointer => {1311 .Pointer => {
...@@ -1218,18 +1332,16 @@ const EmitZIR = struct {...@@ -1218,18 +1332,16 @@ const EmitZIR = struct {
1218 const as_inst = try self.arena.allocator.create(Inst.As);1332 const as_inst = try self.arena.allocator.create(Inst.As);
1219 as_inst.* = .{1333 as_inst.* = .{
1220 .base = .{1334 .base = .{
1221 .name = try self.autoName(),
1222 .src = src,1335 .src = src,
1223 .tag = Inst.As.base_tag,1336 .tag = Inst.As.base_tag,
1224 },1337 },
1225 .positionals = .{1338 .positionals = .{
1226 .dest_type = try self.emitType(src, typed_value.ty),1339 .dest_type = (try self.emitType(src, typed_value.ty)).inst,
1227 .value = try self.emitComptimeIntVal(src, typed_value.val),1340 .value = (try self.emitComptimeIntVal(src, typed_value.val)).inst,
1228 },1341 },
1229 .kw_args = .{},1342 .kw_args = .{},
1230 };1343 };
12311344 return self.emitUnnamedDecl(&as_inst.base);
1232 return &as_inst.base;
1233 },1345 },
1234 .Type => {1346 .Type => {
1235 const ty = typed_value.val.toType();1347 const ty = typed_value.val.toType();
...@@ -1255,7 +1367,6 @@ const EmitZIR = struct {...@@ -1255,7 +1367,6 @@ const EmitZIR = struct {
1255 const fail_inst = try self.arena.allocator.create(Inst.CompileError);1367 const fail_inst = try self.arena.allocator.create(Inst.CompileError);
1256 fail_inst.* = .{1368 fail_inst.* = .{
1257 .base = .{1369 .base = .{
1258 .name = try self.autoName(),
1259 .src = src,1370 .src = src,
1260 .tag = Inst.CompileError.base_tag,1371 .tag = Inst.CompileError.base_tag,
1261 },1372 },
...@@ -1270,7 +1381,6 @@ const EmitZIR = struct {...@@ -1270,7 +1381,6 @@ const EmitZIR = struct {
1270 const fail_inst = try self.arena.allocator.create(Inst.CompileError);1381 const fail_inst = try self.arena.allocator.create(Inst.CompileError);
1271 fail_inst.* = .{1382 fail_inst.* = .{
1272 .base = .{1383 .base = .{
1273 .name = try self.autoName(),
1274 .src = src,1384 .src = src,
1275 .tag = Inst.CompileError.base_tag,1385 .tag = Inst.CompileError.base_tag,
1276 },1386 },
...@@ -1283,7 +1393,7 @@ const EmitZIR = struct {...@@ -1283,7 +1393,7 @@ const EmitZIR = struct {
1283 },1393 },
1284 }1394 }
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
1288 const arena_instrs = try self.arena.allocator.alloc(*Inst, instructions.items.len);1398 const arena_instrs = try self.arena.allocator.alloc(*Inst, instructions.items.len);
1289 mem.copy(*Inst, arena_instrs, instructions.items);1399 mem.copy(*Inst, arena_instrs, instructions.items);
...@@ -1291,18 +1401,16 @@ const EmitZIR = struct {...@@ -1291,18 +1401,16 @@ const EmitZIR = struct {
1291 const fn_inst = try self.arena.allocator.create(Inst.Fn);1401 const fn_inst = try self.arena.allocator.create(Inst.Fn);
1292 fn_inst.* = .{1402 fn_inst.* = .{
1293 .base = .{1403 .base = .{
1294 .name = try self.autoName(),
1295 .src = src,1404 .src = src,
1296 .tag = Inst.Fn.base_tag,1405 .tag = Inst.Fn.base_tag,
1297 },1406 },
1298 .positionals = .{1407 .positionals = .{
1299 .fn_type = fn_type,1408 .fn_type = fn_type.inst,
1300 .body = .{ .instructions = arena_instrs },1409 .body = .{ .instructions = arena_instrs },
1301 },1410 },
1302 .kw_args = .{},1411 .kw_args = .{},
1303 };1412 };
1304 try self.decls.append(self.allocator, &fn_inst.base);1413 return self.emitUnnamedDecl(&fn_inst.base);
1305 return &fn_inst.base;
1306 },1414 },
1307 .Array => {1415 .Array => {
1308 // TODO more checks to make sure this can be emitted as a string literal1416 // TODO more checks to make sure this can be emitted as a string literal
...@@ -1318,7 +1426,6 @@ const EmitZIR = struct {...@@ -1318,7 +1426,6 @@ const EmitZIR = struct {
1318 const str_inst = try self.arena.allocator.create(Inst.Str);1426 const str_inst = try self.arena.allocator.create(Inst.Str);
1319 str_inst.* = .{1427 str_inst.* = .{
1320 .base = .{1428 .base = .{
1321 .name = try self.autoName(),
1322 .src = src,1429 .src = src,
1323 .tag = Inst.Str.base_tag,1430 .tag = Inst.Str.base_tag,
1324 },1431 },
...@@ -1327,8 +1434,7 @@ const EmitZIR = struct {...@@ -1327,8 +1434,7 @@ const EmitZIR = struct {
1327 },1434 },
1328 .kw_args = .{},1435 .kw_args = .{},
1329 };1436 };
1330 try self.decls.append(self.allocator, &str_inst.base);1437 return self.emitUnnamedDecl(&str_inst.base);
1331 return &str_inst.base;
1332 },1438 },
1333 .Void => return self.emitPrimitive(src, .void_value),1439 .Void => return self.emitPrimitive(src, .void_value),
1334 else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}),1440 else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}),
...@@ -1339,7 +1445,6 @@ const EmitZIR = struct {...@@ -1339,7 +1445,6 @@ const EmitZIR = struct {
1339 const new_inst = try self.arena.allocator.create(T);1445 const new_inst = try self.arena.allocator.create(T);
1340 new_inst.* = .{1446 new_inst.* = .{
1341 .base = .{1447 .base = .{
1342 .name = try self.autoName(),
1343 .src = src,1448 .src = src,
1344 .tag = T.base_tag,1449 .tag = T.base_tag,
1345 },1450 },
...@@ -1355,6 +1460,10 @@ const EmitZIR = struct {...@@ -1355,6 +1460,10 @@ const EmitZIR = struct {
1355 inst_table: *std.AutoHashMap(*ir.Inst, *Inst),1460 inst_table: *std.AutoHashMap(*ir.Inst, *Inst),
1356 instructions: *std.ArrayList(*Inst),1461 instructions: *std.ArrayList(*Inst),
1357 ) Allocator.Error!void {1462 ) Allocator.Error!void {
1463 const new_body = ZirBody{
1464 .inst_table = inst_table,
1465 .instructions = instructions,
1466 };
1358 for (body.instructions) |inst| {1467 for (body.instructions) |inst| {
1359 const new_inst = switch (inst.tag) {1468 const new_inst = switch (inst.tag) {
1360 .breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),1469 .breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),
...@@ -1364,16 +1473,15 @@ const EmitZIR = struct {...@@ -1364,16 +1473,15 @@ const EmitZIR = struct {
13641473
1365 const args = try self.arena.allocator.alloc(*Inst, old_inst.args.args.len);1474 const args = try self.arena.allocator.alloc(*Inst, old_inst.args.args.len);
1366 for (args) |*elem, i| {1475 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]);
1368 }1477 }
1369 new_inst.* = .{1478 new_inst.* = .{
1370 .base = .{1479 .base = .{
1371 .name = try self.autoName(),
1372 .src = inst.src,1480 .src = inst.src,
1373 .tag = Inst.Call.base_tag,1481 .tag = Inst.Call.base_tag,
1374 },1482 },
1375 .positionals = .{1483 .positionals = .{
1376 .func = try self.resolveInst(inst_table, old_inst.args.func),1484 .func = try self.resolveInst(new_body, old_inst.args.func),
1377 .args = args,1485 .args = args,
1378 },1486 },
1379 .kw_args = .{},1487 .kw_args = .{},
...@@ -1381,7 +1489,22 @@ const EmitZIR = struct {...@@ -1381,7 +1489,22 @@ const EmitZIR = struct {
1381 break :blk &new_inst.base;1489 break :blk &new_inst.base;
1382 },1490 },
1383 .unreach => try self.emitTrivial(inst.src, Inst.Unreachable),1491 .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),
1385 .constant => unreachable, // excluded from function bodies1508 .constant => unreachable, // excluded from function bodies
1386 .assembly => blk: {1509 .assembly => blk: {
1387 const old_inst = inst.cast(ir.Inst.Assembly).?;1510 const old_inst = inst.cast(ir.Inst.Assembly).?;
...@@ -1389,33 +1512,32 @@ const EmitZIR = struct {...@@ -1389,33 +1512,32 @@ const EmitZIR = struct {
13891512
1390 const inputs = try self.arena.allocator.alloc(*Inst, old_inst.args.inputs.len);1513 const inputs = try self.arena.allocator.alloc(*Inst, old_inst.args.inputs.len);
1391 for (inputs) |*elem, i| {1514 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;
1393 }1516 }
13941517
1395 const clobbers = try self.arena.allocator.alloc(*Inst, old_inst.args.clobbers.len);1518 const clobbers = try self.arena.allocator.alloc(*Inst, old_inst.args.clobbers.len);
1396 for (clobbers) |*elem, i| {1519 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;
1398 }1521 }
13991522
1400 const args = try self.arena.allocator.alloc(*Inst, old_inst.args.args.len);1523 const args = try self.arena.allocator.alloc(*Inst, old_inst.args.args.len);
1401 for (args) |*elem, i| {1524 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]);
1403 }1526 }
14041527
1405 new_inst.* = .{1528 new_inst.* = .{
1406 .base = .{1529 .base = .{
1407 .name = try self.autoName(),
1408 .src = inst.src,1530 .src = inst.src,
1409 .tag = Inst.Asm.base_tag,1531 .tag = Inst.Asm.base_tag,
1410 },1532 },
1411 .positionals = .{1533 .positionals = .{
1412 .asm_source = try self.emitStringLiteral(inst.src, old_inst.args.asm_source),1534 .asm_source = (try self.emitStringLiteral(inst.src, old_inst.args.asm_source)).inst,
1413 .return_type = try self.emitType(inst.src, inst.ty),1535 .return_type = (try self.emitType(inst.src, inst.ty)).inst,
1414 },1536 },
1415 .kw_args = .{1537 .kw_args = .{
1416 .@"volatile" = old_inst.args.is_volatile,1538 .@"volatile" = old_inst.args.is_volatile,
1417 .output = if (old_inst.args.output) |o|1539 .output = if (old_inst.args.output) |o|
1418 try self.emitStringLiteral(inst.src, o)1540 (try self.emitStringLiteral(inst.src, o)).inst
1419 else1541 else
1420 null,1542 null,
1421 .inputs = inputs,1543 .inputs = inputs,
...@@ -1430,12 +1552,11 @@ const EmitZIR = struct {...@@ -1430,12 +1552,11 @@ const EmitZIR = struct {
1430 const new_inst = try self.arena.allocator.create(Inst.PtrToInt);1552 const new_inst = try self.arena.allocator.create(Inst.PtrToInt);
1431 new_inst.* = .{1553 new_inst.* = .{
1432 .base = .{1554 .base = .{
1433 .name = try self.autoName(),
1434 .src = inst.src,1555 .src = inst.src,
1435 .tag = Inst.PtrToInt.base_tag,1556 .tag = Inst.PtrToInt.base_tag,
1436 },1557 },
1437 .positionals = .{1558 .positionals = .{
1438 .ptr = try self.resolveInst(inst_table, old_inst.args.ptr),1559 .ptr = try self.resolveInst(new_body, old_inst.args.ptr),
1439 },1560 },
1440 .kw_args = .{},1561 .kw_args = .{},
1441 };1562 };
...@@ -1446,13 +1567,12 @@ const EmitZIR = struct {...@@ -1446,13 +1567,12 @@ const EmitZIR = struct {
1446 const new_inst = try self.arena.allocator.create(Inst.BitCast);1567 const new_inst = try self.arena.allocator.create(Inst.BitCast);
1447 new_inst.* = .{1568 new_inst.* = .{
1448 .base = .{1569 .base = .{
1449 .name = try self.autoName(),
1450 .src = inst.src,1570 .src = inst.src,
1451 .tag = Inst.BitCast.base_tag,1571 .tag = Inst.BitCast.base_tag,
1452 },1572 },
1453 .positionals = .{1573 .positionals = .{
1454 .dest_type = try self.emitType(inst.src, inst.ty),1574 .dest_type = (try self.emitType(inst.src, inst.ty)).inst,
1455 .operand = try self.resolveInst(inst_table, old_inst.args.operand),1575 .operand = try self.resolveInst(new_body, old_inst.args.operand),
1456 },1576 },
1457 .kw_args = .{},1577 .kw_args = .{},
1458 };1578 };
...@@ -1463,13 +1583,12 @@ const EmitZIR = struct {...@@ -1463,13 +1583,12 @@ const EmitZIR = struct {
1463 const new_inst = try self.arena.allocator.create(Inst.Cmp);1583 const new_inst = try self.arena.allocator.create(Inst.Cmp);
1464 new_inst.* = .{1584 new_inst.* = .{
1465 .base = .{1585 .base = .{
1466 .name = try self.autoName(),
1467 .src = inst.src,1586 .src = inst.src,
1468 .tag = Inst.Cmp.base_tag,1587 .tag = Inst.Cmp.base_tag,
1469 },1588 },
1470 .positionals = .{1589 .positionals = .{
1471 .lhs = try self.resolveInst(inst_table, old_inst.args.lhs),1590 .lhs = try self.resolveInst(new_body, old_inst.args.lhs),
1472 .rhs = try self.resolveInst(inst_table, old_inst.args.rhs),1591 .rhs = try self.resolveInst(new_body, old_inst.args.rhs),
1473 .op = old_inst.args.op,1592 .op = old_inst.args.op,
1474 },1593 },
1475 .kw_args = .{},1594 .kw_args = .{},
...@@ -1491,12 +1610,11 @@ const EmitZIR = struct {...@@ -1491,12 +1610,11 @@ const EmitZIR = struct {
1491 const new_inst = try self.arena.allocator.create(Inst.CondBr);1610 const new_inst = try self.arena.allocator.create(Inst.CondBr);
1492 new_inst.* = .{1611 new_inst.* = .{
1493 .base = .{1612 .base = .{
1494 .name = try self.autoName(),
1495 .src = inst.src,1613 .src = inst.src,
1496 .tag = Inst.CondBr.base_tag,1614 .tag = Inst.CondBr.base_tag,
1497 },1615 },
1498 .positionals = .{1616 .positionals = .{
1499 .condition = try self.resolveInst(inst_table, old_inst.args.condition),1617 .condition = try self.resolveInst(new_body, old_inst.args.condition),
1500 .true_body = .{ .instructions = true_body.toOwnedSlice() },1618 .true_body = .{ .instructions = true_body.toOwnedSlice() },
1501 .false_body = .{ .instructions = false_body.toOwnedSlice() },1619 .false_body = .{ .instructions = false_body.toOwnedSlice() },
1502 },1620 },
...@@ -1509,12 +1627,11 @@ const EmitZIR = struct {...@@ -1509,12 +1627,11 @@ const EmitZIR = struct {
1509 const new_inst = try self.arena.allocator.create(Inst.IsNull);1627 const new_inst = try self.arena.allocator.create(Inst.IsNull);
1510 new_inst.* = .{1628 new_inst.* = .{
1511 .base = .{1629 .base = .{
1512 .name = try self.autoName(),
1513 .src = inst.src,1630 .src = inst.src,
1514 .tag = Inst.IsNull.base_tag,1631 .tag = Inst.IsNull.base_tag,
1515 },1632 },
1516 .positionals = .{1633 .positionals = .{
1517 .operand = try self.resolveInst(inst_table, old_inst.args.operand),1634 .operand = try self.resolveInst(new_body, old_inst.args.operand),
1518 },1635 },
1519 .kw_args = .{},1636 .kw_args = .{},
1520 };1637 };
...@@ -1525,12 +1642,11 @@ const EmitZIR = struct {...@@ -1525,12 +1642,11 @@ const EmitZIR = struct {
1525 const new_inst = try self.arena.allocator.create(Inst.IsNonNull);1642 const new_inst = try self.arena.allocator.create(Inst.IsNonNull);
1526 new_inst.* = .{1643 new_inst.* = .{
1527 .base = .{1644 .base = .{
1528 .name = try self.autoName(),
1529 .src = inst.src,1645 .src = inst.src,
1530 .tag = Inst.IsNonNull.base_tag,1646 .tag = Inst.IsNonNull.base_tag,
1531 },1647 },
1532 .positionals = .{1648 .positionals = .{
1533 .operand = try self.resolveInst(inst_table, old_inst.args.operand),1649 .operand = try self.resolveInst(new_body, old_inst.args.operand),
1534 },1650 },
1535 .kw_args = .{},1651 .kw_args = .{},
1536 };1652 };
...@@ -1542,7 +1658,7 @@ const EmitZIR = struct {...@@ -1542,7 +1658,7 @@ const EmitZIR = struct {
1542 }1658 }
1543 }1659 }
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 {
1546 switch (ty.tag()) {1662 switch (ty.tag()) {
1547 .isize => return self.emitPrimitive(src, .isize),1663 .isize => return self.emitPrimitive(src, .isize),
1548 .usize => return self.emitPrimitive(src, .usize),1664 .usize => return self.emitPrimitive(src, .usize),
...@@ -1575,26 +1691,24 @@ const EmitZIR = struct {...@@ -1575,26 +1691,24 @@ const EmitZIR = struct {
1575 ty.fnParamTypes(param_types);1691 ty.fnParamTypes(param_types);
1576 const emitted_params = try self.arena.allocator.alloc(*Inst, param_types.len);1692 const emitted_params = try self.arena.allocator.alloc(*Inst, param_types.len);
1577 for (param_types) |param_type, i| {1693 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;
1579 }1695 }
15801696
1581 const fntype_inst = try self.arena.allocator.create(Inst.FnType);1697 const fntype_inst = try self.arena.allocator.create(Inst.FnType);
1582 fntype_inst.* = .{1698 fntype_inst.* = .{
1583 .base = .{1699 .base = .{
1584 .name = try self.autoName(),
1585 .src = src,1700 .src = src,
1586 .tag = Inst.FnType.base_tag,1701 .tag = Inst.FnType.base_tag,
1587 },1702 },
1588 .positionals = .{1703 .positionals = .{
1589 .param_types = emitted_params,1704 .param_types = emitted_params,
1590 .return_type = try self.emitType(src, ty.fnReturnType()),1705 .return_type = (try self.emitType(src, ty.fnReturnType())).inst,
1591 },1706 },
1592 .kw_args = .{1707 .kw_args = .{
1593 .cc = ty.fnCallingConvention(),1708 .cc = ty.fnCallingConvention(),
1594 },1709 },
1595 };1710 };
1596 try self.decls.append(self.allocator, &fntype_inst.base);1711 return self.emitUnnamedDecl(&fntype_inst.base);
1597 return &fntype_inst.base;
1598 },1712 },
1599 else => std.debug.panic("TODO implement emitType for {}", .{ty}),1713 else => std.debug.panic("TODO implement emitType for {}", .{ty}),
1600 },1714 },
...@@ -1613,13 +1727,12 @@ const EmitZIR = struct {...@@ -1613,13 +1727,12 @@ const EmitZIR = struct {
1613 }1727 }
1614 }1728 }
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 {
1617 const gop = try self.primitive_table.getOrPut(tag);1731 const gop = try self.primitive_table.getOrPut(tag);
1618 if (!gop.found_existing) {1732 if (!gop.found_existing) {
1619 const primitive_inst = try self.arena.allocator.create(Inst.Primitive);1733 const primitive_inst = try self.arena.allocator.create(Inst.Primitive);
1620 primitive_inst.* = .{1734 primitive_inst.* = .{
1621 .base = .{1735 .base = .{
1622 .name = try self.autoName(),
1623 .src = src,1736 .src = src,
1624 .tag = Inst.Primitive.base_tag,1737 .tag = Inst.Primitive.base_tag,
1625 },1738 },
...@@ -1628,17 +1741,15 @@ const EmitZIR = struct {...@@ -1628,17 +1741,15 @@ const EmitZIR = struct {
1628 },1741 },
1629 .kw_args = .{},1742 .kw_args = .{},
1630 };1743 };
1631 try self.decls.append(self.allocator, &primitive_inst.base);1744 gop.kv.value = try self.emitUnnamedDecl(&primitive_inst.base);
1632 gop.kv.value = &primitive_inst.base;
1633 }1745 }
1634 return gop.kv.value;1746 return gop.kv.value;
1635 }1747 }
16361748
1637 fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Inst {1749 fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Decl {
1638 const str_inst = try self.arena.allocator.create(Inst.Str);1750 const str_inst = try self.arena.allocator.create(Inst.Str);
1639 str_inst.* = .{1751 str_inst.* = .{
1640 .base = .{1752 .base = .{
1641 .name = try self.autoName(),
1642 .src = src,1753 .src = src,
1643 .tag = Inst.Str.base_tag,1754 .tag = Inst.Str.base_tag,
1644 },1755 },
...@@ -1647,22 +1758,17 @@ const EmitZIR = struct {...@@ -1647,22 +1758,17 @@ const EmitZIR = struct {
1647 },1758 },
1648 .kw_args = .{},1759 .kw_args = .{},
1649 };1760 };
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);1764 fn emitUnnamedDecl(self: *EmitZIR, inst: *Inst) !*Decl {
1653 ref_inst.* = .{1765 const decl = try self.arena.allocator.create(Decl);
1654 .base = .{1766 decl.* = .{
1655 .name = try self.autoName(),1767 .name = try self.autoName(),
1656 .src = src,1768 .contents_hash = undefined,
1657 .tag = Inst.Ref.base_tag,1769 .inst = inst,
1658 },
1659 .positionals = .{
1660 .operand = &str_inst.base,
1661 },
1662 .kw_args = .{},
1663 };1770 };
1664 try self.decls.append(self.allocator, &ref_inst.base);1771 try self.decls.append(self.allocator, decl);
16651772 return decl;
1666 return &ref_inst.base;
1667 }1773 }
1668};1774};
src/codegen.cpp+18-2
...@@ -5583,8 +5583,12 @@ static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutableGen *executable, Ir...@@ -5583,8 +5583,12 @@ static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutableGen *executable, Ir
55835583
5584 bool val_is_undef = value_is_all_undef(g, instruction->byte->value);5584 bool val_is_undef = value_is_all_undef(g, instruction->byte->value);
5585 LLVMValueRef fill_char;5585 LLVMValueRef fill_char;
5586 if (val_is_undef && ir_want_runtime_safety_scope(g, instruction->base.base.scope)) {5586 if (val_is_undef) {
5587 fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);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 }
5588 } else {5592 } else {
5589 fill_char = ir_llvm_value(g, instruction->byte);5593 fill_char = ir_llvm_value(g, instruction->byte);
5590 }5594 }
...@@ -7473,6 +7477,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n...@@ -7473,6 +7477,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n
7473 continue;7477 continue;
7474 }7478 }
7475 ZigValue *field_val = const_val->data.x_struct.fields[i];7479 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 }
7476 ZigType *field_type = field_val->type;7486 ZigType *field_type = field_val->type;
7477 assert(field_type != nullptr);7487 assert(field_type != nullptr);
7478 if ((err = ensure_const_val_repr(nullptr, g, nullptr, field_val, field_type))) {7488 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...@@ -9465,9 +9475,15 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
9465 const char *libcxx_include_path = buf_ptr(buf_sprintf("%s" OS_SEP "libcxx" OS_SEP "include",9475 const char *libcxx_include_path = buf_ptr(buf_sprintf("%s" OS_SEP "libcxx" OS_SEP "include",
9466 buf_ptr(g->zig_lib_dir)));9476 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
9468 args.append("-isystem");9481 args.append("-isystem");
9469 args.append(libcxx_include_path);9482 args.append(libcxx_include_path);
94709483
9484 args.append("-isystem");
9485 args.append(libcxxabi_include_path);
9486
9471 if (target_abi_is_musl(g->zig_target->abi)) {9487 if (target_abi_is_musl(g->zig_target->abi)) {
9472 args.append("-D_LIBCPP_HAS_MUSL_LIBC");9488 args.append("-D_LIBCPP_HAS_MUSL_LIBC");
9473 }9489 }
test/stage2/compare_output.zig+115-22
...@@ -1,28 +1,121 @@...@@ -1,28 +1,121 @@
1const std = @import("std");1const std = @import("std");
2const TestContext = @import("../../src-self-hosted/test.zig").TestContext;2const 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
4pub fn addCases(ctx: *TestContext) !void {10pub fn addCases(ctx: *TestContext) !void {
5 // TODO: re-enable these tests.11 if (std.Target.current.os.tag != .linux or
6 // https://github.com/ziglang/zig/issues/136412 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 world19 {
9 //try ctx.testCompareOutputLibC(20 var case = ctx.addExe("hello world with updates", linux_x64);
10 // \\extern fn puts([*]const u8) void;21 // Regular old hello world
11 // \\pub export fn main() c_int {22 case.addCompareOutput(
12 // \\ puts("Hello, world!");23 \\export fn _start() noreturn {
13 // \\ return 0;24 \\ print();
14 // \\}25 \\
15 //, "Hello, world!" ++ std.cstr.line_sep);26 \\ exit();
1627 \\}
17 //// function calling another function28 \\
18 //try ctx.testCompareOutputLibC(29 \\fn print() void {
19 // \\extern fn puts(s: [*]const u8) void;30 \\ asm volatile ("syscall"
20 // \\pub export fn main() c_int {31 \\ :
21 // \\ return foo("OK");32 \\ : [number] "{rax}" (1),
22 // \\}33 \\ [arg1] "{rdi}" (1),
23 // \\fn foo(s: [*]const u8) c_int {34 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
24 // \\ puts(s);35 \\ [arg3] "{rdx}" (14)
25 // \\ return 0;36 \\ : "rcx", "r11", "memory"
26 // \\}37 \\ );
27 //, "OK" ++ std.cstr.line_sep);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 }
28}121}
test/stage2/compile_errors.zig+3-5
...@@ -27,9 +27,8 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -27,9 +27,8 @@ pub fn addCases(ctx: *TestContext) !void {
27 \\ %0 = call(@notafunc, [])27 \\ %0 = call(@notafunc, [])
28 \\})28 \\})
29 \\@0 = str("_start")29 \\@0 = str("_start")
30 \\@1 = ref(@0)30 \\@1 = export(@0, "start")
31 \\@2 = export(@1, @start)31 , &[_][]const u8{":5:13: error: decl 'notafunc' not found"});
32 , &[_][]const u8{":5:13: error: use of undeclared identifier 'notafunc'"});
3332
34 // TODO: this error should occur at the call site, not the fntype decl33 // TODO: this error should occur at the call site, not the fntype decl
35 ctx.addZIRError("call naked function", linux_x64,34 ctx.addZIRError("call naked function", linux_x64,
...@@ -41,8 +40,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -41,8 +40,7 @@ pub fn addCases(ctx: *TestContext) !void {
41 \\ %0 = call(@s, [])40 \\ %0 = call(@s, [])
42 \\})41 \\})
43 \\@0 = str("_start")42 \\@0 = str("_start")
44 \\@1 = ref(@0)43 \\@1 = export(@0, "start")
45 \\@2 = export(@1, @start)
46 , &[_][]const u8{":4:9: error: unable to call function with naked calling convention"});44 , &[_][]const u8{":4:9: error: unable to call function with naked calling convention"});
4745
48 // TODO: re-enable these tests.46 // TODO: re-enable these tests.
test/stage2/zir.zig+152-333
...@@ -14,23 +14,21 @@ pub fn addCases(ctx: *TestContext) void {...@@ -14,23 +14,21 @@ pub fn addCases(ctx: *TestContext) void {
14 \\@fnty = fntype([], @void, cc=C)14 \\@fnty = fntype([], @void, cc=C)
15 \\15 \\
16 \\@9 = str("entry")16 \\@9 = str("entry")
17 \\@10 = ref(@9)17 \\@11 = export(@9, "entry")
18 \\@11 = export(@10, @entry)
19 \\18 \\
20 \\@entry = fn(@fnty, {19 \\@entry = fn(@fnty, {
21 \\ %11 = return()20 \\ %11 = returnvoid()
22 \\})21 \\})
23 ,22 ,
24 \\@void = primitive(void)23 \\@void = primitive(void)
25 \\@fnty = fntype([], @void, cc=C)24 \\@fnty = fntype([], @void, cc=C)
26 \\@9 = str("entry")25 \\@9 = declref("9$0")
27 \\@10 = ref(@9)26 \\@9$0 = str("entry")
28 \\@unnamed$6 = str("entry")27 \\@unnamed$4 = str("entry")
29 \\@unnamed$7 = ref(@unnamed$6)28 \\@unnamed$5 = export(@unnamed$4, "entry")
30 \\@unnamed$8 = export(@unnamed$7, @entry)29 \\@unnamed$6 = fntype([], @void, cc=C)
31 \\@unnamed$10 = fntype([], @void, cc=C)30 \\@entry = fn(@unnamed$6, {
32 \\@entry = fn(@unnamed$10, {31 \\ %0 = returnvoid()
33 \\ %0 = return()
34 \\})32 \\})
35 \\33 \\
36 );34 );
...@@ -45,11 +43,10 @@ pub fn addCases(ctx: *TestContext) void {...@@ -45,11 +43,10 @@ pub fn addCases(ctx: *TestContext) void {
45 \\43 \\
46 \\@entry = fn(@fnty, {44 \\@entry = fn(@fnty, {
47 \\ %a = str("\x32\x08\x01\x0a")45 \\ %a = str("\x32\x08\x01\x0a")
48 \\ %aref = ref(%a)46 \\ %eptr0 = elemptr(%a, @0)
49 \\ %eptr0 = elemptr(%aref, @0)47 \\ %eptr1 = elemptr(%a, @1)
50 \\ %eptr1 = elemptr(%aref, @1)48 \\ %eptr2 = elemptr(%a, @2)
51 \\ %eptr2 = elemptr(%aref, @2)49 \\ %eptr3 = elemptr(%a, @3)
52 \\ %eptr3 = elemptr(%aref, @3)
53 \\ %v0 = deref(%eptr0)50 \\ %v0 = deref(%eptr0)
54 \\ %v1 = deref(%eptr1)51 \\ %v1 = deref(%eptr1)
55 \\ %v2 = deref(%eptr2)52 \\ %v2 = deref(%eptr2)
...@@ -61,15 +58,14 @@ pub fn addCases(ctx: *TestContext) void {...@@ -61,15 +58,14 @@ pub fn addCases(ctx: *TestContext) void {
61 \\ %expected = int(69)58 \\ %expected = int(69)
62 \\ %ok = cmp(%result, eq, %expected)59 \\ %ok = cmp(%result, eq, %expected)
63 \\ %10 = condbr(%ok, {60 \\ %10 = condbr(%ok, {
64 \\ %11 = return()61 \\ %11 = returnvoid()
65 \\ }, {62 \\ }, {
66 \\ %12 = breakpoint()63 \\ %12 = breakpoint()
67 \\ })64 \\ })
68 \\})65 \\})
69 \\66 \\
70 \\@9 = str("entry")67 \\@9 = str("entry")
71 \\@10 = ref(@9)68 \\@11 = export(@9, "entry")
72 \\@11 = export(@10, @entry)
73 ,69 ,
74 \\@void = primitive(void)70 \\@void = primitive(void)
75 \\@fnty = fntype([], @void, cc=C)71 \\@fnty = fntype([], @void, cc=C)
...@@ -77,65 +73,62 @@ pub fn addCases(ctx: *TestContext) void {...@@ -77,65 +73,62 @@ pub fn addCases(ctx: *TestContext) void {
77 \\@1 = int(1)73 \\@1 = int(1)
78 \\@2 = int(2)74 \\@2 = int(2)
79 \\@3 = int(3)75 \\@3 = int(3)
80 \\@unnamed$7 = fntype([], @void, cc=C)76 \\@unnamed$6 = fntype([], @void, cc=C)
81 \\@entry = fn(@unnamed$7, {77 \\@entry = fn(@unnamed$6, {
82 \\ %0 = return()78 \\ %0 = returnvoid()
83 \\})79 \\})
84 \\@a = str("2\x08\x01\n")80 \\@entry$1 = str("2\x08\x01\n")
85 \\@9 = str("entry")81 \\@9 = declref("9$0")
86 \\@10 = ref(@9)82 \\@9$0 = str("entry")
87 \\@unnamed$14 = str("entry")83 \\@unnamed$11 = str("entry")
88 \\@unnamed$15 = ref(@unnamed$14)84 \\@unnamed$12 = export(@unnamed$11, "entry")
89 \\@unnamed$16 = export(@unnamed$15, @entry)
90 \\85 \\
91 );86 );
9287
93 {88 {
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);
95 case.addTransform(90 case.addTransform(
96 \\@void = primitive(void)91 \\@void = primitive(void)
97 \\@fnty = fntype([], @void, cc=C)92 \\@fnty = fntype([], @void, cc=C)
98 \\93 \\
99 \\@9 = str("entry")94 \\@9 = str("entry")
100 \\@10 = ref(@9)95 \\@11 = export(@9, "entry")
101 \\@11 = export(@10, @entry)
102 \\96 \\
103 \\@entry = fn(@fnty, {97 \\@entry = fn(@fnty, {
104 \\ %0 = call(@a, [])98 \\ %0 = call(@a, [])
105 \\ %1 = return()99 \\ %1 = returnvoid()
106 \\})100 \\})
107 \\101 \\
108 \\@a = fn(@fnty, {102 \\@a = fn(@fnty, {
109 \\ %0 = call(@b, [])103 \\ %0 = call(@b, [])
110 \\ %1 = return()104 \\ %1 = returnvoid()
111 \\})105 \\})
112 \\106 \\
113 \\@b = fn(@fnty, {107 \\@b = fn(@fnty, {
114 \\ %0 = call(@a, [])108 \\ %0 = call(@a, [])
115 \\ %1 = return()109 \\ %1 = returnvoid()
116 \\})110 \\})
117 ,111 ,
118 \\@void = primitive(void)112 \\@void = primitive(void)
119 \\@fnty = fntype([], @void, cc=C)113 \\@fnty = fntype([], @void, cc=C)
120 \\@9 = str("entry")114 \\@9 = declref("9$0")
121 \\@10 = ref(@9)115 \\@9$0 = str("entry")
122 \\@unnamed$6 = str("entry")116 \\@unnamed$4 = str("entry")
123 \\@unnamed$7 = ref(@unnamed$6)117 \\@unnamed$5 = export(@unnamed$4, "entry")
124 \\@unnamed$8 = export(@unnamed$7, @entry)118 \\@unnamed$6 = fntype([], @void, cc=C)
125 \\@unnamed$12 = fntype([], @void, cc=C)119 \\@entry = fn(@unnamed$6, {
126 \\@entry = fn(@unnamed$12, {
127 \\ %0 = call(@a, [], modifier=auto)120 \\ %0 = call(@a, [], modifier=auto)
128 \\ %1 = return()121 \\ %1 = returnvoid()
129 \\})122 \\})
130 \\@unnamed$17 = fntype([], @void, cc=C)123 \\@unnamed$8 = fntype([], @void, cc=C)
131 \\@a = fn(@unnamed$17, {124 \\@a = fn(@unnamed$8, {
132 \\ %0 = call(@b, [], modifier=auto)125 \\ %0 = call(@b, [], modifier=auto)
133 \\ %1 = return()126 \\ %1 = returnvoid()
134 \\})127 \\})
135 \\@unnamed$22 = fntype([], @void, cc=C)128 \\@unnamed$10 = fntype([], @void, cc=C)
136 \\@b = fn(@unnamed$22, {129 \\@b = fn(@unnamed$10, {
137 \\ %0 = call(@a, [], modifier=auto)130 \\ %0 = call(@a, [], modifier=auto)
138 \\ %1 = return()131 \\ %1 = returnvoid()
139 \\})132 \\})
140 \\133 \\
141 );134 );
...@@ -145,27 +138,26 @@ pub fn addCases(ctx: *TestContext) void {...@@ -145,27 +138,26 @@ pub fn addCases(ctx: *TestContext) void {
145 \\@fnty = fntype([], @void, cc=C)138 \\@fnty = fntype([], @void, cc=C)
146 \\139 \\
147 \\@9 = str("entry")140 \\@9 = str("entry")
148 \\@10 = ref(@9)141 \\@11 = export(@9, "entry")
149 \\@11 = export(@10, @entry)
150 \\142 \\
151 \\@entry = fn(@fnty, {143 \\@entry = fn(@fnty, {
152 \\ %0 = call(@a, [])144 \\ %0 = call(@a, [])
153 \\ %1 = return()145 \\ %1 = returnvoid()
154 \\})146 \\})
155 \\147 \\
156 \\@a = fn(@fnty, {148 \\@a = fn(@fnty, {
157 \\ %0 = call(@b, [])149 \\ %0 = call(@b, [])
158 \\ %1 = return()150 \\ %1 = returnvoid()
159 \\})151 \\})
160 \\152 \\
161 \\@b = fn(@fnty, {153 \\@b = fn(@fnty, {
162 \\ %9 = compileerror("message")154 \\ %9 = compileerror("message")
163 \\ %0 = call(@a, [])155 \\ %0 = call(@a, [])
164 \\ %1 = return()156 \\ %1 = returnvoid()
165 \\})157 \\})
166 ,158 ,
167 &[_][]const u8{159 &[_][]const u8{
168 ":19:21: error: message",160 ":18:21: error: message",
169 },161 },
170 );162 );
171 // Now we remove the call to `a`. `a` and `b` form a cycle, but no entry points are163 // 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 {...@@ -176,34 +168,32 @@ pub fn addCases(ctx: *TestContext) void {
176 \\@fnty = fntype([], @void, cc=C)168 \\@fnty = fntype([], @void, cc=C)
177 \\169 \\
178 \\@9 = str("entry")170 \\@9 = str("entry")
179 \\@10 = ref(@9)171 \\@11 = export(@9, "entry")
180 \\@11 = export(@10, @entry)
181 \\172 \\
182 \\@entry = fn(@fnty, {173 \\@entry = fn(@fnty, {
183 \\ %1 = return()174 \\ %0 = returnvoid()
184 \\})175 \\})
185 \\176 \\
186 \\@a = fn(@fnty, {177 \\@a = fn(@fnty, {
187 \\ %0 = call(@b, [])178 \\ %0 = call(@b, [])
188 \\ %1 = return()179 \\ %1 = returnvoid()
189 \\})180 \\})
190 \\181 \\
191 \\@b = fn(@fnty, {182 \\@b = fn(@fnty, {
192 \\ %9 = compileerror("message")183 \\ %9 = compileerror("message")
193 \\ %0 = call(@a, [])184 \\ %0 = call(@a, [])
194 \\ %1 = return()185 \\ %1 = returnvoid()
195 \\})186 \\})
196 ,187 ,
197 \\@void = primitive(void)188 \\@void = primitive(void)
198 \\@fnty = fntype([], @void, cc=C)189 \\@fnty = fntype([], @void, cc=C)
199 \\@9 = str("entry")190 \\@9 = declref("9$2")
200 \\@10 = ref(@9)191 \\@9$2 = str("entry")
201 \\@unnamed$6 = str("entry")192 \\@unnamed$4 = str("entry")
202 \\@unnamed$7 = ref(@unnamed$6)193 \\@unnamed$5 = export(@unnamed$4, "entry")
203 \\@unnamed$8 = export(@unnamed$7, @entry)194 \\@unnamed$6 = fntype([], @void, cc=C)
204 \\@unnamed$10 = fntype([], @void, cc=C)195 \\@entry = fn(@unnamed$6, {
205 \\@entry = fn(@unnamed$10, {196 \\ %0 = returnvoid()
206 \\ %0 = return()
207 \\})197 \\})
208 \\198 \\
209 );199 );
...@@ -217,272 +207,101 @@ pub fn addCases(ctx: *TestContext) void {...@@ -217,272 +207,101 @@ pub fn addCases(ctx: *TestContext) void {
217 return;207 return;
218 }208 }
219209
220 ctx.addZIRCompareOutput(210 ctx.addZIRCompareOutput("hello world ZIR",
221 "hello world ZIR, update msg",211 \\@noreturn = primitive(noreturn)
222 &[_][]const u8{212 \\@void = primitive(void)
223 \\@noreturn = primitive(noreturn)213 \\@usize = primitive(usize)
224 \\@void = primitive(void)214 \\@0 = int(0)
225 \\@usize = primitive(usize)215 \\@1 = int(1)
226 \\@0 = int(0)216 \\@2 = int(2)
227 \\@1 = int(1)217 \\@3 = int(3)
228 \\@2 = int(2)218 \\
229 \\@3 = int(3)219 \\@msg = str("Hello, world!\n")
230 \\220 \\
231 \\@syscall_array = str("syscall")221 \\@start_fnty = fntype([], @noreturn, cc=Naked)
232 \\@sysoutreg_array = str("={rax}")222 \\@start = fn(@start_fnty, {
233 \\@rax_array = str("{rax}")223 \\ %SYS_exit_group = int(231)
234 \\@rdi_array = str("{rdi}")224 \\ %exit_code = as(@usize, @0)
235 \\@rcx_array = str("rcx")225 \\
236 \\@r11_array = str("r11")226 \\ %syscall = str("syscall")
237 \\@rdx_array = str("{rdx}")227 \\ %sysoutreg = str("={rax}")
238 \\@rsi_array = str("{rsi}")228 \\ %rax = str("{rax}")
239 \\@memory_array = str("memory")229 \\ %rdi = str("{rdi}")
240 \\@len_array = str("len")230 \\ %rcx = str("rcx")
241 \\231 \\ %rdx = str("{rdx}")
242 \\@msg = str("Hello, world!\n")232 \\ %rsi = str("{rsi}")
243 \\233 \\ %r11 = str("r11")
244 \\@start_fnty = fntype([], @noreturn, cc=Naked)234 \\ %memory = str("memory")
245 \\@start = fn(@start_fnty, {235 \\
246 \\ %SYS_exit_group = int(231)236 \\ %SYS_write = as(@usize, @1)
247 \\ %exit_code = as(@usize, @0)237 \\ %STDOUT_FILENO = as(@usize, @1)
248 \\238 \\
249 \\ %syscall = ref(@syscall_array)239 \\ %msg_addr = ptrtoint(@msg)
250 \\ %sysoutreg = ref(@sysoutreg_array)240 \\
251 \\ %rax = ref(@rax_array)241 \\ %len_name = str("len")
252 \\ %rdi = ref(@rdi_array)242 \\ %msg_len_ptr = fieldptr(@msg, %len_name)
253 \\ %rcx = ref(@rcx_array)243 \\ %msg_len = deref(%msg_len_ptr)
254 \\ %rdx = ref(@rdx_array)244 \\ %rc_write = asm(%syscall, @usize,
255 \\ %rsi = ref(@rsi_array)245 \\ volatile=1,
256 \\ %r11 = ref(@r11_array)246 \\ output=%sysoutreg,
257 \\ %memory = ref(@memory_array)247 \\ inputs=[%rax, %rdi, %rsi, %rdx],
258 \\248 \\ clobbers=[%rcx, %r11, %memory],
259 \\ %SYS_write = as(@usize, @1)249 \\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])
260 \\ %STDOUT_FILENO = as(@usize, @1)250 \\
261 \\251 \\ %rc_exit = asm(%syscall, @usize,
262 \\ %msg_ptr = ref(@msg)252 \\ volatile=1,
263 \\ %msg_addr = ptrtoint(%msg_ptr)253 \\ output=%sysoutreg,
264 \\254 \\ inputs=[%rax, %rdi],
265 \\ %len_name = ref(@len_array)255 \\ clobbers=[%rcx, %r11, %memory],
266 \\ %msg_len_ptr = fieldptr(%msg_ptr, %len_name)256 \\ args=[%SYS_exit_group, %exit_code])
267 \\ %msg_len = deref(%msg_len_ptr)257 \\
268 \\ %rc_write = asm(%syscall, @usize,258 \\ %99 = unreachable()
269 \\ volatile=1,259 \\});
270 \\ output=%sysoutreg,260 \\
271 \\ inputs=[%rax, %rdi, %rsi, %rdx],261 \\@9 = str("_start")
272 \\ clobbers=[%rcx, %r11, %memory],262 \\@11 = export(@9, "start")
273 \\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])263 ,
274 \\264 \\Hello, world!
275 \\ %rc_exit = asm(%syscall, @usize,265 \\
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 },
434 );266 );
435267
436 ctx.addZIRCompareOutput(268 ctx.addZIRCompareOutput("function call with no args no return value",
437 "function call with no args no return value",269 \\@noreturn = primitive(noreturn)
438 &[_][]const u8{270 \\@void = primitive(void)
439 \\@noreturn = primitive(noreturn)271 \\@usize = primitive(usize)
440 \\@void = primitive(void)272 \\@0 = int(0)
441 \\@usize = primitive(usize)273 \\@1 = int(1)
442 \\@0 = int(0)274 \\@2 = int(2)
443 \\@1 = int(1)275 \\@3 = int(3)
444 \\@2 = int(2)276 \\
445 \\@3 = int(3)277 \\@exit0_fnty = fntype([], @noreturn)
446 \\278 \\@exit0 = fn(@exit0_fnty, {
447 \\@syscall_array = str("syscall")279 \\ %SYS_exit_group = int(231)
448 \\@sysoutreg_array = str("={rax}")280 \\ %exit_code = as(@usize, @0)
449 \\@rax_array = str("{rax}")281 \\
450 \\@rdi_array = str("{rdi}")282 \\ %syscall = str("syscall")
451 \\@rcx_array = str("rcx")283 \\ %sysoutreg = str("={rax}")
452 \\@r11_array = str("r11")284 \\ %rax = str("{rax}")
453 \\@memory_array = str("memory")285 \\ %rdi = str("{rdi}")
454 \\286 \\ %rcx = str("rcx")
455 \\@exit0_fnty = fntype([], @noreturn)287 \\ %r11 = str("r11")
456 \\@exit0 = fn(@exit0_fnty, {288 \\ %memory = str("memory")
457 \\ %SYS_exit_group = int(231)289 \\
458 \\ %exit_code = as(@usize, @0)290 \\ %rc = asm(%syscall, @usize,
459 \\291 \\ volatile=1,
460 \\ %syscall = ref(@syscall_array)292 \\ output=%sysoutreg,
461 \\ %sysoutreg = ref(@sysoutreg_array)293 \\ inputs=[%rax, %rdi],
462 \\ %rax = ref(@rax_array)294 \\ clobbers=[%rcx, %r11, %memory],
463 \\ %rdi = ref(@rdi_array)295 \\ args=[%SYS_exit_group, %exit_code])
464 \\ %rcx = ref(@rcx_array)296 \\
465 \\ %r11 = ref(@r11_array)297 \\ %99 = unreachable()
466 \\ %memory = ref(@memory_array)298 \\});
467 \\299 \\
468 \\ %rc = asm(%syscall, @usize,300 \\@start_fnty = fntype([], @noreturn, cc=Naked)
469 \\ volatile=1,301 \\@start = fn(@start_fnty, {
470 \\ output=%sysoutreg,302 \\ %0 = call(@exit0, [])
471 \\ inputs=[%rax, %rdi],303 \\})
472 \\ clobbers=[%rcx, %r11, %memory],304 \\@9 = str("_start")
473 \\ args=[%SYS_exit_group, %exit_code])305 \\@11 = export(@9, "start")
474 \\306 , "");
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 );
488}307}