authorgravatar for timonkruiper@gmail.comTimon Kruiper <timonkruiper@gmail.com> 2021-04-05 22:50:54+02:00
committergravatar for timonkruiper@gmail.comTimon Kruiper <timonkruiper@gmail.com> 2021-04-08 14:23:18+02:00
logac14b52e85f857f7f70846d22ea18ea265acb91a
treebceefa15a211ba323fe7645dd69ab6b768f59555
parente85cd616ef6439fdb9e7ac118251bb7c2296e553

stage2: add support for start.zig

This adds a simplified start2.zig that the current stage2 compiler is able to generate code for.

6 files changed, 136 insertions(+), 34 deletions(-)

lib/std/start2.zig created+58
...@@ -0,0 +1,58 @@
1const root = @import("root");
2const builtin = @import("builtin");
3
4comptime {
5 if (builtin.output_mode == 0) { // OutputMode.Exe
6 if (builtin.link_libc or builtin.object_format == 5) { // ObjectFormat.c
7 if (!@hasDecl(root, "main")) {
8 @export(otherMain, "main");
9 }
10 } else {
11 if (!@hasDecl(root, "_start")) {
12 @export(otherStart, "_start");
13 }
14 }
15 }
16}
17
18// FIXME: Cannot call this function `main`, because `fully qualified names`
19// have not been implemented yet.
20fn otherMain() callconv(.C) c_int {
21 root.zigMain();
22 return 0;
23}
24
25// FIXME: Cannot call this function `_start`, because `fully qualified names`
26// have not been implemented yet.
27fn otherStart() callconv(.Naked) noreturn {
28 root.zigMain();
29 otherExit();
30}
31
32// FIXME: Cannot call this function `exit`, because `fully qualified names`
33// have not been implemented yet.
34fn otherExit() noreturn {
35 if (builtin.arch == 31) { // x86_64
36 asm volatile ("syscall"
37 :
38 : [number] "{rax}" (231),
39 [arg1] "{rdi}" (0)
40 : "rcx", "r11", "memory"
41 );
42 } else if (builtin.arch == 0) { // arm
43 asm volatile ("svc #0"
44 :
45 : [number] "{r7}" (1),
46 [arg1] "{r0}" (0)
47 : "memory"
48 );
49 } else if (builtin.arch == 2) { // aarch64
50 asm volatile ("svc #0"
51 :
52 : [number] "{x8}" (93),
53 [arg1] "{x0}" (0)
54 : "memory", "cc"
55 );
56 } else @compileError("not yet supported!");
57 unreachable;
58}
src/Compilation.zig+40-30
...@@ -908,41 +908,45 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -908,41 +908,45 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
908 };908 };
909909
910 const builtin_pkg = try Package.create(gpa, zig_cache_artifact_directory.path.?, "builtin2.zig");910 const builtin_pkg = try Package.create(gpa, zig_cache_artifact_directory.path.?, "builtin2.zig");
911
912 const std_dir_path = try options.zig_lib_directory.join(gpa, &[_][]const u8{"std"});
913 defer gpa.free(std_dir_path);
914 const start_pkg = try Package.create(gpa, std_dir_path, "start2.zig");
915
911 try root_pkg.add(gpa, "builtin", builtin_pkg);916 try root_pkg.add(gpa, "builtin", builtin_pkg);
912 try root_pkg.add(gpa, "root", root_pkg);917 try root_pkg.add(gpa, "root", root_pkg);
913918
919 try start_pkg.add(gpa, "builtin", builtin_pkg);
920 try start_pkg.add(gpa, "root", root_pkg);
921
914 // TODO when we implement serialization and deserialization of incremental compilation metadata,922 // TODO when we implement serialization and deserialization of incremental compilation metadata,
915 // this is where we would load it. We have open a handle to the directory where923 // this is where we would load it. We have open a handle to the directory where
916 // the output either already is, or will be.924 // the output either already is, or will be.
917 // However we currently do not have serialization of such metadata, so for now925 // However we currently do not have serialization of such metadata, so for now
918 // we set up an empty Module that does the entire compilation fresh.926 // we set up an empty Module that does the entire compilation fresh.
919927
920 const root_scope = rs: {928 if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) return error.ZirFilesUnsupported;
921 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {929
922 const root_scope = try gpa.create(Module.Scope.File);930 const start_scope = ss: {
923 const struct_ty = try Type.Tag.empty_struct.create(931 const start_scope = try gpa.create(Module.Scope.File);
924 gpa,932 const struct_ty = try Type.Tag.empty_struct.create(
925 &root_scope.root_container,933 gpa,
926 );934 &start_scope.root_container,
927 root_scope.* = .{935 );
928 // TODO this is duped so it can be freed in Container.deinit936 start_scope.* = .{
929 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),937 // TODO this is duped so it can be freed in Container.deinit
930 .source = .{ .unloaded = {} },938 .sub_file_path = try gpa.dupe(u8, start_pkg.root_src_path),
931 .tree = undefined,939 .source = .{ .unloaded = {} },
932 .status = .never_loaded,940 .tree = undefined,
933 .pkg = root_pkg,941 .status = .never_loaded,
934 .root_container = .{942 .pkg = start_pkg,
935 .file_scope = root_scope,943 .root_container = .{
936 .decls = .{},944 .file_scope = start_scope,
937 .ty = struct_ty,945 .decls = .{},
938 },946 .ty = struct_ty,
939 };947 },
940 break :rs root_scope;948 };
941 } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) {949 break :ss start_scope;
942 return error.ZirFilesUnsupported;
943 } else {
944 unreachable;
945 }
946 };950 };
947951
948 const module = try arena.create(Module);952 const module = try arena.create(Module);
...@@ -951,7 +955,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -951,7 +955,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
951 .gpa = gpa,955 .gpa = gpa,
952 .comp = comp,956 .comp = comp,
953 .root_pkg = root_pkg,957 .root_pkg = root_pkg,
954 .root_scope = root_scope,958 .root_scope = null,
959 .start_pkg = start_pkg,
960 .start_scope = start_scope,
955 .zig_cache_artifact_directory = zig_cache_artifact_directory,961 .zig_cache_artifact_directory = zig_cache_artifact_directory,
956 .emit_h = options.emit_h,962 .emit_h = options.emit_h,
957 .error_name_list = try std.ArrayListUnmanaged([]const u8).initCapacity(gpa, 1),963 .error_name_list = try std.ArrayListUnmanaged([]const u8).initCapacity(gpa, 1),
...@@ -1353,9 +1359,9 @@ pub fn update(self: *Compilation) !void {...@@ -1353,9 +1359,9 @@ pub fn update(self: *Compilation) !void {
1353 // TODO Detect which source files changed.1359 // TODO Detect which source files changed.
1354 // Until then we simulate a full cache miss. Source files could have been loaded1360 // Until then we simulate a full cache miss. Source files could have been loaded
1355 // for any reason; to force a refresh we unload now.1361 // for any reason; to force a refresh we unload now.
1356 module.unloadFile(module.root_scope);1362 module.unloadFile(module.start_scope);
1357 module.failed_root_src_file = null;1363 module.failed_root_src_file = null;
1358 module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) {1364 module.analyzeContainer(&module.start_scope.root_container) catch |err| switch (err) {
1359 error.AnalysisFail => {1365 error.AnalysisFail => {
1360 assert(self.totalErrorCount() != 0);1366 assert(self.totalErrorCount() != 0);
1361 },1367 },
...@@ -1416,7 +1422,7 @@ pub fn update(self: *Compilation) !void {...@@ -1416,7 +1422,7 @@ pub fn update(self: *Compilation) !void {
1416 // to report error messages. Otherwise we unload all source files to save memory.1422 // to report error messages. Otherwise we unload all source files to save memory.
1417 if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) {1423 if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) {
1418 if (self.bin_file.options.module) |module| {1424 if (self.bin_file.options.module) |module| {
1419 module.root_scope.unload(self.gpa);1425 module.start_scope.unload(self.gpa);
1420 }1426 }
1421 }1427 }
1422}1428}
...@@ -2851,11 +2857,15 @@ fn generateBuiltin2ZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 {...@@ -2851,11 +2857,15 @@ fn generateBuiltin2ZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 {
2851 \\pub const link_libc = {};2857 \\pub const link_libc = {};
2852 \\pub const arch = {};2858 \\pub const arch = {};
2853 \\pub const os = {};2859 \\pub const os = {};
2860 \\pub const output_mode = {};
2861 \\pub const object_format = {};
2854 \\2862 \\
2855 , .{2863 , .{
2856 comp.bin_file.options.link_libc,2864 comp.bin_file.options.link_libc,
2857 @enumToInt(target.cpu.arch),2865 @enumToInt(target.cpu.arch),
2858 @enumToInt(target.os.tag),2866 @enumToInt(target.os.tag),
2867 @enumToInt(comp.bin_file.options.output_mode),
2868 @enumToInt(comp.bin_file.options.object_format),
2859 });2869 });
28602870
2861 return buffer.toOwnedSlice();2871 return buffer.toOwnedSlice();
src/Module.zig+7-2
...@@ -35,8 +35,11 @@ comp: *Compilation,...@@ -35,8 +35,11 @@ comp: *Compilation,
35zig_cache_artifact_directory: Compilation.Directory,35zig_cache_artifact_directory: Compilation.Directory,
36/// Pointer to externally managed resource. `null` if there is no zig file being compiled.36/// Pointer to externally managed resource. `null` if there is no zig file being compiled.
37root_pkg: *Package,37root_pkg: *Package,
38/// This is populated when `@import("root")` is analysed.
39root_scope: ?*Scope.File,
40start_pkg: *Package,
38/// Module owns this resource.41/// Module owns this resource.
39root_scope: *Scope.File,42start_scope: *Scope.File,
40/// It's rare for a decl to be exported, so we save memory by having a sparse map of43/// It's rare for a decl to be exported, so we save memory by having a sparse map of
41/// Decl pointers to details about them being exported.44/// Decl pointers to details about them being exported.
42/// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table.45/// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table.
...@@ -2341,7 +2344,9 @@ pub fn deinit(mod: *Module) void {...@@ -2341,7 +2344,9 @@ pub fn deinit(mod: *Module) void {
2341 mod.export_owners.deinit(gpa);2344 mod.export_owners.deinit(gpa);
23422345
2343 mod.symbol_exports.deinit(gpa);2346 mod.symbol_exports.deinit(gpa);
2344 mod.root_scope.destroy(gpa);2347
2348 mod.start_scope.destroy(gpa);
2349 mod.start_pkg.destroy(gpa);
23452350
2346 var it = mod.global_error_set.iterator();2351 var it = mod.global_error_set.iterator();
2347 while (it.next()) |entry| {2352 while (it.next()) |entry| {
src/Package.zig+25
...@@ -15,6 +15,9 @@ root_src_path: []const u8,...@@ -15,6 +15,9 @@ root_src_path: []const u8,
15table: Table = .{},15table: Table = .{},
16parent: ?*Package = null,16parent: ?*Package = null,
1717
18// Used when freeing packages
19seen: bool = false,
20
18/// Allocate a Package. No references to the slices passed are kept.21/// Allocate a Package. No references to the slices passed are kept.
19pub fn create(22pub fn create(
20 gpa: *Allocator,23 gpa: *Allocator,
...@@ -55,6 +58,14 @@ pub fn destroy(pkg: *Package, gpa: *Allocator) void {...@@ -55,6 +58,14 @@ pub fn destroy(pkg: *Package, gpa: *Allocator) void {
55 pkg.root_src_directory.handle.close();58 pkg.root_src_directory.handle.close();
56 }59 }
5760
61 // First we recurse into all the packages and remove packages from the tables
62 // once we have seen it before. We do this to make sure that that
63 // a package can only be found once in the whole tree.
64 if (!pkg.seen) {
65 pkg.seen = true;
66 pkg.markSeen(gpa);
67 }
68
58 {69 {
59 var it = pkg.table.iterator();70 var it = pkg.table.iterator();
60 while (it.next()) |kv| {71 while (it.next()) |kv| {
...@@ -69,6 +80,20 @@ pub fn destroy(pkg: *Package, gpa: *Allocator) void {...@@ -69,6 +80,20 @@ pub fn destroy(pkg: *Package, gpa: *Allocator) void {
69 gpa.destroy(pkg);80 gpa.destroy(pkg);
70}81}
7182
83fn markSeen(pkg: *Package, gpa: *Allocator) void {
84 var it = pkg.table.iterator();
85 while (it.next()) |kv| {
86 if (pkg != kv.value) {
87 if (kv.value.seen) {
88 pkg.table.removeAssertDiscard(kv.key);
89 } else {
90 kv.value.seen = true;
91 kv.value.markSeen(gpa);
92 }
93 }
94 }
95}
96
72pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) !void {97pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) !void {
73 try pkg.table.ensureCapacity(gpa, pkg.table.count() + 1);98 try pkg.table.ensureCapacity(gpa, pkg.table.count() + 1);
74 const name_dupe = try mem.dupe(gpa, u8, name);99 const name_dupe = try mem.dupe(gpa, u8, name);
src/Sema.zig+4-1
...@@ -4699,7 +4699,7 @@ fn namedFieldPtr(...@@ -4699,7 +4699,7 @@ fn namedFieldPtr(
4699 }4699 }
47004700
4701 // TODO this will give false positives for structs inside the root file4701 // TODO this will give false positives for structs inside the root file
4702 if (container_scope.file_scope == mod.root_scope) {4702 if (container_scope.file_scope == mod.root_scope.?) {
4703 return mod.fail(4703 return mod.fail(
4704 &block.base,4704 &block.base,
4705 src,4705 src,
...@@ -5338,6 +5338,9 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin...@@ -5338,6 +5338,9 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
5338 .ty = struct_ty,5338 .ty = struct_ty,
5339 },5339 },
5340 };5340 };
5341 if (mem.eql(u8, target_string, "root")) {
5342 sema.mod.root_scope = file_scope;
5343 }
5341 sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {5344 sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
5342 error.AnalysisFail => {5345 error.AnalysisFail => {
5343 assert(sema.mod.comp.totalErrorCount() != 0);5346 assert(sema.mod.comp.totalErrorCount() != 0);
src/main.zig+2-1
...@@ -1732,6 +1732,8 @@ fn buildOutputType(...@@ -1732,6 +1732,8 @@ fn buildOutputType(
1732 },1732 },
1733 }1733 }
17341734
1735 // This gets cleaned up, because root_pkg becomes part of the
1736 // package table of the start_pkg.
1735 const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {1737 const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {
1736 if (main_pkg_path) |p| {1738 if (main_pkg_path) |p| {
1737 const rel_src_path = try fs.path.relative(gpa, p, src_path);1739 const rel_src_path = try fs.path.relative(gpa, p, src_path);
...@@ -1741,7 +1743,6 @@ fn buildOutputType(...@@ -1741,7 +1743,6 @@ fn buildOutputType(
1741 break :blk try Package.create(gpa, fs.path.dirname(src_path), fs.path.basename(src_path));1743 break :blk try Package.create(gpa, fs.path.dirname(src_path), fs.path.basename(src_path));
1742 }1744 }
1743 } else null;1745 } else null;
1744 defer if (root_pkg) |p| p.destroy(gpa);
17451746
1746 // Transfer packages added with --pkg-begin/--pkg-end to the root package1747 // Transfer packages added with --pkg-begin/--pkg-end to the root package
1747 if (root_pkg) |pkg| {1748 if (root_pkg) |pkg| {