authorgravatar for noam@pixelhero.devNoam Preil <noam@pixelhero.dev> 2020-07-07 16:40:14-04:00
committergravatar for noam@pixelhero.devNoam Preil <noam@pixelhero.dev> 2020-07-07 16:40:14-04:00
loga17200dab1b0b373e85c6c2cc266078012a81948
tree320be8b1150cd3396d3e428d463fdbbb6836de78
parentb4c571301be7dd2174b2d067d643a2a093797e7e
signature Commit is signed but in an unrecognized format.

CBE skeleton


3 files changed, 114 insertions(+), 34 deletions(-)

src-self-hosted/link.zig+58-1
...@@ -38,7 +38,11 @@ pub fn openBinFilePath(...@@ -38,7 +38,11 @@ pub fn openBinFilePath(
38 errdefer file.close();38 errdefer file.close();
3939
40 if (options.c_standard) |cstd| {40 if (options.c_standard) |cstd| {
41 return error.Unimplemented;41 var bin_file = try allocator.create(File.C);
42 errdefer allocator.destroy(bin_file);
43 bin_file.* = try openCFile(allocator, file, options);
44 bin_file.owns_file_handle = true;
45 return &bin_file.base;
42 } else {46 } else {
43 var bin_file = try allocator.create(File.Elf);47 var bin_file = try allocator.create(File.Elf);
44 errdefer allocator.destroy(bin_file);48 errdefer allocator.destroy(bin_file);
...@@ -82,6 +86,17 @@ pub fn writeFilePath(...@@ -82,6 +86,17 @@ pub fn writeFilePath(
82 return result;86 return result;
83}87}
8488
89pub fn openCFile(allocator: *Allocator, file: fs.File, options: Options) !File.C {
90 var self: File.C = .{
91 .allocator = allocator,
92 .file = file,
93 .options = options,
94 .owns_file_handle = false,
95 };
96 errdefer self.deinit();
97 return self;
98}
99
85/// Attempts incremental linking, if the file already exists.100/// Attempts incremental linking, if the file already exists.
86/// If incremental linking fails, falls back to truncating the file and rewriting it.101/// If incremental linking fails, falls back to truncating the file and rewriting it.
87/// Returns an error if `file` is not already open with +read +write +seek abilities.102/// Returns an error if `file` is not already open with +read +write +seek abilities.
...@@ -108,6 +123,7 @@ pub const File = struct {...@@ -108,6 +123,7 @@ pub const File = struct {
108 pub fn makeWritable(base: *File, dir: fs.Dir, sub_path: []const u8) !void {123 pub fn makeWritable(base: *File, dir: fs.Dir, sub_path: []const u8) !void {
109 try switch (base.tag) {124 try switch (base.tag) {
110 .Elf => @fieldParentPtr(Elf, "base", base).makeWritable(dir, sub_path),125 .Elf => @fieldParentPtr(Elf, "base", base).makeWritable(dir, sub_path),
126 .C => @fieldParentPtr(C, "base", base).makeWritable(dir, sub_path),
111 else => unreachable,127 else => unreachable,
112 };128 };
113 }129 }
...@@ -122,6 +138,7 @@ pub const File = struct {...@@ -122,6 +138,7 @@ pub const File = struct {
122 pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void {138 pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void {
123 try switch (base.tag) {139 try switch (base.tag) {
124 .Elf => @fieldParentPtr(Elf, "base", base).updateDecl(module, decl),140 .Elf => @fieldParentPtr(Elf, "base", base).updateDecl(module, decl),
141 .C => @fieldParentPtr(C, "base", base).updateDecl(module, decl),
125 else => unreachable,142 else => unreachable,
126 };143 };
127 }144 }
...@@ -129,6 +146,9 @@ pub const File = struct {...@@ -129,6 +146,9 @@ pub const File = struct {
129 pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void {146 pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void {
130 try switch (base.tag) {147 try switch (base.tag) {
131 .Elf => @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),148 .Elf => @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),
149 .C => {
150 //TODO
151 },
132 else => unreachable,152 else => unreachable,
133 };153 };
134 }154 }
...@@ -136,6 +156,7 @@ pub const File = struct {...@@ -136,6 +156,7 @@ pub const File = struct {
136 pub fn deinit(base: *File) void {156 pub fn deinit(base: *File) void {
137 switch (base.tag) {157 switch (base.tag) {
138 .Elf => @fieldParentPtr(Elf, "base", base).deinit(),158 .Elf => @fieldParentPtr(Elf, "base", base).deinit(),
159 .C => @fieldParentPtr(C, "base", base).deinit(),
139 else => unreachable,160 else => unreachable,
140 }161 }
141 }162 }
...@@ -143,6 +164,9 @@ pub const File = struct {...@@ -143,6 +164,9 @@ pub const File = struct {
143 pub fn flush(base: *File) !void {164 pub fn flush(base: *File) !void {
144 try switch (base.tag) {165 try switch (base.tag) {
145 .Elf => @fieldParentPtr(Elf, "base", base).flush(),166 .Elf => @fieldParentPtr(Elf, "base", base).flush(),
167 .C => {
168 //TODO
169 },
146 else => unreachable,170 else => unreachable,
147 };171 };
148 }172 }
...@@ -157,6 +181,7 @@ pub const File = struct {...@@ -157,6 +181,7 @@ pub const File = struct {
157 pub fn errorFlags(base: *File) ErrorFlags {181 pub fn errorFlags(base: *File) ErrorFlags {
158 return switch (base.tag) {182 return switch (base.tag) {
159 .Elf => @fieldParentPtr(Elf, "base", base).error_flags,183 .Elf => @fieldParentPtr(Elf, "base", base).error_flags,
184 .C => return .{ .no_entry_point_found = false },
160 else => unreachable,185 else => unreachable,
161 };186 };
162 }187 }
...@@ -176,6 +201,38 @@ pub const File = struct {...@@ -176,6 +201,38 @@ pub const File = struct {
176 pub const ErrorFlags = struct {201 pub const ErrorFlags = struct {
177 no_entry_point_found: bool = false,202 no_entry_point_found: bool = false,
178 };203 };
204
205 pub const C = struct {
206 pub const base_tag: Tag = .C;
207 base: File = File{ .tag = base_tag },
208
209 allocator: *Allocator,
210 file: ?fs.File,
211 owns_file_handle: bool,
212 options: Options,
213
214 pub fn makeWritable(self: *File.C, dir: fs.Dir, sub_path: []const u8) !void {
215 assert(self.owns_file_handle);
216 if (self.file != null) return;
217 self.file = try dir.createFile(sub_path, .{
218 .truncate = false,
219 .read = true,
220 .mode = determineMode(self.options),
221 });
222 }
223
224 pub fn deinit(self: *File.C) void {
225 if (self.owns_file_handle) {
226 if (self.file) |f|
227 f.close();
228 }
229 }
230
231 pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void {
232 return error.Unimplemented;
233 }
234 };
235
179 pub const Elf = struct {236 pub const Elf = struct {
180 pub const base_tag: Tag = .Elf;237 pub const base_tag: Tag = .Elf;
181 base: File = File{ .tag = base_tag },238 base: File = File{ .tag = base_tag },
src-self-hosted/test.zig+50-27
...@@ -464,33 +464,54 @@ pub const TestContext = struct {...@@ -464,33 +464,54 @@ pub const TestContext = struct {
464464
465 switch (update.case) {465 switch (update.case) {
466 .Transformation => |expected_output| {466 .Transformation => |expected_output| {
467 update_node.estimated_total_items = 5;467 var label: []const u8 = "ZIR";
468 var emit_node = update_node.start("emit", null);468 if (case.c_standard) |cstd| {
469 emit_node.activate();469 label = @tagName(cstd);
470 var new_zir_module = try zir.emit(allocator, module);470 var c: *link.File.C = module.bin_file.cast(link.File.C).?;
471 defer new_zir_module.deinit(allocator);471 var out = c.file.?.reader().readAllAlloc(allocator, 1024 * 1024) catch @panic("Unable to read C output!");
472 emit_node.end();472 defer allocator.free(out);
473473
474 var write_node = update_node.start("write", null);474 if (expected_output.len != out.len) {
475 write_node.activate();475 std.debug.warn("{}\nTransformed {} length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, label, expected_output, out });
476 var out_zir = std.ArrayList(u8).init(allocator);476 std.process.exit(1);
477 defer out_zir.deinit();477 }
478 try new_zir_module.writeToStream(allocator, out_zir.outStream());478 for (expected_output) |e, i| {
479 write_node.end();479 if (out[i] != e) {
480480 if (expected_output.len != out.len) {
481 var test_node = update_node.start("assert", null);481 std.debug.warn("{}\nTransformed {} differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, label, expected_output, out });
482 test_node.activate();482 std.process.exit(1);
483 defer test_node.end();483 }
484 const label = if (case.c_standard) |_| "C" else "ZIR";484 }
485 if (expected_output.len != out_zir.items.len) {485 }
486 std.debug.warn("{}\nTransformed {} length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, label, expected_output, out_zir.items });486 } else {
487 std.process.exit(1);487 update_node.estimated_total_items = 5;
488 }488 var emit_node = update_node.start("emit", null);
489 for (expected_output) |e, i| {489 emit_node.activate();
490 if (out_zir.items[i] != e) {490 var new_zir_module = try zir.emit(allocator, module);
491 if (expected_output.len != out_zir.items.len) {491 defer new_zir_module.deinit(allocator);
492 std.debug.warn("{}\nTransformed {} differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, label, expected_output, out_zir.items });492 emit_node.end();
493 std.process.exit(1);493
494 var write_node = update_node.start("write", null);
495 write_node.activate();
496 var out_zir = std.ArrayList(u8).init(allocator);
497 defer out_zir.deinit();
498 try new_zir_module.writeToStream(allocator, out_zir.outStream());
499 write_node.end();
500
501 var test_node = update_node.start("assert", null);
502 test_node.activate();
503 defer test_node.end();
504
505 if (expected_output.len != out_zir.items.len) {
506 std.debug.warn("{}\nTransformed {} length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, label, expected_output, out_zir.items });
507 std.process.exit(1);
508 }
509 for (expected_output) |e, i| {
510 if (out_zir.items[i] != e) {
511 if (expected_output.len != out_zir.items.len) {
512 std.debug.warn("{}\nTransformed {} differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, label, expected_output, out_zir.items });
513 std.process.exit(1);
514 }
494 }515 }
495 }516 }
496 }517 }
...@@ -527,6 +548,8 @@ pub const TestContext = struct {...@@ -527,6 +548,8 @@ pub const TestContext = struct {
527 }548 }
528 },549 },
529 .Execution => |expected_stdout| {550 .Execution => |expected_stdout| {
551 std.debug.assert(case.c_standard == null);
552
530 update_node.estimated_total_items = 4;553 update_node.estimated_total_items = 4;
531 var exec_result = x: {554 var exec_result = x: {
532 var exec_node = update_node.start("execute", null);555 var exec_node = update_node.start("execute", null);
test/stage2/cbe.zig+6-6
...@@ -9,10 +9,10 @@ const linux_x64 = std.zig.CrossTarget{...@@ -9,10 +9,10 @@ const linux_x64 = std.zig.CrossTarget{
9};9};
1010
11pub fn addCases(ctx: *TestContext) !void {11pub fn addCases(ctx: *TestContext) !void {
12 // // These tests should work on every platform12 // These tests should work on every platform
13 // ctx.c11("empty start function", linux_x64,13 ctx.c11("empty start function", linux_x64,
14 // \\export fn start() void {}14 \\export fn start() void {}
15 // ,15 ,
16 // \\void start(void) {}16 \\void start(void) {}
17 // );17 );
18}18}