diff --git a/src-self-hosted/cgen.zig b/src-self-hosted/cgen.zig index 99828ee362..5b04d98119 100644 --- a/src-self-hosted/cgen.zig +++ b/src-self-hosted/cgen.zig @@ -16,16 +16,24 @@ fn map(name: []const u8) ![]const u8 { return name; } -fn renderFunctionSignature(writer: std.ArrayList(u8).Writer, decl: *Decl) !void { - const tv = decl.typed_value.most_recent.typed_value; - switch (tv.ty.fnReturnType().zigTypeTag()) { - .NoReturn => { - try writer.writeAll("_Noreturn void "); - }, - else => return error.Unimplemented, +fn renderType(file: *C, writer: std.ArrayList(u8).Writer, T: Type) !void { + if (T.tag() == .usize) { + file.need_stddef = true; + try writer.writeAll("size_t"); + } else { + switch (T.zigTypeTag()) { + .NoReturn => try writer.writeAll("_Noreturn void"), + .Void => try writer.writeAll("void"), + else => return error.Unimplemented, + } } +} + +fn renderFunctionSignature(file: *C, writer: std.ArrayList(u8).Writer, decl: *Decl) !void { + const tv = decl.typed_value.most_recent.typed_value; + try renderType(file, writer, tv.ty.fnReturnType()); const name = try map(mem.spanZ(decl.name)); - try writer.print("{}(", .{name}); + try writer.print(" {}(", .{name}); if (tv.ty.fnParamLen() == 0) { try writer.writeAll("void)"); } else { @@ -39,7 +47,7 @@ pub fn generate(file: *C, decl: *Decl, standard: CStandard) !void { const tv = decl.typed_value.most_recent.typed_value; switch (tv.ty.zigTypeTag()) { .Fn => { - try renderFunctionSignature(writer, decl); + try renderFunctionSignature(file, writer, decl); try writer.writeAll(" {"); const func: *Module.Fn = tv.val.cast(Value.Payload.Function).?.func; @@ -48,6 +56,55 @@ pub fn generate(file: *C, decl: *Decl, standard: CStandard) !void { for (instructions) |inst| { try writer.writeAll("\n\t"); switch (inst.tag) { + .assembly => { + const as = inst.cast(ir.Inst.Assembly).?.args; + for (as.inputs) |i, index| { + if (i[0] == '{' and i[i.len - 1] == '}') { + const reg = i[1 .. i.len - 1]; + const arg = as.args[index]; + if (arg.cast(ir.Inst.Constant)) |c| { + if (c.val.tag() == .int_u64) { + try writer.writeAll("register "); + try renderType(file, writer, arg.ty); + try writer.print(" {}_constant __asm__(\"{}\") = {};\n\t", .{ reg, reg, c.val.toUnsignedInt() }); + } else { + return error.Unimplemented; + } + } else { + return error.Unimplemented; + } + } else { + return error.Unimplemented; + } + } + try writer.print("__asm {} (\"{}\"", .{ if (as.is_volatile) @as([]const u8, "volatile") else "", as.asm_source }); + if (as.output) |o| { + return error.Unimplemented; + } + if (as.inputs.len > 0) { + if (as.output == null) { + try writer.writeAll(" :"); + } + try writer.writeAll(": "); + for (as.inputs) |i, index| { + if (i[0] == '{' and i[i.len - 1] == '}') { + const reg = i[1 .. i.len - 1]; + const arg = as.args[index]; + if (index > 0) { + try writer.writeAll(", "); + } + if (arg.cast(ir.Inst.Constant)) |c| { + try writer.print("\"\"({}_constant)", .{reg}); + } else { + return error.Unimplemented; + } + } else { + return error.Unimplemented; + } + } + } + try writer.writeAll(");"); + }, .call => { const call = inst.cast(ir.Inst.Call).?.args; if (call.func.cast(ir.Inst.Constant)) |func_inst| { @@ -56,17 +113,20 @@ pub fn generate(file: *C, decl: *Decl, standard: CStandard) !void { const tname = mem.spanZ(target.name); if (file.called.get(tname) == null) { try file.called.put(tname, void{}); - try renderFunctionSignature(header, target); + try renderFunctionSignature(file, header, target); try header.writeAll(";\n"); } try writer.print("{}();", .{tname}); } else { + std.debug.warn("non-function call target?\n", .{}); return error.Unimplemented; } if (call.args.len != 0) { + std.debug.warn("parameters\n", .{}); return error.Unimplemented; } } else { + std.debug.warn("non-constant call inst?\n", .{}); return error.Unimplemented; } }, @@ -80,6 +140,21 @@ pub fn generate(file: *C, decl: *Decl, standard: CStandard) !void { try writer.writeAll("}\n\n"); }, - else => return error.Unimplemented, + .Array => { + if (mem.indexOf(u8, mem.span(decl.name), "$") == null) { + // TODO: prevent inline asm constants from being emitted + if (tv.val.cast(Value.Payload.Bytes)) |payload| { + try writer.print("const char *const {} = \"{}\";\n", .{ decl.name, payload.data }); + std.debug.warn("\n\nARRAYTRANS\n", .{}); + if (tv.ty.arraySentinel()) |sentinel| {} + } else { + return error.Unimplemented; + } + } + }, + else => |e| { + std.debug.warn("\nTODO implement {}\n", .{e}); + return error.Unimplemented; + }, } } diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index c47e1597c6..8352f64fca 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -191,7 +191,7 @@ pub const File = struct { pub fn options(base: *File) Options { return switch (base.tag) { .Elf => @fieldParentPtr(Elf, "base", base).options, - else => unreachable, + .C => @fieldParentPtr(C, "base", base).options, }; } @@ -215,6 +215,8 @@ pub const File = struct { owns_file_handle: bool, options: Options, called: std.StringHashMap(void), + need_stddef: bool = false, + need_stdint: bool = false, pub fn makeWritable(self: *File.C, dir: fs.Dir, sub_path: []const u8) !void { assert(self.owns_file_handle); @@ -242,10 +244,21 @@ pub const File = struct { pub fn flush(self: *File.C) !void { const writer = self.file.?.writer(); - if (self.header.items.len > 0) { - try self.header.append('\n'); + var includes = false; + if (self.need_stddef) { + try writer.writeAll("#include \n"); + includes = true; + } + if (self.need_stdint) { + try writer.writeAll("#include \n"); + includes = true; + } + if (includes) { + try writer.writeByte('\n'); + } + if (self.header.items.len > 0) { + try writer.print("{}\n", .{self.header.items}); } - try writer.writeAll(self.header.items); if (self.main.items.len > 1) { const last_two = self.main.items[self.main.items.len - 2 ..]; if (std.mem.eql(u8, last_two, "\n\n")) { diff --git a/test/stage2/cbe.zig b/test/stage2/cbe.zig index 88eb6c5953..9a28c25e27 100644 --- a/test/stage2/cbe.zig +++ b/test/stage2/cbe.zig @@ -31,4 +31,55 @@ pub fn addCases(ctx: *TestContext) !void { \\_Noreturn void main(void) {} \\ ); + // TODO: implement return values + ctx.c11("inline asm", linux_x64, + \\fn exitGood() void { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ ); + \\} + \\ + \\export fn _start() noreturn { + \\ exitGood(); + \\} + , + \\#include + \\ + \\void exitGood(void); + \\ + \\_Noreturn void _start(void) { + \\ exitGood(); + \\} + \\ + \\void exitGood(void) { + \\ register size_t rax_constant __asm__("rax") = 231; + \\ register size_t rdi_constant __asm__("rdi") = 0; + \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant)); + \\} + \\ + ); + //ctx.c11("basic return", linux_x64, + // \\fn main() u8 { + // \\ return 103; + // \\} + // \\ + // \\export fn _start() noreturn { + // \\ _ = main(); + // \\} + //, + // \\#include + // \\ + // \\uint8_t main(void); + // \\ + // \\_Noreturn void _start(void) { + // \\ (void)main(); + // \\} + // \\ + // \\uint8_t main(void) { + // \\ return 103; + // \\} + // \\ + //); }