From a17200dab1b0b373e85c6c2cc266078012a81948 Mon Sep 17 00:00:00 2001 From: Noam Preil Date: Tue, 7 Jul 2020 16:40:14 -0400 Subject: [PATCH] CBE skeleton --- src-self-hosted/link.zig | 59 +++++++++++++++++++++++++++++++- src-self-hosted/test.zig | 73 ++++++++++++++++++++++++++-------------- test/stage2/cbe.zig | 12 +++---- 3 files changed, 112 insertions(+), 32 deletions(-) diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index 9e273a2b9e..e37f567d92 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -38,7 +38,11 @@ pub fn openBinFilePath( errdefer file.close(); if (options.c_standard) |cstd| { - return error.Unimplemented; + var bin_file = try allocator.create(File.C); + errdefer allocator.destroy(bin_file); + bin_file.* = try openCFile(allocator, file, options); + bin_file.owns_file_handle = true; + return &bin_file.base; } else { var bin_file = try allocator.create(File.Elf); errdefer allocator.destroy(bin_file); @@ -82,6 +86,17 @@ pub fn writeFilePath( return result; } +pub fn openCFile(allocator: *Allocator, file: fs.File, options: Options) !File.C { + var self: File.C = .{ + .allocator = allocator, + .file = file, + .options = options, + .owns_file_handle = false, + }; + errdefer self.deinit(); + return self; +} + /// Attempts incremental linking, if the file already exists. /// If incremental linking fails, falls back to truncating the file and rewriting it. /// Returns an error if `file` is not already open with +read +write +seek abilities. @@ -108,6 +123,7 @@ pub const File = struct { pub fn makeWritable(base: *File, dir: fs.Dir, sub_path: []const u8) !void { try switch (base.tag) { .Elf => @fieldParentPtr(Elf, "base", base).makeWritable(dir, sub_path), + .C => @fieldParentPtr(C, "base", base).makeWritable(dir, sub_path), else => unreachable, }; } @@ -122,6 +138,7 @@ pub const File = struct { pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void { try switch (base.tag) { .Elf => @fieldParentPtr(Elf, "base", base).updateDecl(module, decl), + .C => @fieldParentPtr(C, "base", base).updateDecl(module, decl), else => unreachable, }; } @@ -129,6 +146,9 @@ pub const File = struct { pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void { try switch (base.tag) { .Elf => @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl), + .C => { + //TODO + }, else => unreachable, }; } @@ -136,6 +156,7 @@ pub const File = struct { pub fn deinit(base: *File) void { switch (base.tag) { .Elf => @fieldParentPtr(Elf, "base", base).deinit(), + .C => @fieldParentPtr(C, "base", base).deinit(), else => unreachable, } } @@ -143,6 +164,9 @@ pub const File = struct { pub fn flush(base: *File) !void { try switch (base.tag) { .Elf => @fieldParentPtr(Elf, "base", base).flush(), + .C => { + //TODO + }, else => unreachable, }; } @@ -157,6 +181,7 @@ pub const File = struct { pub fn errorFlags(base: *File) ErrorFlags { return switch (base.tag) { .Elf => @fieldParentPtr(Elf, "base", base).error_flags, + .C => return .{ .no_entry_point_found = false }, else => unreachable, }; } @@ -176,6 +201,38 @@ pub const File = struct { pub const ErrorFlags = struct { no_entry_point_found: bool = false, }; + + pub const C = struct { + pub const base_tag: Tag = .C; + base: File = File{ .tag = base_tag }, + + allocator: *Allocator, + file: ?fs.File, + owns_file_handle: bool, + options: Options, + + pub fn makeWritable(self: *File.C, dir: fs.Dir, sub_path: []const u8) !void { + assert(self.owns_file_handle); + if (self.file != null) return; + self.file = try dir.createFile(sub_path, .{ + .truncate = false, + .read = true, + .mode = determineMode(self.options), + }); + } + + pub fn deinit(self: *File.C) void { + if (self.owns_file_handle) { + if (self.file) |f| + f.close(); + } + } + + pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void { + return error.Unimplemented; + } + }; + pub const Elf = struct { pub const base_tag: Tag = .Elf; base: File = File{ .tag = base_tag }, diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig index a1dd659e75..ce20c172cf 100644 --- a/src-self-hosted/test.zig +++ b/src-self-hosted/test.zig @@ -464,33 +464,54 @@ pub const TestContext = struct { switch (update.case) { .Transformation => |expected_output| { - update_node.estimated_total_items = 5; - var emit_node = update_node.start("emit", null); - emit_node.activate(); - var new_zir_module = try zir.emit(allocator, module); - defer new_zir_module.deinit(allocator); - emit_node.end(); + var label: []const u8 = "ZIR"; + if (case.c_standard) |cstd| { + label = @tagName(cstd); + var c: *link.File.C = module.bin_file.cast(link.File.C).?; + var out = c.file.?.reader().readAllAlloc(allocator, 1024 * 1024) catch @panic("Unable to read C output!"); + defer allocator.free(out); - var write_node = update_node.start("write", null); - write_node.activate(); - var out_zir = std.ArrayList(u8).init(allocator); - defer out_zir.deinit(); - try new_zir_module.writeToStream(allocator, out_zir.outStream()); - write_node.end(); + if (expected_output.len != out.len) { + std.debug.warn("{}\nTransformed {} length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, label, expected_output, out }); + std.process.exit(1); + } + for (expected_output) |e, i| { + if (out[i] != e) { + if (expected_output.len != out.len) { + std.debug.warn("{}\nTransformed {} differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, label, expected_output, out }); + std.process.exit(1); + } + } + } + } else { + update_node.estimated_total_items = 5; + var emit_node = update_node.start("emit", null); + emit_node.activate(); + var new_zir_module = try zir.emit(allocator, module); + defer new_zir_module.deinit(allocator); + emit_node.end(); - var test_node = update_node.start("assert", null); - test_node.activate(); - defer test_node.end(); - const label = if (case.c_standard) |_| "C" else "ZIR"; - if (expected_output.len != out_zir.items.len) { - 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 }); - std.process.exit(1); - } - for (expected_output) |e, i| { - if (out_zir.items[i] != e) { - if (expected_output.len != out_zir.items.len) { - 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 }); - std.process.exit(1); + var write_node = update_node.start("write", null); + write_node.activate(); + var out_zir = std.ArrayList(u8).init(allocator); + defer out_zir.deinit(); + try new_zir_module.writeToStream(allocator, out_zir.outStream()); + write_node.end(); + + var test_node = update_node.start("assert", null); + test_node.activate(); + defer test_node.end(); + + if (expected_output.len != out_zir.items.len) { + 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 }); + std.process.exit(1); + } + for (expected_output) |e, i| { + if (out_zir.items[i] != e) { + if (expected_output.len != out_zir.items.len) { + 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 }); + std.process.exit(1); + } } } } @@ -527,6 +548,8 @@ pub const TestContext = struct { } }, .Execution => |expected_stdout| { + std.debug.assert(case.c_standard == null); + update_node.estimated_total_items = 4; var exec_result = x: { var exec_node = update_node.start("execute", null); diff --git a/test/stage2/cbe.zig b/test/stage2/cbe.zig index 884f5c927f..a599367aec 100644 --- a/test/stage2/cbe.zig +++ b/test/stage2/cbe.zig @@ -9,10 +9,10 @@ const linux_x64 = std.zig.CrossTarget{ }; pub fn addCases(ctx: *TestContext) !void { - // // These tests should work on every platform - // ctx.c11("empty start function", linux_x64, - // \\export fn start() void {} - // , - // \\void start(void) {} - // ); + // These tests should work on every platform + ctx.c11("empty start function", linux_x64, + \\export fn start() void {} + , + \\void start(void) {} + ); }