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
signaturelock-open 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 {...@@ -722,12 +722,6 @@ pub const AllErrors = struct {
722 }722 }
723};723};
724724
725pub const CStandard = enum {
726 C99,
727 GNU99,
728 C11,
729};
730
731pub const InitOptions = struct {725pub const InitOptions = struct {
732 target: std.Target,726 target: std.Target,
733 root_pkg: *Package,727 root_pkg: *Package,
...@@ -738,7 +732,7 @@ pub const InitOptions = struct {...@@ -738,7 +732,7 @@ pub const InitOptions = struct {
738 object_format: ?std.builtin.ObjectFormat = null,732 object_format: ?std.builtin.ObjectFormat = null,
739 optimize_mode: std.builtin.Mode = .Debug,733 optimize_mode: std.builtin.Mode = .Debug,
740 keep_source_files_loaded: bool = false,734 keep_source_files_loaded: bool = false,
741 c_standard: ?CStandard = null,735 cbe: bool = false,
742};736};
743737
744pub fn init(gpa: *Allocator, options: InitOptions) !Module {738pub fn init(gpa: *Allocator, options: InitOptions) !Module {
...@@ -748,7 +742,7 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {...@@ -748,7 +742,7 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
748 .output_mode = options.output_mode,742 .output_mode = options.output_mode,
749 .link_mode = options.link_mode orelse .Static,743 .link_mode = options.link_mode orelse .Static,
750 .object_format = options.object_format orelse options.target.getObjectFormat(),744 .object_format = options.object_format orelse options.target.getObjectFormat(),
751 .c_standard = options.c_standard,745 .cbe = options.cbe,
752 });746 });
753 errdefer bin_file.*.deinit();747 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");...@@ -7,7 +7,6 @@ const std = @import("std");
77
8const C = link.File.C;8const C = link.File.C;
9const Decl = Module.Decl;9const Decl = Module.Decl;
10const CStandard = Module.CStandard;
11const mem = std.mem;10const mem = std.mem;
1211
13/// Maps a name from Zig source to C. This will always give the same output for12/// 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 {...@@ -22,7 +21,10 @@ fn renderType(file: *C, writer: std.ArrayList(u8).Writer, T: Type) !void {
22 try writer.writeAll("size_t");21 try writer.writeAll("size_t");
23 } else {22 } else {
24 switch (T.zigTypeTag()) {23 switch (T.zigTypeTag()) {
25 .NoReturn => try writer.writeAll("_Noreturn void"),24 .NoReturn => {
25 file.need_noreturn = true;
26 try writer.writeAll("noreturn void");
27 },
26 .Void => try writer.writeAll("void"),28 .Void => try writer.writeAll("void"),
27 else => return error.Unimplemented,29 else => return error.Unimplemented,
28 }30 }
...@@ -41,13 +43,14 @@ fn renderFunctionSignature(file: *C, writer: std.ArrayList(u8).Writer, decl: *De...@@ -41,13 +43,14 @@ fn renderFunctionSignature(file: *C, writer: std.ArrayList(u8).Writer, decl: *De
41 }43 }
42}44}
4345
44pub fn generate(file: *C, decl: *Decl, standard: CStandard) !void {46pub fn generate(file: *C, decl: *Decl) !void {
45 const writer = file.main.writer();47 const writer = file.main.writer();
46 const header = file.header.writer();48 const header = file.header.writer();
47 const tv = decl.typed_value.most_recent.typed_value;49 const tv = decl.typed_value.most_recent.typed_value;
48 switch (tv.ty.zigTypeTag()) {50 switch (tv.ty.zigTypeTag()) {
49 .Fn => {51 .Fn => {
50 try renderFunctionSignature(file, writer, decl);52 try renderFunctionSignature(file, writer, decl);
53
51 try writer.writeAll(" {");54 try writer.writeAll(" {");
5255
53 const func: *Module.Fn = tv.val.cast(Value.Payload.Function).?.func;56 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 {...@@ -22,7 +22,7 @@ pub const Options = struct {
22 /// Used for calculating how much space to reserve for executable program code in case22 /// Used for calculating how much space to reserve for executable program code in case
23 /// the binary file deos not already have such a section.23 /// the binary file deos not already have such a section.
24 program_code_size_hint: u64 = 256 * 1024,24 program_code_size_hint: u64 = 256 * 1024,
25 c_standard: ?Module.CStandard = null,25 cbe: bool = false,
26};26};
2727
28/// Attempts incremental linking, if the file already exists.28/// Attempts incremental linking, if the file already exists.
...@@ -38,7 +38,7 @@ pub fn openBinFilePath(...@@ -38,7 +38,7 @@ pub fn openBinFilePath(
38 const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(options) });38 const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(options) });
39 errdefer file.close();39 errdefer file.close();
4040
41 if (options.c_standard) |cstd| {41 if (options.cbe) {
42 var bin_file = try allocator.create(File.C);42 var bin_file = try allocator.create(File.C);
43 errdefer allocator.destroy(bin_file);43 errdefer allocator.destroy(bin_file);
44 bin_file.* = try openCFile(allocator, file, options);44 bin_file.* = try openCFile(allocator, file, options);
...@@ -217,6 +217,7 @@ pub const File = struct {...@@ -217,6 +217,7 @@ pub const File = struct {
217 called: std.StringHashMap(void),217 called: std.StringHashMap(void),
218 need_stddef: bool = false,218 need_stddef: bool = false,
219 need_stdint: bool = false,219 need_stdint: bool = false,
220 need_noreturn: bool = false,
220221
221 pub fn makeWritable(self: *File.C, dir: fs.Dir, sub_path: []const u8) !void {222 pub fn makeWritable(self: *File.C, dir: fs.Dir, sub_path: []const u8) !void {
222 assert(self.owns_file_handle);223 assert(self.owns_file_handle);
...@@ -239,11 +240,12 @@ pub const File = struct {...@@ -239,11 +240,12 @@ pub const File = struct {
239 }240 }
240241
241 pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void {242 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);
243 }244 }
244245
245 pub fn flush(self: *File.C) !void {246 pub fn flush(self: *File.C) !void {
246 const writer = self.file.?.writer();247 const writer = self.file.?.writer();
248 try writer.writeAll(@embedFile("cbe.h"));
247 var includes = false;249 var includes = false;
248 if (self.need_stddef) {250 if (self.need_stddef) {
249 try writer.writeAll("#include <stddef.h>\n");251 try writer.writeAll("#include <stddef.h>\n");
src-self-hosted/main.zig+5-15
...@@ -191,7 +191,7 @@ fn buildOutputType(...@@ -191,7 +191,7 @@ fn buildOutputType(
191 var emit_zir: Emit = .no;191 var emit_zir: Emit = .no;
192 var target_arch_os_abi: []const u8 = "native";192 var target_arch_os_abi: []const u8 = "native";
193 var target_mcpu: ?[]const u8 = null;193 var target_mcpu: ?[]const u8 = null;
194 var target_c_standard: ?Module.CStandard = null;194 var cbe: bool = false;
195 var target_dynamic_linker: ?[]const u8 = null;195 var target_dynamic_linker: ?[]const u8 = null;
196196
197 var system_libs = std.ArrayList([]const u8).init(gpa);197 var system_libs = std.ArrayList([]const u8).init(gpa);
...@@ -279,18 +279,8 @@ fn buildOutputType(...@@ -279,18 +279,8 @@ fn buildOutputType(
279 }279 }
280 i += 1;280 i += 1;
281 target_mcpu = args[i];281 target_mcpu = args[i];
282 } else if (mem.eql(u8, arg, "--c-standard")) {282 } else if (mem.eql(u8, arg, "--c")) {
283 if (i + 1 >= args.len) {283 cbe = true;
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 }
294 } else if (mem.startsWith(u8, arg, "-mcpu=")) {284 } else if (mem.startsWith(u8, arg, "-mcpu=")) {
295 target_mcpu = arg["-mcpu=".len..];285 target_mcpu = arg["-mcpu=".len..];
296 } else if (mem.eql(u8, arg, "--dynamic-linker")) {286 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
...@@ -374,7 +364,7 @@ fn buildOutputType(...@@ -374,7 +364,7 @@ fn buildOutputType(
374 }364 }
375 }365 }
376366
377 if (target_c_standard != null and output_mode != .Obj) {367 if (cbe and output_mode != .Obj) {
378 std.debug.print("The C backend must be used with build-obj\n", .{});368 std.debug.print("The C backend must be used with build-obj\n", .{});
379 process.exit(1);369 process.exit(1);
380 }370 }
...@@ -479,7 +469,7 @@ fn buildOutputType(...@@ -479,7 +469,7 @@ fn buildOutputType(
479 .object_format = object_format,469 .object_format = object_format,
480 .optimize_mode = build_mode,470 .optimize_mode = build_mode,
481 .keep_source_files_loaded = zir_out_path != null,471 .keep_source_files_loaded = zir_out_path != null,
482 .c_standard = target_c_standard,472 .cbe = cbe,
483 });473 });
484 defer module.deinit();474 defer module.deinit();
485475
src-self-hosted/test.zig+21-21
...@@ -5,6 +5,8 @@ const Allocator = std.mem.Allocator;...@@ -5,6 +5,8 @@ const Allocator = std.mem.Allocator;
5const zir = @import("zir.zig");5const zir = @import("zir.zig");
6const Package = @import("Package.zig");6const Package = @import("Package.zig");
77
8const cheader = @embedFile("cbe.h");
9
8test "self-hosted" {10test "self-hosted" {
9 var ctx = TestContext.init();11 var ctx = TestContext.init();
10 defer ctx.deinit();12 defer ctx.deinit();
...@@ -68,7 +70,7 @@ pub const TestContext = struct {...@@ -68,7 +70,7 @@ pub const TestContext = struct {
68 output_mode: std.builtin.OutputMode,70 output_mode: std.builtin.OutputMode,
69 updates: std.ArrayList(Update),71 updates: std.ArrayList(Update),
70 extension: TestType,72 extension: TestType,
71 c_standard: ?Module.CStandard = null,73 cbe: bool = false,
7274
73 /// Adds a subcase in which the module is updated with `src`, and the75 /// Adds a subcase in which the module is updated with `src`, and the
74 /// resulting ZIR is validated against `result`.76 /// resulting ZIR is validated against `result`.
...@@ -188,20 +190,20 @@ pub const TestContext = struct {...@@ -188,20 +190,20 @@ pub const TestContext = struct {
188 return ctx.addObj(name, target, .ZIR);190 return ctx.addObj(name, target, .ZIR);
189 }191 }
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 {
192 ctx.cases.append(Case{194 ctx.cases.append(Case{
193 .name = name,195 .name = name,
194 .target = target,196 .target = target,
195 .updates = std.ArrayList(Update).init(ctx.cases.allocator),197 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
196 .output_mode = .Obj,198 .output_mode = .Obj,
197 .extension = T,199 .extension = T,
198 .c_standard = standard,200 .cbe = true,
199 }) catch unreachable;201 }) catch unreachable;
200 return &ctx.cases.items[ctx.cases.items.len - 1];202 return &ctx.cases.items[ctx.cases.items.len - 1];
201 }203 }
202204
203 pub fn c11(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget, src: [:0]const u8, c: [:0]const u8) void {205 pub fn c(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {
204 ctx.addC(name, target, .Zig, .C11).addTransform(src, c);206 ctx.addC(name, target, .Zig).addTransform(src, cheader ++ out);
205 }207 }
206208
207 pub fn addCompareOutput(209 pub fn addCompareOutput(
...@@ -382,13 +384,13 @@ pub const TestContext = struct {...@@ -382,13 +384,13 @@ pub const TestContext = struct {
382 }384 }
383385
384 fn deinit(self: *TestContext) void {386 fn deinit(self: *TestContext) void {
385 for (self.cases.items) |c| {387 for (self.cases.items) |case| {
386 for (c.updates.items) |u| {388 for (case.updates.items) |u| {
387 if (u.case == .Error) {389 if (u.case == .Error) {
388 c.updates.allocator.free(u.case.Error);390 case.updates.allocator.free(u.case.Error);
389 }391 }
390 }392 }
391 c.updates.deinit();393 case.updates.deinit();
392 }394 }
393 self.cases.deinit();395 self.cases.deinit();
394 self.* = undefined;396 self.* = undefined;
...@@ -442,7 +444,7 @@ pub const TestContext = struct {...@@ -442,7 +444,7 @@ pub const TestContext = struct {
442 .bin_file_path = bin_name,444 .bin_file_path = bin_name,
443 .root_pkg = root_pkg,445 .root_pkg = root_pkg,
444 .keep_source_files_loaded = true,446 .keep_source_files_loaded = true,
445 .c_standard = case.c_standard,447 .cbe = case.cbe,
446 });448 });
447 defer module.deinit();449 defer module.deinit();
448450
...@@ -477,24 +479,22 @@ pub const TestContext = struct {...@@ -477,24 +479,22 @@ pub const TestContext = struct {
477479
478 switch (update.case) {480 switch (update.case) {
479 .Transformation => |expected_output| {481 .Transformation => |expected_output| {
480 var label: []const u8 = "ZIR";482 if (case.cbe) {
481 if (case.c_standard) |cstd| {483 var cfile: *link.File.C = module.bin_file.cast(link.File.C).?;
482 label = @tagName(cstd);484 cfile.file.?.close();
483 var c: *link.File.C = module.bin_file.cast(link.File.C).?;485 cfile.file = null;
484 c.file.?.close();
485 c.file = null;
486 var file = try tmp.dir.openFile(bin_name, .{ .read = true });486 var file = try tmp.dir.openFile(bin_name, .{ .read = true });
487 defer file.close();487 defer file.close();
488 var out = file.reader().readAllAlloc(allocator, 1024 * 1024) catch @panic("Unable to read C output!");488 var out = file.reader().readAllAlloc(allocator, 1024 * 1024) catch @panic("Unable to read C output!");
489 defer allocator.free(out);489 defer allocator.free(out);
490490
491 if (expected_output.len != out.len) {491 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 });
493 std.process.exit(1);493 std.process.exit(1);
494 }494 }
495 for (expected_output) |e, i| {495 for (expected_output) |e, i| {
496 if (out[i] != e) {496 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 });
498 std.process.exit(1);498 std.process.exit(1);
499 }499 }
500 }500 }
...@@ -518,12 +518,12 @@ pub const TestContext = struct {...@@ -518,12 +518,12 @@ pub const TestContext = struct {
518 defer test_node.end();518 defer test_node.end();
519519
520 if (expected_output.len != out_zir.items.len) {520 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 });
522 std.process.exit(1);522 std.process.exit(1);
523 }523 }
524 for (expected_output) |e, i| {524 for (expected_output) |e, i| {
525 if (out_zir.items[i] != e) {525 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 });
527 std.process.exit(1);527 std.process.exit(1);
528 }528 }
529 }529 }
...@@ -561,7 +561,7 @@ pub const TestContext = struct {...@@ -561,7 +561,7 @@ pub const TestContext = struct {
561 }561 }
562 },562 },
563 .Execution => |expected_stdout| {563 .Execution => |expected_stdout| {
564 std.debug.assert(case.c_standard == null);564 std.debug.assert(!case.cbe);
565565
566 update_node.estimated_total_items = 4;566 update_node.estimated_total_items = 4;
567 var exec_result = x: {567 var exec_result = x: {
test/stage2/cbe.zig+10-10
...@@ -9,30 +9,30 @@ const linux_x64 = std.zig.CrossTarget{...@@ -9,30 +9,30 @@ const linux_x64 = std.zig.CrossTarget{
9};9};
1010
11pub fn addCases(ctx: *TestContext) !void {11pub fn addCases(ctx: *TestContext) !void {
12 ctx.c11("empty start function", linux_x64,12 ctx.c("empty start function", linux_x64,
13 \\export fn _start() noreturn {}13 \\export fn _start() noreturn {}
14 ,14 ,
15 \\_Noreturn void _start(void) {}15 \\noreturn void _start(void) {}
16 \\16 \\
17 );17 );
18 ctx.c11("less empty start function", linux_x64,18 ctx.c("less empty start function", linux_x64,
19 \\fn main() noreturn {}19 \\fn main() noreturn {}
20 \\20 \\
21 \\export fn _start() noreturn {21 \\export fn _start() noreturn {
22 \\ main();22 \\ main();
23 \\}23 \\}
24 ,24 ,
25 \\_Noreturn void main(void);25 \\noreturn void main(void);
26 \\26 \\
27 \\_Noreturn void _start(void) {27 \\noreturn void _start(void) {
28 \\ main();28 \\ main();
29 \\}29 \\}
30 \\30 \\
31 \\_Noreturn void main(void) {}31 \\noreturn void main(void) {}
32 \\32 \\
33 );33 );
34 // TODO: implement return values34 // TODO: implement return values
35 ctx.c11("inline asm", linux_x64,35 ctx.c("inline asm", linux_x64,
36 \\fn exitGood() void {36 \\fn exitGood() void {
37 \\ asm volatile ("syscall"37 \\ asm volatile ("syscall"
38 \\ :38 \\ :
...@@ -49,7 +49,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -49,7 +49,7 @@ pub fn addCases(ctx: *TestContext) !void {
49 \\49 \\
50 \\void exitGood(void);50 \\void exitGood(void);
51 \\51 \\
52 \\_Noreturn void _start(void) {52 \\noreturn void _start(void) {
53 \\ exitGood();53 \\ exitGood();
54 \\}54 \\}
55 \\55 \\
...@@ -60,7 +60,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -60,7 +60,7 @@ pub fn addCases(ctx: *TestContext) !void {
60 \\}60 \\}
61 \\61 \\
62 );62 );
63 //ctx.c11("basic return", linux_x64,63 //ctx.c("basic return", linux_x64,
64 // \\fn main() u8 {64 // \\fn main() u8 {
65 // \\ return 103;65 // \\ return 103;
66 // \\}66 // \\}
...@@ -73,7 +73,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -73,7 +73,7 @@ pub fn addCases(ctx: *TestContext) !void {
73 // \\73 // \\
74 // \\uint8_t main(void);74 // \\uint8_t main(void);
75 // \\75 // \\
76 // \\_Noreturn void _start(void) {76 // \\noreturn void _start(void) {
77 // \\ (void)main();77 // \\ (void)main();
78 // \\}78 // \\}
79 // \\79 // \\