Commit a17200dab1

Noam Preil <pleasantatk@gmail.com>
2020-07-07 22:40:14
CBE skeleton
1 parent b4c5713
Changed files (3)
src-self-hosted
test
stage2
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 },
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 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();
-                    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 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);
+
+                        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 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);
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) {}
+    );
 }