Commit 64bf130182

Noam Preil <pleasantatk@gmail.com>
2020-07-08 03:35:00
CBE: working asm Inputs and Outputs; std{int,def}.h auto-inclusion
1 parent cf09b33
Changed files (3)
src-self-hosted
test
stage2
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;
+        },
     }
 }
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();
+            var includes = false;
+            if (self.need_stddef) {
+                try writer.writeAll("#include <stddef.h>\n");
+                includes = true;
+            }
+            if (self.need_stdint) {
+                try writer.writeAll("#include <stdint.h>\n");
+                includes = true;
+            }
+            if (includes) {
+                try writer.writeByte('\n');
+            }
             if (self.header.items.len > 0) {
-                try self.header.append('\n');
+                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")) {
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 <stddef.h>
+        \\
+        \\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 <stdint.h>
+    //    \\
+    //    \\uint8_t main(void);
+    //    \\
+    //    \\_Noreturn void _start(void) {
+    //    \\	(void)main();
+    //    \\}
+    //    \\
+    //    \\uint8_t main(void) {
+    //    \\	return 103;
+    //    \\}
+    //    \\
+    //);
 }