authorgravatar for noam@pixelhero.devNoam Preil <noam@pixelhero.dev> 2020-07-07 22:57:34-04:00
committergravatar for noam@pixelhero.devNoam Preil <noam@pixelhero.dev> 2020-07-07 22:57:34-04:00
logb91cf1597267275dbbf57551acbe0461216ff08e
tree1452ddff902d80e49c3d88766fe8ee681ef9fea6
parent5461c482d0643abd83ac834be0a95da066c53c69
signature Commit is signed but in an unrecognized format.

CBE: Move standards determination to generated code


7 files changed, 57 insertions(+), 60 deletions(-)

src-self-hosted/Module.zig+2-8
......@@ -722,12 +722,6 @@ pub const AllErrors = struct {
722722 }
723723};
724724
725pub const CStandard = enum {
726 C99,
727 GNU99,
728 C11,
729};
730
731725pub const InitOptions = struct {
732726 target: std.Target,
733727 root_pkg: *Package,
......@@ -738,7 +732,7 @@ pub const InitOptions = struct {
738732 object_format: ?std.builtin.ObjectFormat = null,
739733 optimize_mode: std.builtin.Mode = .Debug,
740734 keep_source_files_loaded: bool = false,
741 c_standard: ?CStandard = null,
735 cbe: bool = false,
742736};
743737
744738pub fn init(gpa: *Allocator, options: InitOptions) !Module {
......@@ -748,7 +742,7 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
748742 .output_mode = options.output_mode,
749743 .link_mode = options.link_mode orelse .Static,
750744 .object_format = options.object_format orelse options.target.getObjectFormat(),
751 .c_standard = options.c_standard,
745 .cbe = options.cbe,
752746 });
753747 errdefer bin_file.*.deinit();
754748
src-self-hosted/cbe.h created+8
......@@ -0,0 +1,8 @@
1#if __STDC_VERSION__ >= 201112L
2#define noreturn _Noreturn
3#elif !__STRICT_ANSI__
4#define noreturn __attribute__ ((noreturn))
5#else
6#define noreturn
7#endif
8
src-self-hosted/cgen.zig+6-3
......@@ -7,7 +7,6 @@ const std = @import("std");
77
88const C = link.File.C;
99const Decl = Module.Decl;
10const CStandard = Module.CStandard;
1110const mem = std.mem;
1211
1312/// Maps a name from Zig source to C. This will always give the same output for
......@@ -22,7 +21,10 @@ fn renderType(file: *C, writer: std.ArrayList(u8).Writer, T: Type) !void {
2221 try writer.writeAll("size_t");
2322 } else {
2423 switch (T.zigTypeTag()) {
25 .NoReturn => try writer.writeAll("_Noreturn void"),
24 .NoReturn => {
25 file.need_noreturn = true;
26 try writer.writeAll("noreturn void");
27 },
2628 .Void => try writer.writeAll("void"),
2729 else => return error.Unimplemented,
2830 }
......@@ -41,13 +43,14 @@ fn renderFunctionSignature(file: *C, writer: std.ArrayList(u8).Writer, decl: *De
4143 }
4244}
4345
44pub fn generate(file: *C, decl: *Decl, standard: CStandard) !void {
46pub fn generate(file: *C, decl: *Decl) !void {
4547 const writer = file.main.writer();
4648 const header = file.header.writer();
4749 const tv = decl.typed_value.most_recent.typed_value;
4850 switch (tv.ty.zigTypeTag()) {
4951 .Fn => {
5052 try renderFunctionSignature(file, writer, decl);
53
5154 try writer.writeAll(" {");
5255
5356 const func: *Module.Fn = tv.val.cast(Value.Payload.Function).?.func;
src-self-hosted/link.zig+5-3
......@@ -22,7 +22,7 @@ pub const Options = struct {
2222 /// Used for calculating how much space to reserve for executable program code in case
2323 /// the binary file deos not already have such a section.
2424 program_code_size_hint: u64 = 256 * 1024,
25 c_standard: ?Module.CStandard = null,
25 cbe: bool = false,
2626};
2727
2828/// Attempts incremental linking, if the file already exists.
......@@ -38,7 +38,7 @@ pub fn openBinFilePath(
3838 const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(options) });
3939 errdefer file.close();
4040
41 if (options.c_standard) |cstd| {
41 if (options.cbe) {
4242 var bin_file = try allocator.create(File.C);
4343 errdefer allocator.destroy(bin_file);
4444 bin_file.* = try openCFile(allocator, file, options);
......@@ -217,6 +217,7 @@ pub const File = struct {
217217 called: std.StringHashMap(void),
218218 need_stddef: bool = false,
219219 need_stdint: bool = false,
220 need_noreturn: bool = false,
220221
221222 pub fn makeWritable(self: *File.C, dir: fs.Dir, sub_path: []const u8) !void {
222223 assert(self.owns_file_handle);
......@@ -239,11 +240,12 @@ pub const File = struct {
239240 }
240241
241242 pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void {
242 try cgen.generate(self, decl, self.options.c_standard.?);
243 try cgen.generate(self, decl);
243244 }
244245
245246 pub fn flush(self: *File.C) !void {
246247 const writer = self.file.?.writer();
248 try writer.writeAll(@embedFile("cbe.h"));
247249 var includes = false;
248250 if (self.need_stddef) {
249251 try writer.writeAll("#include <stddef.h>\n");
src-self-hosted/main.zig+5-15
......@@ -191,7 +191,7 @@ fn buildOutputType(
191191 var emit_zir: Emit = .no;
192192 var target_arch_os_abi: []const u8 = "native";
193193 var target_mcpu: ?[]const u8 = null;
194 var target_c_standard: ?Module.CStandard = null;
194 var cbe: bool = false;
195195 var target_dynamic_linker: ?[]const u8 = null;
196196
197197 var system_libs = std.ArrayList([]const u8).init(gpa);
......@@ -279,18 +279,8 @@ fn buildOutputType(
279279 }
280280 i += 1;
281281 target_mcpu = args[i];
282 } else if (mem.eql(u8, arg, "--c-standard")) {
283 if (i + 1 >= args.len) {
284 std.debug.print("expected parameter after --c-standard\n", .{});
285 process.exit(1);
286 }
287 i += 1;
288 if (std.meta.stringToEnum(Module.CStandard, args[i])) |cstd| {
289 target_c_standard = cstd;
290 } else {
291 std.debug.print("Invalid C standard: {}\n", .{args[i]});
292 process.exit(1);
293 }
282 } else if (mem.eql(u8, arg, "--c")) {
283 cbe = true;
294284 } else if (mem.startsWith(u8, arg, "-mcpu=")) {
295285 target_mcpu = arg["-mcpu=".len..];
296286 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
......@@ -374,7 +364,7 @@ fn buildOutputType(
374364 }
375365 }
376366
377 if (target_c_standard != null and output_mode != .Obj) {
367 if (cbe and output_mode != .Obj) {
378368 std.debug.print("The C backend must be used with build-obj\n", .{});
379369 process.exit(1);
380370 }
......@@ -479,7 +469,7 @@ fn buildOutputType(
479469 .object_format = object_format,
480470 .optimize_mode = build_mode,
481471 .keep_source_files_loaded = zir_out_path != null,
482 .c_standard = target_c_standard,
472 .cbe = cbe,
483473 });
484474 defer module.deinit();
485475
src-self-hosted/test.zig+21-21
......@@ -5,6 +5,8 @@ const Allocator = std.mem.Allocator;
55const zir = @import("zir.zig");
66const Package = @import("Package.zig");
77
8const cheader = @embedFile("cbe.h");
9
810test "self-hosted" {
911 var ctx = TestContext.init();
1012 defer ctx.deinit();
......@@ -68,7 +70,7 @@ pub const TestContext = struct {
6870 output_mode: std.builtin.OutputMode,
6971 updates: std.ArrayList(Update),
7072 extension: TestType,
71 c_standard: ?Module.CStandard = null,
73 cbe: bool = false,
7274
7375 /// Adds a subcase in which the module is updated with `src`, and the
7476 /// resulting ZIR is validated against `result`.
......@@ -188,20 +190,20 @@ pub const TestContext = struct {
188190 return ctx.addObj(name, target, .ZIR);
189191 }
190192
191 pub fn addC(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget, T: TestType, standard: Module.CStandard) *Case {
193 pub fn addC(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget, T: TestType) *Case {
192194 ctx.cases.append(Case{
193195 .name = name,
194196 .target = target,
195197 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
196198 .output_mode = .Obj,
197199 .extension = T,
198 .c_standard = standard,
200 .cbe = true,
199201 }) catch unreachable;
200202 return &ctx.cases.items[ctx.cases.items.len - 1];
201203 }
202204
203 pub fn c11(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget, src: [:0]const u8, c: [:0]const u8) void {
204 ctx.addC(name, target, .Zig, .C11).addTransform(src, c);
205 pub fn c(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {
206 ctx.addC(name, target, .Zig).addTransform(src, cheader ++ out);
205207 }
206208
207209 pub fn addCompareOutput(
......@@ -382,13 +384,13 @@ pub const TestContext = struct {
382384 }
383385
384386 fn deinit(self: *TestContext) void {
385 for (self.cases.items) |c| {
386 for (c.updates.items) |u| {
387 for (self.cases.items) |case| {
388 for (case.updates.items) |u| {
387389 if (u.case == .Error) {
388 c.updates.allocator.free(u.case.Error);
390 case.updates.allocator.free(u.case.Error);
389391 }
390392 }
391 c.updates.deinit();
393 case.updates.deinit();
392394 }
393395 self.cases.deinit();
394396 self.* = undefined;
......@@ -442,7 +444,7 @@ pub const TestContext = struct {
442444 .bin_file_path = bin_name,
443445 .root_pkg = root_pkg,
444446 .keep_source_files_loaded = true,
445 .c_standard = case.c_standard,
447 .cbe = case.cbe,
446448 });
447449 defer module.deinit();
448450
......@@ -477,24 +479,22 @@ pub const TestContext = struct {
477479
478480 switch (update.case) {
479481 .Transformation => |expected_output| {
480 var label: []const u8 = "ZIR";
481 if (case.c_standard) |cstd| {
482 label = @tagName(cstd);
483 var c: *link.File.C = module.bin_file.cast(link.File.C).?;
484 c.file.?.close();
485 c.file = null;
482 if (case.cbe) {
483 var cfile: *link.File.C = module.bin_file.cast(link.File.C).?;
484 cfile.file.?.close();
485 cfile.file = null;
486486 var file = try tmp.dir.openFile(bin_name, .{ .read = true });
487487 defer file.close();
488488 var out = file.reader().readAllAlloc(allocator, 1024 * 1024) catch @panic("Unable to read C output!");
489489 defer allocator.free(out);
490490
491491 if (expected_output.len != out.len) {
492 std.debug.warn("\nTransformed {} length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ label, expected_output, out });
492 std.debug.warn("\nTransformed C length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ expected_output, out });
493493 std.process.exit(1);
494494 }
495495 for (expected_output) |e, i| {
496496 if (out[i] != e) {
497 std.debug.warn("\nTransformed {} differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ label, expected_output, out });
497 std.debug.warn("\nTransformed C differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ expected_output, out });
498498 std.process.exit(1);
499499 }
500500 }
......@@ -518,12 +518,12 @@ pub const TestContext = struct {
518518 defer test_node.end();
519519
520520 if (expected_output.len != out_zir.items.len) {
521 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 });
521 std.debug.warn("{}\nTransformed ZIR length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, expected_output, out_zir.items });
522522 std.process.exit(1);
523523 }
524524 for (expected_output) |e, i| {
525525 if (out_zir.items[i] != e) {
526 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 });
526 std.debug.warn("{}\nTransformed ZIR differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, expected_output, out_zir.items });
527527 std.process.exit(1);
528528 }
529529 }
......@@ -561,7 +561,7 @@ pub const TestContext = struct {
561561 }
562562 },
563563 .Execution => |expected_stdout| {
564 std.debug.assert(case.c_standard == null);
564 std.debug.assert(!case.cbe);
565565
566566 update_node.estimated_total_items = 4;
567567 var exec_result = x: {
test/stage2/cbe.zig+10-10
......@@ -9,30 +9,30 @@ const linux_x64 = std.zig.CrossTarget{
99};
1010
1111pub fn addCases(ctx: *TestContext) !void {
12 ctx.c11("empty start function", linux_x64,
12 ctx.c("empty start function", linux_x64,
1313 \\export fn _start() noreturn {}
1414 ,
15 \\_Noreturn void _start(void) {}
15 \\noreturn void _start(void) {}
1616 \\
1717 );
18 ctx.c11("less empty start function", linux_x64,
18 ctx.c("less empty start function", linux_x64,
1919 \\fn main() noreturn {}
2020 \\
2121 \\export fn _start() noreturn {
2222 \\ main();
2323 \\}
2424 ,
25 \\_Noreturn void main(void);
25 \\noreturn void main(void);
2626 \\
27 \\_Noreturn void _start(void) {
27 \\noreturn void _start(void) {
2828 \\ main();
2929 \\}
3030 \\
31 \\_Noreturn void main(void) {}
31 \\noreturn void main(void) {}
3232 \\
3333 );
3434 // TODO: implement return values
35 ctx.c11("inline asm", linux_x64,
35 ctx.c("inline asm", linux_x64,
3636 \\fn exitGood() void {
3737 \\ asm volatile ("syscall"
3838 \\ :
......@@ -49,7 +49,7 @@ pub fn addCases(ctx: *TestContext) !void {
4949 \\
5050 \\void exitGood(void);
5151 \\
52 \\_Noreturn void _start(void) {
52 \\noreturn void _start(void) {
5353 \\ exitGood();
5454 \\}
5555 \\
......@@ -60,7 +60,7 @@ pub fn addCases(ctx: *TestContext) !void {
6060 \\}
6161 \\
6262 );
63 //ctx.c11("basic return", linux_x64,
63 //ctx.c("basic return", linux_x64,
6464 // \\fn main() u8 {
6565 // \\ return 103;
6666 // \\}
......@@ -73,7 +73,7 @@ pub fn addCases(ctx: *TestContext) !void {
7373 // \\
7474 // \\uint8_t main(void);
7575 // \\
76 // \\_Noreturn void _start(void) {
76 // \\noreturn void _start(void) {
7777 // \\ (void)main();
7878 // \\}
7979 // \\