| author | |
| committer | |
| log | a17200dab1b0b373e85c6c2cc266078012a81948 |
| tree | 320be8b1150cd3396d3e428d463fdbbb6836de78 |
| parent | b4c571301be7dd2174b2d067d643a2a093797e7e |
| signature | Commit is signed but in an unrecognized format. |
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(); |
| 39 | 39 | ||
| 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 | } |
| 84 | 88 | ||
| 89 | pub 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 { |
| 464 | 464 | ||
| 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); |
| 473 | 473 | ||
| 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) { |
| 480 | 480 | 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 | }; |
| 10 | 10 | ||
| 11 | pub fn addCases(ctx: *TestContext) !void { | 11 | pub fn addCases(ctx: *TestContext) !void { |
| 12 | // // These tests should work on every platform | 12 | // 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 | } |