Commit 6ca0ff90b6

Veikka Tuominen <git@vexu.eu>
2021-01-26 19:25:30
stage2 cbe: use AutoIndentingStream
1 parent 81c512f
Changed files (2)
src
codegen
link
src/codegen/c.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
 const mem = std.mem;
 const log = std.log.scoped(.c);
-const Writer = std.ArrayList(u8).Writer;
 
 const link = @import("../link.zig");
 const Module = @import("../Module.zig");
@@ -42,6 +41,7 @@ pub const Object = struct {
     value_map: CValueMap,
     next_arg_index: usize = 0,
     next_local_index: usize = 0,
+    indent_writer: std.io.AutoIndentingStream(std.ArrayList(u8).Writer),
 
     fn resolveInst(o: *Object, inst: *Inst) !CValue {
         if (inst.value()) |_| {
@@ -58,31 +58,28 @@ pub const Object = struct {
 
     fn allocLocal(o: *Object, ty: Type, mutability: Mutability) !CValue {
         const local_value = o.allocLocalValue();
-        try o.renderTypeAndName(o.code.writer(), ty, local_value, mutability);
+        try o.renderTypeAndName(o.writer(), ty, local_value, mutability);
         return local_value;
     }
 
-    fn indent(o: *Object) !void {
-        const indent_size = 4;
-        const indent_level = 1;
-        const indent_amt = indent_size * indent_level;
-        try o.code.writer().writeByteNTimes(' ', indent_amt);
+    fn writer(o: *Object) std.io.AutoIndentingStream(std.ArrayList(u8).Writer).Writer {
+        return o.indent_writer.writer();
     }
 
-    fn writeCValue(o: *Object, writer: Writer, c_value: CValue) !void {
+    fn writeCValue(o: *Object, w: anytype, c_value: CValue) !void {
         switch (c_value) {
             .none => unreachable,
-            .local => |i| return writer.print("t{d}", .{i}),
-            .local_ref => |i| return writer.print("&t{d}", .{i}),
-            .constant => |inst| return o.dg.renderValue(writer, inst.ty, inst.value().?),
-            .arg => |i| return writer.print("a{d}", .{i}),
-            .decl => |decl| return writer.writeAll(mem.span(decl.name)),
+            .local => |i| return w.print("t{d}", .{i}),
+            .local_ref => |i| return w.print("&t{d}", .{i}),
+            .constant => |inst| return o.dg.renderValue(w, inst.ty, inst.value().?),
+            .arg => |i| return w.print("a{d}", .{i}),
+            .decl => |decl| return w.writeAll(mem.span(decl.name)),
         }
     }
 
     fn renderTypeAndName(
         o: *Object,
-        writer: Writer,
+        w: anytype,
         ty: Type,
         name: CValue,
         mutability: Mutability,
@@ -98,15 +95,15 @@ pub const Object = struct {
             render_ty = render_ty.elemType();
         }
 
-        try o.dg.renderType(writer, render_ty);
+        try o.dg.renderType(w, render_ty);
 
         const const_prefix = switch (mutability) {
             .Const => "const ",
             .Mut => "",
         };
-        try writer.print(" {s}", .{const_prefix});
-        try o.writeCValue(writer, name);
-        try writer.writeAll(suffix.items);
+        try w.print(" {s}", .{const_prefix});
+        try o.writeCValue(w, name);
+        try w.writeAll(suffix.items);
     }
 };
 
@@ -127,7 +124,7 @@ pub const DeclGen = struct {
 
     fn renderValue(
         dg: *DeclGen,
-        writer: Writer,
+        writer: anytype,
         t: Type,
         val: Value,
     ) error{ OutOfMemory, AnalysisFail }!void {
@@ -204,7 +201,7 @@ pub const DeclGen = struct {
         }
     }
 
-    fn renderFunctionSignature(dg: *DeclGen, w: Writer, is_global: bool) !void {
+    fn renderFunctionSignature(dg: *DeclGen, w: anytype, is_global: bool) !void {
         if (!is_global) {
             try w.writeAll("static ");
         }
@@ -228,7 +225,7 @@ pub const DeclGen = struct {
         try w.writeByte(')');
     }
 
-    fn renderType(dg: *DeclGen, w: Writer, t: Type) error{ OutOfMemory, AnalysisFail }!void {
+    fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void {
         switch (t.zigTypeTag()) {
             .NoReturn => {
                 try w.writeAll("zig_noreturn void");
@@ -325,20 +322,19 @@ pub fn genDecl(o: *Object) !void {
         try fwd_decl_writer.writeAll(";\n");
 
         const func: *Module.Fn = func_payload.data;
-        const writer = o.code.writer();
-        try writer.writeAll("\n");
-        try o.dg.renderFunctionSignature(writer, is_global);
+        try o.indent_writer.insertNewline();
+        try o.dg.renderFunctionSignature(o.writer(), is_global);
         
         try genBody(o, func.body);
 
-        try writer.writeAll("\n");
+        try o.indent_writer.insertNewline();
     } else if (tv.val.tag() == .extern_fn) {
-        const writer = o.code.writer();
+        const writer = o.writer();
         try writer.writeAll("ZIG_EXTERN_C ");
         try o.dg.renderFunctionSignature(writer, true);
         try writer.writeAll(";\n");
     } else {
-        const writer = o.code.writer();
+        const writer = o.writer();
         try writer.writeAll("static ");
 
         // TODO ask the Decl if it is const
@@ -374,15 +370,15 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
 }
 
 pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!void {
-    const writer = o.code.writer();
+    const writer = o.writer();
     if (body.instructions.len == 0) {
         try writer.writeAll(" {}");
         return;
     }
 
-    try writer.writeAll(" {");
+    try writer.writeAll(" {\n");
+    o.indent_writer.pushIndent();
 
-    try writer.writeAll("\n");
     for (body.instructions) |inst| {
         const result_value = switch (inst.tag) {
             .add => try genBinOp(o, inst.castTag(.add).?, " + "),
@@ -416,14 +412,14 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
         }
     }
 
+    o.indent_writer.popIndent();
     try writer.writeAll("}");
 }
 
 fn genAlloc(o: *Object, alloc: *Inst.NoOp) !CValue {
-    const writer = o.code.writer();
+    const writer = o.writer();
 
     // First line: the variable used as data storage.
-    try o.indent();
     const elem_type = alloc.base.ty.elemType();
     const mutability: Mutability = if (alloc.base.ty.isConstPtr()) .Const else .Mut;
     const local = try o.allocLocal(elem_type, mutability);
@@ -439,15 +435,13 @@ fn genArg(o: *Object) CValue {
 }
 
 fn genRetVoid(o: *Object) !CValue {
-    try o.indent();
-    try o.code.writer().print("return;\n", .{});
+    try o.writer().print("return;\n", .{});
     return CValue.none;
 }
 
 fn genLoad(o: *Object, inst: *Inst.UnOp) !CValue {
     const operand = try o.resolveInst(inst.operand);
-    const writer = o.code.writer();
-    try o.indent();
+    const writer = o.writer();
     const local = try o.allocLocal(inst.base.ty, .Const);
     switch (operand) {
         .local_ref => |i| {
@@ -467,8 +461,7 @@ fn genLoad(o: *Object, inst: *Inst.UnOp) !CValue {
 
 fn genRet(o: *Object, inst: *Inst.UnOp) !CValue {
     const operand = try o.resolveInst(inst.operand);
-    try o.indent();
-    const writer = o.code.writer();
+    const writer = o.writer();
     try writer.writeAll("return ");
     try o.writeCValue(writer, operand);
     try writer.writeAll(";\n");
@@ -481,8 +474,7 @@ fn genIntCast(o: *Object, inst: *Inst.UnOp) !CValue {
 
     const from = try o.resolveInst(inst.operand);
 
-    try o.indent();
-    const writer = o.code.writer();
+    const writer = o.writer();
     const local = try o.allocLocal(inst.base.ty, .Const);
     try writer.writeAll(" = (");
     try o.dg.renderType(writer, inst.base.ty);
@@ -497,8 +489,7 @@ fn genStore(o: *Object, inst: *Inst.BinOp) !CValue {
     const dest_ptr = try o.resolveInst(inst.lhs);
     const src_val = try o.resolveInst(inst.rhs);
 
-    try o.indent();
-    const writer = o.code.writer();
+    const writer = o.writer();
     switch (dest_ptr) {
         .local_ref => |i| {
             const dest: CValue = .{ .local = i };
@@ -525,8 +516,7 @@ fn genBinOp(o: *Object, inst: *Inst.BinOp, operator: []const u8) !CValue {
     const lhs = try o.resolveInst(inst.lhs);
     const rhs = try o.resolveInst(inst.rhs);
 
-    try o.indent();
-    const writer = o.code.writer();
+    const writer = o.writer();
     const local = try o.allocLocal(inst.base.ty, .Const);
 
     try writer.writeAll(" = ");
@@ -552,8 +542,7 @@ fn genCall(o: *Object, inst: *Inst.Call) !CValue {
         const unused_result = inst.base.isUnused();
         var result_local: CValue = .none;
 
-        try o.indent();
-        const writer = o.code.writer();
+        const writer = o.writer();
         if (unused_result) {
             if (ret_ty.hasCodeGenBits()) {
                 try writer.print("(void)", .{});
@@ -596,8 +585,7 @@ fn genBlock(o: *Object, inst: *Inst.Block) !CValue {
 fn genBitcast(o: *Object, inst: *Inst.UnOp) !CValue {
     const operand = try o.resolveInst(inst.operand);
 
-    const writer = o.code.writer();
-    try o.indent();
+    const writer = o.writer();
     if (inst.base.ty.zigTypeTag() == .Pointer and inst.operand.ty.zigTypeTag() == .Pointer) {
         const local = try o.allocLocal(inst.base.ty, .Const);
         try writer.writeAll(" = (");
@@ -611,7 +599,6 @@ fn genBitcast(o: *Object, inst: *Inst.UnOp) !CValue {
 
     const local = try o.allocLocal(inst.base.ty, .Mut);
     try writer.writeAll(";\n");
-    try o.indent();
 
     try writer.writeAll("memcpy(&");
     try o.writeCValue(writer, local);
@@ -625,22 +612,19 @@ fn genBitcast(o: *Object, inst: *Inst.UnOp) !CValue {
 }
 
 fn genBreakpoint(o: *Object, inst: *Inst.NoOp) !CValue {
-    try o.indent();
-    try o.code.writer().writeAll("zig_breakpoint();\n");
+    try o.writer().writeAll("zig_breakpoint();\n");
     return CValue.none;
 }
 
 fn genUnreach(o: *Object, inst: *Inst.NoOp) !CValue {
-    try o.indent();
-    try o.code.writer().writeAll("zig_unreachable();\n");
+    try o.writer().writeAll("zig_unreachable();\n");
     return CValue.none;
 }
 
 fn genLoop(o: *Object, inst: *Inst.Loop) !CValue {
-    try o.indent();
-    try o.code.writer().writeAll("while (true)");
+    try o.writer().writeAll("while (true)");
     try genBody(o, inst.body);
-    try o.code.writer().writeAll("\n");
+    try o.indent_writer.insertNewline();
     return CValue.none;
 }
 
@@ -648,13 +632,12 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {
     if (as.base.isUnused() and !as.is_volatile)
         return CValue.none;
 
-    const writer = o.code.writer();
+    const writer = o.writer();
     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];
             const arg_c_value = try o.resolveInst(arg);
-            try o.indent();
             try writer.writeAll("register ");
             try o.dg.renderType(writer, arg.ty);
 
@@ -665,7 +648,6 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {
             return o.dg.fail(o.dg.decl.src(), "TODO non-explicit inline asm regs", .{});
         }
     }
-    try o.indent();
     const volatile_string: []const u8 = if (as.is_volatile) "volatile " else "";
     try writer.print("__asm {s}(\"{s}\"", .{ volatile_string, as.asm_source });
     if (as.output) |_| {
src/link/C.zig
@@ -95,7 +95,9 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
         .gpa = module.gpa,
         .code = code.toManaged(module.gpa),
         .value_map = codegen.CValueMap.init(module.gpa),
+        .indent_writer = undefined, // set later so we can get a pointer to object.code
     };
+    object.indent_writer = std.io.autoIndentingStream(4, object.code.writer());
     defer object.value_map.deinit();
     defer object.code.deinit();
     defer object.dg.fwd_decl.deinit();