| author | |
| committer | |
| log | ac14b52e85f857f7f70846d22ea18ea265acb91a |
| tree | bceefa15a211ba323fe7645dd69ab6b768f59555 |
| parent | e85cd616ef6439fdb9e7ac118251bb7c2296e553 |
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 @@ | ||
| 1 | const root = @import("root"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | |||
| 4 | comptime { | ||
| 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. | ||
| 20 | fn 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. | ||
| 27 | fn 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. | ||
| 34 | fn 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 | }; |
| 909 | 909 | ||
| 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); |
| 913 | 918 | ||
| 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 where | 923 | // 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 now | 925 | // 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. |
| 919 | 927 | ||
| 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.deinit | 936 | 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 | }; |
| 947 | 951 | ||
| 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 loaded | 1360 | // 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 | }); |
| 2860 | 2870 | ||
| 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, |
| 35 | zig_cache_artifact_directory: Compilation.Directory, | 35 | zig_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. |
| 37 | root_pkg: *Package, | 37 | root_pkg: *Package, |
| 38 | /// This is populated when `@import("root")` is analysed. | ||
| 39 | root_scope: ?*Scope.File, | ||
| 40 | start_pkg: *Package, | ||
| 38 | /// Module owns this resource. | 41 | /// Module owns this resource. |
| 39 | root_scope: *Scope.File, | 42 | start_scope: *Scope.File, |
| 40 | /// It's rare for a decl to be exported, so we save memory by having a sparse map of | 43 | /// 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); |
| 2342 | 2345 | ||
| 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); | ||
| 2345 | 2350 | ||
| 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, |
| 15 | table: Table = .{}, | 15 | table: Table = .{}, |
| 16 | parent: ?*Package = null, | 16 | parent: ?*Package = null, |
| 17 | 17 | ||
| 18 | // Used when freeing packages | ||
| 19 | seen: 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. |
| 19 | pub fn create( | 22 | pub 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 | } |
| 57 | 60 | ||
| 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 | } |
| 71 | 82 | ||
| 83 | fn 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 | |||
| 72 | pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) !void { | 97 | pub 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 | } |
| 4700 | 4700 | ||
| 4701 | // TODO this will give false positives for structs inside the root file | 4701 | // 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 | } |
| 1734 | 1734 | ||
| 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); | ||
| 1745 | 1746 | ||
| 1746 | // Transfer packages added with --pkg-begin/--pkg-end to the root package | 1747 | // Transfer packages added with --pkg-begin/--pkg-end to the root package |
| 1747 | if (root_pkg) |pkg| { | 1748 | if (root_pkg) |pkg| { |