Commit 1dd4a6102f

Jacob Young <jacobly0@users.noreply.github.com>
2022-10-11 10:51:52
cbe: implement global assembly
1 parent e8bda9e
Changed files (6)
src
codegen
link
test
src/codegen/c.zig
@@ -1845,6 +1845,13 @@ pub const DeclGen = struct {
     }
 };
 
+pub fn genGlobalAsm(mod: *Module, code: *std.ArrayList(u8)) !void {
+    var it = mod.global_assembly.valueIterator();
+    while (it.next()) |asm_source| {
+        try code.writer().print("__asm({s});\n", .{fmtStringLiteral(asm_source.*)});
+    }
+}
+
 pub fn genErrDecls(o: *Object) !void {
     if (o.dg.module.global_error_set.size == 0) return;
     const writer = o.writer();
@@ -3450,8 +3457,10 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
     try writer.writeAll("{\n");
     f.object.indent_writer.pushIndent();
 
+    const output_locals_begin = f.next_local_index;
+    f.next_local_index += outputs.len;
     const constraints_extra_begin = extra_i;
-    for (outputs) |output| {
+    for (outputs) |output, index| {
         const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
         const constraint = std.mem.sliceTo(extra_bytes, 0);
         const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
@@ -3461,7 +3470,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
 
         const output_ty = if (output == .none) inst_ty else f.air.typeOf(output).childType();
         try writer.writeAll("register ");
-        try f.object.dg.renderTypeAndName(writer, output_ty, .{ .identifier = name }, .Mut, 0);
+        try f.object.dg.renderTypeAndName(writer, output_ty, .{
+            .local = output_locals_begin + index,
+        }, .Mut, 0);
         if (std.mem.startsWith(u8, constraint, "={") and std.mem.endsWith(u8, constraint, "}")) {
             try writer.writeAll(" __asm(\"");
             try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
@@ -3475,7 +3486,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
         }
         try writer.writeAll(";\n");
     }
-    for (inputs) |input| {
+    const input_locals_begin = f.next_local_index;
+    f.next_local_index += inputs.len;
+    for (inputs) |input, index| {
         const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
         const constraint = std.mem.sliceTo(extra_bytes, 0);
         const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
@@ -3485,7 +3498,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
 
         const input_ty = f.air.typeOf(input);
         try writer.writeAll("register ");
-        try f.object.dg.renderTypeAndName(writer, input_ty, .{ .identifier = name }, .Const, 0);
+        try f.object.dg.renderTypeAndName(writer, input_ty, .{
+            .local = input_locals_begin + index,
+        }, .Const, 0);
         if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) {
             try writer.writeAll(" __asm(\"");
             try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);
@@ -3524,7 +3539,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
 
         if (index > 0) try writer.writeByte(',');
         try writer.print(" {s}(", .{fmtStringLiteral(if (constraint[1] == '{') "=r" else constraint)});
-        try f.writeCValue(writer, .{ .identifier = name });
+        try f.writeCValue(writer, .{ .local = output_locals_begin + index });
         try writer.writeByte(')');
     }
     try writer.writeByte(':');
@@ -3538,7 +3553,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
 
         if (index > 0) try writer.writeByte(',');
         try writer.print(" {s}(", .{fmtStringLiteral(if (constraint[0] == '{') "r" else constraint)});
-        try f.writeCValue(writer, .{ .identifier = name });
+        try f.writeCValue(writer, .{ .local = input_locals_begin + index });
         try writer.writeByte(')');
     }
     try writer.writeByte(':');
@@ -3559,7 +3574,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
     try writer.writeAll(");\n");
 
     extra_i = constraints_extra_begin;
-    for (outputs) |output| {
+    for (outputs) |output, index| {
         const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
         const constraint = std.mem.sliceTo(extra_bytes, 0);
         const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
@@ -3571,7 +3586,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
             .local_ref = local.local,
         } else try f.resolveInst(output));
         try writer.writeAll(" = ");
-        try f.writeCValue(writer, .{ .identifier = name });
+        try f.writeCValue(writer, .{ .local = output_locals_begin + index });
         try writer.writeAll(";\n");
     }
 
src/link/C.zig
@@ -256,7 +256,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
     var f: Flush = .{};
     defer f.deinit(gpa);
 
-    // Covers zig.h and typedef.
+    // Covers zig.h, typedef, and asm.
     try f.all_buffers.ensureUnusedCapacity(gpa, 2);
 
     f.appendBufAssumeCapacity(zig_h);
@@ -264,6 +264,16 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
     const typedef_index = f.all_buffers.items.len;
     f.all_buffers.items.len += 1;
 
+    {
+        var asm_buf = f.asm_buf.toManaged(module.gpa);
+        defer asm_buf.deinit();
+
+        try codegen.genGlobalAsm(module, &asm_buf);
+
+        f.asm_buf = asm_buf.moveToUnmanaged();
+        f.appendBufAssumeCapacity(f.asm_buf.items);
+    }
+
     try self.flushErrDecls(&f);
 
     // Typedefs, forward decls, and non-functions first.
@@ -307,6 +317,7 @@ const Flush = struct {
     remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{},
     typedefs: Typedefs = .{},
     typedef_buf: std.ArrayListUnmanaged(u8) = .{},
+    asm_buf: std.ArrayListUnmanaged(u8) = .{},
     /// We collect a list of buffers to write, and write them all at once with pwritev ๐Ÿ˜Ž
     all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{},
     /// Keeps track of the total bytes of `all_buffers`.
test/behavior/array.zig
@@ -527,7 +527,6 @@ test "type coercion of anon struct literal to array" {
 }
 
 test "type coercion of pointer to anon struct literal to pointer to array" {
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
test/behavior/asm.zig
@@ -18,7 +18,6 @@ comptime {
 }
 
 test "module level assembly" {
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
@@ -50,7 +49,6 @@ test "output constraint modifiers" {
 }
 
 test "alternative constraints" {
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/eval.zig
@@ -746,7 +746,6 @@ fn scalar(x: u32) u32 {
 
 test "array concatenation peer resolves element types - value" {
     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 
@@ -781,7 +780,6 @@ test "array concatenation sets the sentinel - value" {
     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 
@@ -819,7 +817,6 @@ test "array multiplication sets the sentinel - value" {
     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 
test/behavior/slice.zig
@@ -533,7 +533,6 @@ test "slice pointer-to-array zero length" {
 }
 
 test "type coercion of pointer to anon struct literal to pointer to slice" {
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO