diff options
Diffstat (limited to 'src/codegen/c.zig')
| -rw-r--r-- | src/codegen/c.zig | 100 |
1 files changed, 41 insertions, 59 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig index ccde36a10d..9bccde5ffd 100644 --- a/src/codegen/c.zig +++ b/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) |_| { |
