diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-07-10 12:04:27 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-10 12:04:27 +0200 |
| commit | 1a998886c863a1829d649f196093f1058cd9cf13 (patch) | |
| tree | db1b3b0a043a113cfb6544e8103cb64f8e4e4d8f /src/codegen | |
| parent | 5b4b033236a7bed19c90faf7fefbc1990911cfef (diff) | |
| parent | 10d6db5d7d1fb62ee2915a7ad2c7feb771ea3bbb (diff) | |
| download | zig-1a998886c863a1829d649f196093f1058cd9cf13.tar.gz zig-1a998886c863a1829d649f196093f1058cd9cf13.zip | |
Merge pull request #24329 from ziglang/writergate
Deprecates all existing std.io readers and writers in favor of the newly
provided std.io.Reader and std.io.Writer which are non-generic and have the
buffer above the vtable - in other words the buffer is in the interface, not
the implementation. This means that although Reader and Writer are no longer
generic, they are still transparent to optimization; all of the interface
functions have a concrete hot path operating on the buffer, and only make
vtable calls when the buffer is full.
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/c.zig | 4379 | ||||
| -rw-r--r-- | src/codegen/c/Type.zig | 46 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 48 | ||||
| -rw-r--r-- | src/codegen/spirv.zig | 18 | ||||
| -rw-r--r-- | src/codegen/spirv/spec.zig | 10 |
5 files changed, 2278 insertions, 2223 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 7ee33577d8..61bd5259ae 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -4,6 +4,7 @@ const assert = std.debug.assert; const mem = std.mem; const log = std.log.scoped(.c); const Allocator = mem.Allocator; +const Writer = std.io.Writer; const dev = @import("../dev.zig"); const link = @import("../link.zig"); @@ -55,6 +56,7 @@ pub const Mir = struct { /// less than the natural alignment. uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), // These remaining fields are essentially just an owned version of `link.C.AvBlock`. + code_header: []u8, code: []u8, fwd_decl: []u8, ctype_pool: CType.Pool, @@ -62,6 +64,7 @@ pub const Mir = struct { pub fn deinit(mir: *Mir, gpa: Allocator) void { mir.uavs.deinit(gpa); + gpa.free(mir.code_header); gpa.free(mir.code); gpa.free(mir.fwd_decl); mir.ctype_pool.deinit(gpa); @@ -69,6 +72,8 @@ pub const Mir = struct { } }; +pub const Error = Writer.Error || std.mem.Allocator.Error || error{AnalysisFail}; + pub const CType = @import("c/Type.zig"); pub const CValue = union(enum) { @@ -340,53 +345,61 @@ fn isReservedIdent(ident: []const u8) bool { } else return reserved_idents.has(ident); } -fn formatIdent( - ident: []const u8, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { - const solo = fmt_str.len != 0 and fmt_str[0] == ' '; // space means solo; not part of a bigger ident. +fn formatIdentSolo(ident: []const u8, w: *std.io.Writer) std.io.Writer.Error!void { + return formatIdentOptions(ident, w, true); +} + +fn formatIdentUnsolo(ident: []const u8, w: *std.io.Writer) std.io.Writer.Error!void { + return formatIdentOptions(ident, w, false); +} + +fn formatIdentOptions(ident: []const u8, w: *std.io.Writer, solo: bool) std.io.Writer.Error!void { if (solo and isReservedIdent(ident)) { - try writer.writeAll("zig_e_"); + try w.writeAll("zig_e_"); } for (ident, 0..) |c, i| { switch (c) { - 'a'...'z', 'A'...'Z', '_' => try writer.writeByte(c), - '.' => try writer.writeByte('_'), + 'a'...'z', 'A'...'Z', '_' => try w.writeByte(c), + '.' => try w.writeByte('_'), '0'...'9' => if (i == 0) { - try writer.print("_{x:2}", .{c}); + try w.print("_{x:2}", .{c}); } else { - try writer.writeByte(c); + try w.writeByte(c); }, - else => try writer.print("_{x:2}", .{c}), + else => try w.print("_{x:2}", .{c}), } } } -pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) { + +pub fn fmtIdentSolo(ident: []const u8) std.fmt.Formatter([]const u8, formatIdentSolo) { + return .{ .data = ident }; +} + +pub fn fmtIdentUnsolo(ident: []const u8) std.fmt.Formatter([]const u8, formatIdentUnsolo) { return .{ .data = ident }; } const CTypePoolStringFormatData = struct { ctype_pool_string: CType.Pool.String, ctype_pool: *const CType.Pool, + solo: bool, }; -fn formatCTypePoolString( - data: CTypePoolStringFormatData, - comptime fmt_str: []const u8, - fmt_opts: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { +fn formatCTypePoolString(data: CTypePoolStringFormatData, w: *std.io.Writer) std.io.Writer.Error!void { if (data.ctype_pool_string.toSlice(data.ctype_pool)) |slice| - try formatIdent(slice, fmt_str, fmt_opts, writer) + try formatIdentOptions(slice, w, data.solo) else - try writer.print("{}", .{data.ctype_pool_string.fmt(data.ctype_pool)}); + try w.print("{f}", .{data.ctype_pool_string.fmt(data.ctype_pool)}); } pub fn fmtCTypePoolString( ctype_pool_string: CType.Pool.String, ctype_pool: *const CType.Pool, -) std.fmt.Formatter(formatCTypePoolString) { - return .{ .data = .{ .ctype_pool_string = ctype_pool_string, .ctype_pool = ctype_pool } }; + solo: bool, +) std.fmt.Formatter(CTypePoolStringFormatData, formatCTypePoolString) { + return .{ .data = .{ + .ctype_pool_string = ctype_pool_string, + .ctype_pool = ctype_pool, + .solo = solo, + } }; } // Returns true if `formatIdent` would make any edits to ident. @@ -440,18 +453,18 @@ pub const Function = struct { const ty = f.typeOf(ref); const result: CValue = if (lowersToArray(ty, pt)) result: { - const writer = f.object.codeHeaderWriter(); + const ch = &f.object.code_header.writer; const decl_c_value = try f.allocLocalValue(.{ .ctype = try f.ctypeFromType(ty, .complete), .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(pt.zcu)), }); const gpa = f.object.dg.gpa; try f.allocs.put(gpa, decl_c_value.new_local, false); - try writer.writeAll("static "); - try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, .none, .complete); - try writer.writeAll(" = "); - try f.object.dg.renderValue(writer, val, .StaticInitializer); - try writer.writeAll(";\n "); + try ch.writeAll("static "); + try f.object.dg.renderTypeAndName(ch, ty, decl_c_value, Const, .none, .complete); + try ch.writeAll(" = "); + try f.object.dg.renderValue(ch, val, .StaticInitializer); + try ch.writeAll(";\n "); break :result .{ .local = decl_c_value.new_local }; } else .{ .constant = val }; @@ -504,7 +517,7 @@ pub const Function = struct { return result; } - fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void { + fn writeCValue(f: *Function, w: *Writer, c_value: CValue, location: ValueRenderLocation) !void { switch (c_value) { .none => unreachable, .new_local, .local => |i| try w.print("t{d}", .{i}), @@ -517,7 +530,7 @@ pub const Function = struct { } } - fn writeCValueDeref(f: *Function, w: anytype, c_value: CValue) !void { + fn writeCValueDeref(f: *Function, w: *Writer, c_value: CValue) !void { switch (c_value) { .none => unreachable, .new_local, .local, .constant => { @@ -538,41 +551,41 @@ pub const Function = struct { fn writeCValueMember( f: *Function, - writer: anytype, + w: *Writer, c_value: CValue, member: CValue, - ) error{ OutOfMemory, AnalysisFail }!void { + ) Error!void { switch (c_value) { .new_local, .local, .local_ref, .constant, .arg, .arg_array => { - try f.writeCValue(writer, c_value, .Other); - try writer.writeByte('.'); - try f.writeCValue(writer, member, .Other); + try f.writeCValue(w, c_value, .Other); + try w.writeByte('.'); + try f.writeCValue(w, member, .Other); }, - else => return f.object.dg.writeCValueMember(writer, c_value, member), + else => return f.object.dg.writeCValueMember(w, c_value, member), } } - fn writeCValueDerefMember(f: *Function, writer: anytype, c_value: CValue, member: CValue) !void { + fn writeCValueDerefMember(f: *Function, w: *Writer, c_value: CValue, member: CValue) !void { switch (c_value) { .new_local, .local, .arg, .arg_array => { - try f.writeCValue(writer, c_value, .Other); - try writer.writeAll("->"); + try f.writeCValue(w, c_value, .Other); + try w.writeAll("->"); }, .constant => { - try writer.writeByte('('); - try f.writeCValue(writer, c_value, .Other); - try writer.writeAll(")->"); + try w.writeByte('('); + try f.writeCValue(w, c_value, .Other); + try w.writeAll(")->"); }, .local_ref => { - try f.writeCValueDeref(writer, c_value); - try writer.writeByte('.'); + try f.writeCValueDeref(w, c_value); + try w.writeByte('.'); }, - else => return f.object.dg.writeCValueDerefMember(writer, c_value, member), + else => return f.object.dg.writeCValueDerefMember(w, c_value, member), } - try f.writeCValue(writer, member, .Other); + try f.writeCValue(w, member, .Other); } - fn fail(f: *Function, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { + fn fail(f: *Function, comptime format: []const u8, args: anytype) Error { return f.object.dg.fail(format, args); } @@ -584,20 +597,24 @@ pub const Function = struct { return f.object.dg.byteSize(ctype); } - fn renderType(f: *Function, w: anytype, ctype: Type) !void { + fn renderType(f: *Function, w: *Writer, ctype: Type) !void { return f.object.dg.renderType(w, ctype); } - fn renderCType(f: *Function, w: anytype, ctype: CType) !void { + fn renderCType(f: *Function, w: *Writer, ctype: CType) !void { return f.object.dg.renderCType(w, ctype); } - fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, v: Vectorize, src_ty: Type, location: ValueRenderLocation) !void { + fn renderIntCast(f: *Function, w: *Writer, dest_ty: Type, src: CValue, v: Vectorize, src_ty: Type, location: ValueRenderLocation) !void { return f.object.dg.renderIntCast(w, dest_ty, .{ .c_value = .{ .f = f, .value = src, .v = v } }, src_ty, location); } - fn fmtIntLiteral(f: *Function, val: Value) !std.fmt.Formatter(formatIntLiteral) { - return f.object.dg.fmtIntLiteral(val, .Other); + fn fmtIntLiteralDec(f: *Function, val: Value) !std.fmt.Formatter(FormatIntLiteralContext, formatIntLiteral) { + return f.object.dg.fmtIntLiteralDec(val, .Other); + } + + fn fmtIntLiteralHex(f: *Function, val: Value) !std.fmt.Formatter(FormatIntLiteralContext, formatIntLiteral) { + return f.object.dg.fmtIntLiteralHex(val, .Other); } fn getLazyFnName(f: *Function, key: LazyFnKey) ![]const u8 { @@ -614,16 +631,16 @@ pub const Function = struct { gop.value_ptr.* = .{ .fn_name = switch (key) { .tag_name, - => |enum_ty| try ctype_pool.fmt(gpa, "zig_{s}_{}__{d}", .{ + => |enum_ty| try ctype_pool.fmt(gpa, "zig_{s}_{f}__{d}", .{ @tagName(key), - fmtIdent(ip.loadEnumType(enum_ty).name.toSlice(ip)), + fmtIdentUnsolo(ip.loadEnumType(enum_ty).name.toSlice(ip)), @intFromEnum(enum_ty), }), .never_tail, .never_inline, - => |owner_nav| try ctype_pool.fmt(gpa, "zig_{s}_{}__{d}", .{ + => |owner_nav| try ctype_pool.fmt(gpa, "zig_{s}_{f}__{d}", .{ @tagName(key), - fmtIdent(ip.getNav(owner_nav).name.toSlice(ip)), + fmtIdentUnsolo(ip.getNav(owner_nav).name.toSlice(ip)), @intFromEnum(owner_nav), }), }, @@ -659,12 +676,12 @@ pub const Function = struct { }, else => {}, } - const writer = f.object.writer(); - const a = try Assignment.start(f, writer, ctype); - try f.writeCValue(writer, dst, .Other); - try a.assign(f, writer); - try f.writeCValue(writer, src, .Other); - try a.end(f, writer); + const w = &f.object.code.writer; + const a = try Assignment.start(f, w, ctype); + try f.writeCValue(w, dst, .Other); + try a.assign(f, w); + try f.writeCValue(w, src, .Other); + try a.end(f, w); } fn moveCValue(f: *Function, inst: Air.Inst.Index, ty: Type, src: CValue) !CValue { @@ -693,18 +710,32 @@ pub const Function = struct { /// It is not available when generating .h file. pub const Object = struct { dg: DeclGen, - /// This is a borrowed reference from `link.C`. - code: std.ArrayList(u8), - /// Goes before code. Initialized and deinitialized in `genFunc`. - code_header: std.ArrayList(u8) = undefined, - indent_writer: IndentWriter(std.ArrayList(u8).Writer), - - fn writer(o: *Object) IndentWriter(std.ArrayList(u8).Writer).Writer { - return o.indent_writer.writer(); - } - - fn codeHeaderWriter(o: *Object) ArrayListWriter { - return arrayListWriter(&o.code_header); + code_header: std.io.Writer.Allocating, + code: std.io.Writer.Allocating, + indent_counter: usize, + + const indent_width = 1; + const indent_char = ' '; + + fn newline(o: *Object) !void { + const w = &o.code.writer; + try w.writeByte('\n'); + try w.splatByteAll(indent_char, o.indent_counter); + } + fn indent(o: *Object) void { + o.indent_counter += indent_width; + } + fn outdent(o: *Object) !void { + o.indent_counter -= indent_width; + const written = o.code.getWritten(); + switch (written[written.len - 1]) { + indent_char => o.code.shrinkRetainingCapacity(written.len - indent_width), + '\n' => try o.code.writer.splatByteAll(indent_char, o.indent_counter), + else => { + std.debug.print("\"{f}\"\n", .{std.zig.fmtString(written[written.len -| 100..])}); + unreachable; + }, + } } }; @@ -716,8 +747,7 @@ pub const DeclGen = struct { pass: Pass, is_naked_fn: bool, expected_block: ?u32, - /// This is a borrowed reference from `link.C`. - fwd_decl: std.ArrayList(u8), + fwd_decl: std.io.Writer.Allocating, error_msg: ?*Zcu.ErrorMsg, ctype_pool: CType.Pool, scratch: std.ArrayListUnmanaged(u32), @@ -734,11 +764,7 @@ pub const DeclGen = struct { flush, }; - fn fwdDeclWriter(dg: *DeclGen) ArrayListWriter { - return arrayListWriter(&dg.fwd_decl); - } - - fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { + fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) Error { @branchHint(.cold); const zcu = dg.pt.zcu; const src_loc = zcu.navSrcLoc(dg.pass.nav); @@ -748,10 +774,10 @@ pub const DeclGen = struct { fn renderUav( dg: *DeclGen, - writer: anytype, + w: *Writer, uav: InternPool.Key.Ptr.BaseAddr.Uav, location: ValueRenderLocation, - ) error{ OutOfMemory, AnalysisFail }!void { + ) Error!void { const pt = dg.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -762,14 +788,14 @@ pub const DeclGen = struct { // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. const ptr_ty: Type = .fromInterned(uav.orig_ty); if (ptr_ty.isPtrAtRuntime(zcu) and !uav_ty.isFnOrHasRuntimeBits(zcu)) { - return dg.writeCValue(writer, .{ .undef = ptr_ty }); + return dg.writeCValue(w, .{ .undef = ptr_ty }); } // Chase function values in order to be able to reference the original function. switch (ip.indexToKey(uav.val)) { .variable => unreachable, - .func => |func| return dg.renderNav(writer, func.owner_nav, location), - .@"extern" => |@"extern"| return dg.renderNav(writer, @"extern".owner_nav, location), + .func => |func| return dg.renderNav(w, func.owner_nav, location), + .@"extern" => |@"extern"| return dg.renderNav(w, @"extern".owner_nav, location), else => {}, } @@ -783,13 +809,13 @@ pub const DeclGen = struct { const need_cast = !elem_ctype.eql(uav_ctype) and (elem_ctype.info(ctype_pool) != .function or uav_ctype.info(ctype_pool) != .function); if (need_cast) { - try writer.writeAll("(("); - try dg.renderCType(writer, ptr_ctype); - try writer.writeByte(')'); + try w.writeAll("(("); + try dg.renderCType(w, ptr_ctype); + try w.writeByte(')'); } - try writer.writeByte('&'); - try renderUavName(writer, uav_val); - if (need_cast) try writer.writeByte(')'); + try w.writeByte('&'); + try renderUavName(w, uav_val); + if (need_cast) try w.writeByte(')'); // Indicate that the anon decl should be rendered to the output so that // our reference above is not undefined. @@ -810,10 +836,10 @@ pub const DeclGen = struct { fn renderNav( dg: *DeclGen, - writer: anytype, + w: *Writer, nav_index: InternPool.Nav.Index, location: ValueRenderLocation, - ) error{ OutOfMemory, AnalysisFail }!void { + ) Error!void { _ = location; const pt = dg.pt; const zcu = pt.zcu; @@ -835,7 +861,7 @@ pub const DeclGen = struct { const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).typeOf(ip)); const ptr_ty = try pt.navPtrType(owner_nav); if (!nav_ty.isFnOrHasRuntimeBits(zcu)) { - return dg.writeCValue(writer, .{ .undef = ptr_ty }); + return dg.writeCValue(w, .{ .undef = ptr_ty }); } // We shouldn't cast C function pointers as this is UB (when you call @@ -848,21 +874,21 @@ pub const DeclGen = struct { const need_cast = !elem_ctype.eql(nav_ctype) and (elem_ctype.info(ctype_pool) != .function or nav_ctype.info(ctype_pool) != .function); if (need_cast) { - try writer.writeAll("(("); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeAll("(("); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } - try writer.writeByte('&'); - try dg.renderNavName(writer, owner_nav); - if (need_cast) try writer.writeByte(')'); + try w.writeByte('&'); + try dg.renderNavName(w, owner_nav); + if (need_cast) try w.writeByte(')'); } fn renderPointer( dg: *DeclGen, - writer: anytype, + w: *Writer, derivation: Value.PointerDeriveStep, location: ValueRenderLocation, - ) error{ OutOfMemory, AnalysisFail }!void { + ) Error!void { const pt = dg.pt; const zcu = pt.zcu; switch (derivation) { @@ -870,18 +896,18 @@ pub const DeclGen = struct { .int => |int| { const ptr_ctype = try dg.ctypeFromType(int.ptr_ty, .complete); const addr_val = try pt.intValue(.usize, int.addr); - try writer.writeByte('('); - try dg.renderCType(writer, ptr_ctype); - try writer.print("){x}", .{try dg.fmtIntLiteral(addr_val, .Other)}); + try w.writeByte('('); + try dg.renderCType(w, ptr_ctype); + try w.print("){f}", .{try dg.fmtIntLiteralHex(addr_val, .Other)}); }, - .nav_ptr => |nav| try dg.renderNav(writer, nav, location), - .uav_ptr => |uav| try dg.renderUav(writer, uav, location), + .nav_ptr => |nav| try dg.renderNav(w, nav, location), + .uav_ptr => |uav| try dg.renderUav(w, uav, location), inline .eu_payload_ptr, .opt_payload_ptr => |info| { - try writer.writeAll("&("); - try dg.renderPointer(writer, info.parent.*, location); - try writer.writeAll(")->payload"); + try w.writeAll("&("); + try dg.renderPointer(w, info.parent.*, location); + try w.writeAll(")->payload"); }, .field_ptr => |field| { @@ -893,26 +919,26 @@ pub const DeclGen = struct { switch (fieldLocation(parent_ptr_ty, field.result_ptr_ty, field.field_idx, pt)) { .begin => { const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete); - try writer.writeByte('('); - try dg.renderCType(writer, ptr_ctype); - try writer.writeByte(')'); - try dg.renderPointer(writer, field.parent.*, location); + try w.writeByte('('); + try dg.renderCType(w, ptr_ctype); + try w.writeByte(')'); + try dg.renderPointer(w, field.parent.*, location); }, .field => |name| { - try writer.writeAll("&("); - try dg.renderPointer(writer, field.parent.*, location); - try writer.writeAll(")->"); - try dg.writeCValue(writer, name); + try w.writeAll("&("); + try dg.renderPointer(w, field.parent.*, location); + try w.writeAll(")->"); + try dg.writeCValue(w, name); }, .byte_offset => |byte_offset| { const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete); - try writer.writeByte('('); - try dg.renderCType(writer, ptr_ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ptr_ctype); + try w.writeByte(')'); const offset_val = try pt.intValue(.usize, byte_offset); - try writer.writeAll("((char *)"); - try dg.renderPointer(writer, field.parent.*, location); - try writer.print(" + {})", .{try dg.fmtIntLiteral(offset_val, .Other)}); + try w.writeAll("((char *)"); + try dg.renderPointer(w, field.parent.*, location); + try w.print(" + {f})", .{try dg.fmtIntLiteralDec(offset_val, .Other)}); }, } }, @@ -920,10 +946,10 @@ pub const DeclGen = struct { .elem_ptr => |elem| if (!(try elem.parent.ptrType(pt)).childType(zcu).hasRuntimeBits(zcu)) { // Element type is zero-bit, so lowers to `void`. The index is irrelevant; just cast the pointer. const ptr_ctype = try dg.ctypeFromType(elem.result_ptr_ty, .complete); - try writer.writeByte('('); - try dg.renderCType(writer, ptr_ctype); - try writer.writeByte(')'); - try dg.renderPointer(writer, elem.parent.*, location); + try w.writeByte('('); + try dg.renderCType(w, ptr_ctype); + try w.writeByte(')'); + try dg.renderPointer(w, elem.parent.*, location); } else { const index_val = try pt.intValue(.usize, elem.elem_idx); // We want to do pointer arithmetic on a pointer to the element type. @@ -932,48 +958,47 @@ pub const DeclGen = struct { const parent_ctype = try dg.ctypeFromType(try elem.parent.ptrType(pt), .complete); if (result_ctype.eql(parent_ctype)) { // The pointer already has an appropriate type - just do the arithmetic. - try writer.writeByte('('); - try dg.renderPointer(writer, elem.parent.*, location); - try writer.print(" + {})", .{try dg.fmtIntLiteral(index_val, .Other)}); + try w.writeByte('('); + try dg.renderPointer(w, elem.parent.*, location); + try w.print(" + {f})", .{try dg.fmtIntLiteralDec(index_val, .Other)}); } else { // We probably have an array pointer `T (*)[n]`. Cast to an element pointer, // and *then* apply the index. - try writer.writeAll("(("); - try dg.renderCType(writer, result_ctype); - try writer.writeByte(')'); - try dg.renderPointer(writer, elem.parent.*, location); - try writer.print(" + {})", .{try dg.fmtIntLiteral(index_val, .Other)}); + try w.writeAll("(("); + try dg.renderCType(w, result_ctype); + try w.writeByte(')'); + try dg.renderPointer(w, elem.parent.*, location); + try w.print(" + {f})", .{try dg.fmtIntLiteralDec(index_val, .Other)}); } }, .offset_and_cast => |oac| { const ptr_ctype = try dg.ctypeFromType(oac.new_ptr_ty, .complete); - try writer.writeByte('('); - try dg.renderCType(writer, ptr_ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ptr_ctype); + try w.writeByte(')'); if (oac.byte_offset == 0) { - try dg.renderPointer(writer, oac.parent.*, location); + try dg.renderPointer(w, oac.parent.*, location); } else { const offset_val = try pt.intValue(.usize, oac.byte_offset); - try writer.writeAll("((char *)"); - try dg.renderPointer(writer, oac.parent.*, location); - try writer.print(" + {})", .{try dg.fmtIntLiteral(offset_val, .Other)}); + try w.writeAll("((char *)"); + try dg.renderPointer(w, oac.parent.*, location); + try w.print(" + {f})", .{try dg.fmtIntLiteralDec(offset_val, .Other)}); } }, } } - fn renderErrorName(dg: *DeclGen, writer: anytype, err_name: InternPool.NullTerminatedString) !void { - const ip = &dg.pt.zcu.intern_pool; - try writer.print("zig_error_{}", .{fmtIdent(err_name.toSlice(ip))}); + fn renderErrorName(dg: *DeclGen, w: *Writer, err_name: InternPool.NullTerminatedString) !void { + try w.print("zig_error_{f}", .{fmtIdentUnsolo(err_name.toSlice(&dg.pt.zcu.intern_pool))}); } fn renderValue( dg: *DeclGen, - writer: anytype, + w: *Writer, val: Value, location: ValueRenderLocation, - ) error{ OutOfMemory, AnalysisFail }!void { + ) Error!void { const pt = dg.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -986,7 +1011,7 @@ pub const DeclGen = struct { }; const ty = val.typeOf(zcu); - if (val.isUndefDeep(zcu)) return dg.renderUndefValue(writer, ty, location); + if (val.isUndefDeep(zcu)) return dg.renderUndefValue(w, ty, location); const ctype = try dg.ctypeFromType(ty, location.toCTypeKind()); switch (ip.indexToKey(val.toIntern())) { // types, not values @@ -1019,8 +1044,8 @@ pub const DeclGen = struct { .empty_tuple => unreachable, .@"unreachable" => unreachable, - .false => try writer.writeAll("false"), - .true => try writer.writeAll("true"), + .false => try w.writeAll("false"), + .true => try w.writeAll("true"), }, .variable, .@"extern", @@ -1029,45 +1054,45 @@ pub const DeclGen = struct { .empty_enum_value, => unreachable, // non-runtime values .int => |int| switch (int.storage) { - .u64, .i64, .big_int => try writer.print("{}", .{try dg.fmtIntLiteral(val, location)}), + .u64, .i64, .big_int => try w.print("{f}", .{try dg.fmtIntLiteralDec(val, location)}), .lazy_align, .lazy_size => { - try writer.writeAll("(("); - try dg.renderCType(writer, ctype); - try writer.print("){x})", .{try dg.fmtIntLiteral( + try w.writeAll("(("); + try dg.renderCType(w, ctype); + try w.print("){f})", .{try dg.fmtIntLiteralHex( try pt.intValue(.usize, val.toUnsignedInt(zcu)), .Other, )}); }, }, - .err => |err| try dg.renderErrorName(writer, err.name), + .err => |err| try dg.renderErrorName(w, err.name), .error_union => |error_union| switch (ctype.info(ctype_pool)) { .basic => switch (error_union.val) { - .err_name => |err_name| try dg.renderErrorName(writer, err_name), - .payload => try writer.writeAll("0"), + .err_name => |err_name| try dg.renderErrorName(w, err_name), + .payload => try w.writeByte('0'), }, .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable, .aggregate => |aggregate| { if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } - try writer.writeByte('{'); + try w.writeByte('{'); for (0..aggregate.fields.len) |field_index| { - if (field_index > 0) try writer.writeByte(','); + if (field_index > 0) try w.writeByte(','); switch (aggregate.fields.at(field_index, ctype_pool).name.index) { .@"error" => switch (error_union.val) { - .err_name => |err_name| try dg.renderErrorName(writer, err_name), - .payload => try writer.writeByte('0'), + .err_name => |err_name| try dg.renderErrorName(w, err_name), + .payload => try w.writeByte('0'), }, .payload => switch (error_union.val) { .err_name => try dg.renderUndefValue( - writer, + w, ty.errorUnionPayload(zcu), initializer_type, ), .payload => |payload| try dg.renderValue( - writer, + w, Value.fromInterned(payload), initializer_type, ), @@ -1075,10 +1100,10 @@ pub const DeclGen = struct { else => unreachable, } } - try writer.writeByte('}'); + try w.writeByte('}'); }, }, - .enum_tag => |enum_tag| try dg.renderValue(writer, Value.fromInterned(enum_tag.int), location), + .enum_tag => |enum_tag| try dg.renderValue(w, Value.fromInterned(enum_tag.int), location), .float => { const bits = ty.floatBits(target); const f128_val = val.toFloat(f128, zcu); @@ -1105,18 +1130,18 @@ pub const DeclGen = struct { var empty = true; if (std.math.isFinite(f128_val)) { - try writer.writeAll("zig_make_"); - try dg.renderTypeForBuiltinFnName(writer, ty); - try writer.writeByte('('); + try w.writeAll("zig_make_"); + try dg.renderTypeForBuiltinFnName(w, ty); + try w.writeByte('('); switch (bits) { - 16 => try writer.print("{x}", .{val.toFloat(f16, zcu)}), - 32 => try writer.print("{x}", .{val.toFloat(f32, zcu)}), - 64 => try writer.print("{x}", .{val.toFloat(f64, zcu)}), - 80 => try writer.print("{x}", .{val.toFloat(f80, zcu)}), - 128 => try writer.print("{x}", .{f128_val}), + 16 => try w.print("{x}", .{val.toFloat(f16, zcu)}), + 32 => try w.print("{x}", .{val.toFloat(f32, zcu)}), + 64 => try w.print("{x}", .{val.toFloat(f64, zcu)}), + 80 => try w.print("{x}", .{val.toFloat(f80, zcu)}), + 128 => try w.print("{x}", .{f128_val}), else => unreachable, } - try writer.writeAll(", "); + try w.writeAll(", "); empty = false; } else { // isSignalNan is equivalent to isNan currently, and MSVC doesn't have nans, so prefer nan @@ -1140,45 +1165,45 @@ pub const DeclGen = struct { // return dg.fail("Only quiet nans are supported in global variable initializers", .{}); } - try writer.writeAll("zig_"); - try writer.writeAll(if (location == .StaticInitializer) "init" else "make"); - try writer.writeAll("_special_"); - try dg.renderTypeForBuiltinFnName(writer, ty); - try writer.writeByte('('); - if (std.math.signbit(f128_val)) try writer.writeByte('-'); - try writer.writeAll(", "); - try writer.writeAll(operation); - try writer.writeAll(", "); + try w.writeAll("zig_"); + try w.writeAll(if (location == .StaticInitializer) "init" else "make"); + try w.writeAll("_special_"); + try dg.renderTypeForBuiltinFnName(w, ty); + try w.writeByte('('); + if (std.math.signbit(f128_val)) try w.writeByte('-'); + try w.writeAll(", "); + try w.writeAll(operation); + try w.writeAll(", "); if (std.math.isNan(f128_val)) switch (bits) { // We only actually need to pass the significand, but it will get // properly masked anyway, so just pass the whole value. - 16 => try writer.print("\"0x{x}\"", .{@as(u16, @bitCast(val.toFloat(f16, zcu)))}), - 32 => try writer.print("\"0x{x}\"", .{@as(u32, @bitCast(val.toFloat(f32, zcu)))}), - 64 => try writer.print("\"0x{x}\"", .{@as(u64, @bitCast(val.toFloat(f64, zcu)))}), - 80 => try writer.print("\"0x{x}\"", .{@as(u80, @bitCast(val.toFloat(f80, zcu)))}), - 128 => try writer.print("\"0x{x}\"", .{@as(u128, @bitCast(f128_val))}), + 16 => try w.print("\"0x{x}\"", .{@as(u16, @bitCast(val.toFloat(f16, zcu)))}), + 32 => try w.print("\"0x{x}\"", .{@as(u32, @bitCast(val.toFloat(f32, zcu)))}), + 64 => try w.print("\"0x{x}\"", .{@as(u64, @bitCast(val.toFloat(f64, zcu)))}), + 80 => try w.print("\"0x{x}\"", .{@as(u80, @bitCast(val.toFloat(f80, zcu)))}), + 128 => try w.print("\"0x{x}\"", .{@as(u128, @bitCast(f128_val))}), else => unreachable, }; - try writer.writeAll(", "); + try w.writeAll(", "); empty = false; } - try writer.print("{x}", .{try dg.fmtIntLiteral( + try w.print("{f}", .{try dg.fmtIntLiteralHex( try pt.intValue_big(repr_ty, repr_val_big.toConst()), location, )}); - if (!empty) try writer.writeByte(')'); + if (!empty) try w.writeByte(')'); }, .slice => |slice| { const aggregate = ctype.info(ctype_pool).aggregate; if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } - try writer.writeByte('{'); + try w.writeByte('{'); for (0..aggregate.fields.len) |field_index| { - if (field_index > 0) try writer.writeByte(','); - try dg.renderValue(writer, Value.fromInterned( + if (field_index > 0) try w.writeByte(','); + try dg.renderValue(w, Value.fromInterned( switch (aggregate.fields.at(field_index, ctype_pool).name.index) { .ptr => slice.ptr, .len => slice.len, @@ -1186,33 +1211,33 @@ pub const DeclGen = struct { }, ), initializer_type); } - try writer.writeByte('}'); + try w.writeByte('}'); }, .ptr => { var arena = std.heap.ArenaAllocator.init(zcu.gpa); defer arena.deinit(); const derivation = try val.pointerDerivation(arena.allocator(), pt); - try dg.renderPointer(writer, derivation, location); + try dg.renderPointer(w, derivation, location); }, .opt => |opt| switch (ctype.info(ctype_pool)) { - .basic => if (ctype.isBool()) try writer.writeAll(switch (opt.val) { + .basic => if (ctype.isBool()) try w.writeAll(switch (opt.val) { .none => "true", else => "false", }) else switch (opt.val) { - .none => try writer.writeAll("0"), + .none => try w.writeByte('0'), else => |payload| switch (ip.indexToKey(payload)) { .undef => |err_ty| try dg.renderUndefValue( - writer, + w, .fromInterned(err_ty), location, ), - .err => |err| try dg.renderErrorName(writer, err.name), + .err => |err| try dg.renderErrorName(w, err.name), else => unreachable, }, }, .pointer => switch (opt.val) { - .none => try writer.writeAll("NULL"), - else => |payload| try dg.renderValue(writer, Value.fromInterned(payload), location), + .none => try w.writeAll("NULL"), + else => |payload| try dg.renderValue(w, Value.fromInterned(payload), location), }, .aligned, .array, .vector, .fwd_decl, .function => unreachable, .aggregate => |aggregate| { @@ -1221,7 +1246,7 @@ pub const DeclGen = struct { else => |payload| switch (aggregate.fields.at(0, ctype_pool).name.index) { .is_null, .payload => {}, .ptr, .len => return dg.renderValue( - writer, + w, Value.fromInterned(payload), location, ), @@ -1229,48 +1254,48 @@ pub const DeclGen = struct { }, } if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } - try writer.writeByte('{'); + try w.writeByte('{'); for (0..aggregate.fields.len) |field_index| { - if (field_index > 0) try writer.writeByte(','); + if (field_index > 0) try w.writeByte(','); switch (aggregate.fields.at(field_index, ctype_pool).name.index) { - .is_null => try writer.writeAll(switch (opt.val) { + .is_null => try w.writeAll(switch (opt.val) { .none => "true", else => "false", }), .payload => switch (opt.val) { .none => try dg.renderUndefValue( - writer, + w, ty.optionalChild(zcu), initializer_type, ), else => |payload| try dg.renderValue( - writer, + w, Value.fromInterned(payload), initializer_type, ), }, - .ptr => try writer.writeAll("NULL"), - .len => try dg.renderUndefValue(writer, .usize, initializer_type), + .ptr => try w.writeAll("NULL"), + .len => try dg.renderUndefValue(w, .usize, initializer_type), else => unreachable, } } - try writer.writeByte('}'); + try w.writeByte('}'); }, }, .aggregate => switch (ip.indexToKey(ty.toIntern())) { .array_type, .vector_type => { if (location == .FunctionArgument) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } const ai = ty.arrayInfo(zcu); if (ai.elem_type.eql(.u8, zcu)) { - var literal = stringLiteral(writer, ty.arrayLenIncludingSentinel(zcu)); + var literal: StringLiteral = .init(w, @intCast(ty.arrayLenIncludingSentinel(zcu))); try literal.start(); var index: usize = 0; while (index < ai.len) : (index += 1) { @@ -1287,28 +1312,28 @@ pub const DeclGen = struct { } try literal.end(); } else { - try writer.writeByte('{'); + try w.writeByte('{'); var index: usize = 0; while (index < ai.len) : (index += 1) { - if (index != 0) try writer.writeByte(','); + if (index != 0) try w.writeByte(','); const elem_val = try val.elemValue(pt, index); - try dg.renderValue(writer, elem_val, initializer_type); + try dg.renderValue(w, elem_val, initializer_type); } if (ai.sentinel) |s| { - if (index != 0) try writer.writeByte(','); - try dg.renderValue(writer, s, initializer_type); + if (index != 0) try w.writeByte(','); + try dg.renderValue(w, s, initializer_type); } - try writer.writeByte('}'); + try w.writeByte('}'); } }, .tuple_type => |tuple| { if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } - try writer.writeByte('{'); + try w.writeByte('{'); var empty = true; for (0..tuple.types.len) |field_index| { const comptime_val = tuple.values.get(ip)[field_index]; @@ -1316,7 +1341,7 @@ pub const DeclGen = struct { const field_ty: Type = .fromInterned(tuple.types.get(ip)[field_index]); if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; - if (!empty) try writer.writeByte(','); + if (!empty) try w.writeByte(','); const field_val = Value.fromInterned( switch (ip.indexToKey(val.toIntern()).aggregate.storage) { @@ -1328,30 +1353,30 @@ pub const DeclGen = struct { .repeated_elem => |elem| elem, }, ); - try dg.renderValue(writer, field_val, initializer_type); + try dg.renderValue(w, field_val, initializer_type); empty = false; } - try writer.writeByte('}'); + try w.writeByte('}'); }, .struct_type => { const loaded_struct = ip.loadStructType(ty.toIntern()); switch (loaded_struct.layout) { .auto, .@"extern" => { if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } - try writer.writeByte('{'); + try w.writeByte('{'); var field_it = loaded_struct.iterateRuntimeOrder(ip); var need_comma = false; while (field_it.next()) |field_index| { const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; - if (need_comma) try writer.writeByte(','); + if (need_comma) try w.writeByte(','); need_comma = true; const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) { .bytes => |bytes| try pt.intern(.{ .int = .{ @@ -1361,9 +1386,9 @@ pub const DeclGen = struct { .elems => |elems| elems[field_index], .repeated_elem => |elem| elem, }; - try dg.renderValue(writer, Value.fromInterned(field_val), initializer_type); + try dg.renderValue(w, Value.fromInterned(field_val), initializer_type); } - try writer.writeByte('}'); + try w.writeByte('}'); }, .@"packed" => { const int_info = ty.intInfo(zcu); @@ -1381,16 +1406,16 @@ pub const DeclGen = struct { } if (eff_num_fields == 0) { - try writer.writeByte('('); - try dg.renderUndefValue(writer, ty, location); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderUndefValue(w, ty, location); + try w.writeByte(')'); } else if (ty.bitSize(zcu) > 64) { // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off)) var num_or = eff_num_fields - 1; while (num_or > 0) : (num_or -= 1) { - try writer.writeAll("zig_or_"); - try dg.renderTypeForBuiltinFnName(writer, ty); - try writer.writeByte('('); + try w.writeAll("zig_or_"); + try dg.renderTypeForBuiltinFnName(w, ty); + try w.writeByte('('); } var eff_index: usize = 0; @@ -1409,36 +1434,36 @@ pub const DeclGen = struct { }; const cast_context = IntCastContext{ .value = .{ .value = Value.fromInterned(field_val) } }; if (bit_offset != 0) { - try writer.writeAll("zig_shl_"); - try dg.renderTypeForBuiltinFnName(writer, ty); - try writer.writeByte('('); - try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument); - try writer.writeAll(", "); - try dg.renderValue(writer, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument); - try writer.writeByte(')'); + try w.writeAll("zig_shl_"); + try dg.renderTypeForBuiltinFnName(w, ty); + try w.writeByte('('); + try dg.renderIntCast(w, ty, cast_context, field_ty, .FunctionArgument); + try w.writeAll(", "); + try dg.renderValue(w, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument); + try w.writeByte(')'); } else { - try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument); + try dg.renderIntCast(w, ty, cast_context, field_ty, .FunctionArgument); } - if (needs_closing_paren) try writer.writeByte(')'); - if (eff_index != eff_num_fields - 1) try writer.writeAll(", "); + if (needs_closing_paren) try w.writeByte(')'); + if (eff_index != eff_num_fields - 1) try w.writeAll(", "); bit_offset += field_ty.bitSize(zcu); needs_closing_paren = true; eff_index += 1; } } else { - try writer.writeByte('('); + try w.writeByte('('); // a << a_off | b << b_off | c << c_off var empty = true; for (0..loaded_struct.field_types.len) |field_index| { const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; - if (!empty) try writer.writeAll(" | "); - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + if (!empty) try w.writeAll(" | "); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) { .bytes => |bytes| try pt.intern(.{ .int = .{ @@ -1455,24 +1480,24 @@ pub const DeclGen = struct { .{ .signedness = .unsigned, .bits = undefined }; switch (field_int_info.signedness) { .signed => { - try writer.writeByte('('); - try dg.renderValue(writer, Value.fromInterned(field_val), .Other); - try writer.writeAll(" & "); + try w.writeByte('('); + try dg.renderValue(w, Value.fromInterned(field_val), .Other); + try w.writeAll(" & "); const field_uint_ty = try pt.intType(.unsigned, field_int_info.bits); - try dg.renderValue(writer, try field_uint_ty.maxIntScalar(pt, field_uint_ty), .Other); - try writer.writeByte(')'); + try dg.renderValue(w, try field_uint_ty.maxIntScalar(pt, field_uint_ty), .Other); + try w.writeByte(')'); }, - .unsigned => try dg.renderValue(writer, Value.fromInterned(field_val), .Other), + .unsigned => try dg.renderValue(w, Value.fromInterned(field_val), .Other), } if (bit_offset != 0) { - try writer.writeAll(" << "); - try dg.renderValue(writer, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument); + try w.writeAll(" << "); + try dg.renderValue(w, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument); } bit_offset += field_ty.bitSize(zcu); empty = false; } - try writer.writeByte(')'); + try w.writeByte(')'); } }, } @@ -1486,11 +1511,11 @@ pub const DeclGen = struct { switch (loaded_union.flagsUnordered(ip).layout) { .@"packed" => { if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderType(writer, backing_ty); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderType(w, backing_ty); + try w.writeByte(')'); } - try dg.renderValue(writer, Value.fromInterned(un.val), location); + try dg.renderValue(w, Value.fromInterned(un.val), location); }, .@"extern" => { if (location == .StaticInitializer) { @@ -1498,21 +1523,21 @@ pub const DeclGen = struct { } const ptr_ty = try pt.singleConstPtrType(ty); - try writer.writeAll("*(("); - try dg.renderType(writer, ptr_ty); - try writer.writeAll(")("); - try dg.renderType(writer, backing_ty); - try writer.writeAll("){"); - try dg.renderValue(writer, Value.fromInterned(un.val), location); - try writer.writeAll("})"); + try w.writeAll("*(("); + try dg.renderType(w, ptr_ty); + try w.writeAll(")("); + try dg.renderType(w, backing_ty); + try w.writeAll("){"); + try dg.renderValue(w, Value.fromInterned(un.val), location); + try w.writeAll("})"); }, else => unreachable, } } else { if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } const field_index = zcu.unionTagFieldIndex(loaded_union, Value.fromInterned(un.tag)).?; @@ -1521,57 +1546,57 @@ pub const DeclGen = struct { if (loaded_union.flagsUnordered(ip).layout == .@"packed") { if (field_ty.hasRuntimeBits(zcu)) { if (field_ty.isPtrAtRuntime(zcu)) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } else if (field_ty.zigTypeTag(zcu) == .float) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } - try dg.renderValue(writer, Value.fromInterned(un.val), location); - } else try writer.writeAll("0"); + try dg.renderValue(w, Value.fromInterned(un.val), location); + } else try w.writeByte('0'); return; } const has_tag = loaded_union.hasTag(ip); - if (has_tag) try writer.writeByte('{'); + if (has_tag) try w.writeByte('{'); const aggregate = ctype.info(ctype_pool).aggregate; for (0..if (has_tag) aggregate.fields.len else 1) |outer_field_index| { - if (outer_field_index > 0) try writer.writeByte(','); + if (outer_field_index > 0) try w.writeByte(','); switch (if (has_tag) aggregate.fields.at(outer_field_index, ctype_pool).name.index else .payload) { .tag => try dg.renderValue( - writer, + w, Value.fromInterned(un.tag), initializer_type, ), .payload => { - try writer.writeByte('{'); + try w.writeByte('{'); if (field_ty.hasRuntimeBits(zcu)) { - try writer.print(" .{ } = ", .{fmtIdent(field_name.toSlice(ip))}); + try w.print(" .{f} = ", .{fmtIdentSolo(field_name.toSlice(ip))}); try dg.renderValue( - writer, + w, Value.fromInterned(un.val), initializer_type, ); - try writer.writeByte(' '); + try w.writeByte(' '); } else for (0..loaded_union.field_types.len) |inner_field_index| { const inner_field_ty: Type = .fromInterned( loaded_union.field_types.get(ip)[inner_field_index], ); if (!inner_field_ty.hasRuntimeBits(zcu)) continue; - try dg.renderUndefValue(writer, inner_field_ty, initializer_type); + try dg.renderUndefValue(w, inner_field_ty, initializer_type); break; } - try writer.writeByte('}'); + try w.writeByte('}'); }, else => unreachable, } } - if (has_tag) try writer.writeByte('}'); + if (has_tag) try w.writeByte('}'); } }, } @@ -1579,10 +1604,10 @@ pub const DeclGen = struct { fn renderUndefValue( dg: *DeclGen, - writer: anytype, + w: *Writer, ty: Type, location: ValueRenderLocation, - ) error{ OutOfMemory, AnalysisFail }!void { + ) Error!void { const pt = dg.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -1612,57 +1637,57 @@ pub const DeclGen = struct { // All unsigned ints matching float types are pre-allocated. const repr_ty = dg.pt.intType(.unsigned, bits) catch unreachable; - try writer.writeAll("zig_make_"); - try dg.renderTypeForBuiltinFnName(writer, ty); - try writer.writeByte('('); + try w.writeAll("zig_make_"); + try dg.renderTypeForBuiltinFnName(w, ty); + try w.writeByte('('); switch (bits) { - 16 => try writer.print("{x}", .{@as(f16, @bitCast(undefPattern(i16)))}), - 32 => try writer.print("{x}", .{@as(f32, @bitCast(undefPattern(i32)))}), - 64 => try writer.print("{x}", .{@as(f64, @bitCast(undefPattern(i64)))}), - 80 => try writer.print("{x}", .{@as(f80, @bitCast(undefPattern(i80)))}), - 128 => try writer.print("{x}", .{@as(f128, @bitCast(undefPattern(i128)))}), + 16 => try w.print("{x}", .{@as(f16, @bitCast(undefPattern(i16)))}), + 32 => try w.print("{x}", .{@as(f32, @bitCast(undefPattern(i32)))}), + 64 => try w.print("{x}", .{@as(f64, @bitCast(undefPattern(i64)))}), + 80 => try w.print("{x}", .{@as(f80, @bitCast(undefPattern(i80)))}), + 128 => try w.print("{x}", .{@as(f128, @bitCast(undefPattern(i128)))}), else => unreachable, } - try writer.writeAll(", "); - try dg.renderUndefValue(writer, repr_ty, .FunctionArgument); - return writer.writeByte(')'); + try w.writeAll(", "); + try dg.renderUndefValue(w, repr_ty, .FunctionArgument); + return w.writeByte(')'); }, - .bool_type => try writer.writeAll(if (safety_on) "0xaa" else "false"), + .bool_type => try w.writeAll(if (safety_on) "0xaa" else "false"), else => switch (ip.indexToKey(ty.toIntern())) { .simple_type, .int_type, .enum_type, .error_set_type, .inferred_error_set_type, - => return writer.print("{x}", .{ - try dg.fmtIntLiteral(try pt.undefValue(ty), location), + => return w.print("{f}", .{ + try dg.fmtIntLiteralHex(try pt.undefValue(ty), location), }), .ptr_type => |ptr_type| switch (ptr_type.flags.size) { .one, .many, .c => { - try writer.writeAll("(("); - try dg.renderCType(writer, ctype); - return writer.print("){x})", .{ - try dg.fmtIntLiteral(.undef_usize, .Other), + try w.writeAll("(("); + try dg.renderCType(w, ctype); + return w.print("){f})", .{ + try dg.fmtIntLiteralHex(.undef_usize, .Other), }); }, .slice => { if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } - try writer.writeAll("{("); + try w.writeAll("{("); const ptr_ty = ty.slicePtrFieldType(zcu); - try dg.renderType(writer, ptr_ty); - return writer.print("){x}, {0x}}}", .{ - try dg.fmtIntLiteral(.undef_usize, .Other), + try dg.renderType(w, ptr_ty); + return w.print("){f}, {0f}}}", .{ + try dg.fmtIntLiteralHex(.undef_usize, .Other), }); }, }, .opt_type => |child_type| switch (ctype.info(ctype_pool)) { .basic, .pointer => try dg.renderUndefValue( - writer, + w, .fromInterned(if (ctype.isBool()) .bool_type else child_type), location, ), @@ -1671,21 +1696,21 @@ pub const DeclGen = struct { switch (aggregate.fields.at(0, ctype_pool).name.index) { .is_null, .payload => {}, .ptr, .len => return dg.renderUndefValue( - writer, + w, .fromInterned(child_type), location, ), else => unreachable, } if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } - try writer.writeByte('{'); + try w.writeByte('{'); for (0..aggregate.fields.len) |field_index| { - if (field_index > 0) try writer.writeByte(','); - try dg.renderUndefValue(writer, .fromInterned( + if (field_index > 0) try w.writeByte(','); + try dg.renderUndefValue(w, .fromInterned( switch (aggregate.fields.at(field_index, ctype_pool).name.index) { .is_null => .bool_type, .payload => child_type, @@ -1693,7 +1718,7 @@ pub const DeclGen = struct { }, ), initializer_type); } - try writer.writeByte('}'); + try w.writeByte('}'); }, }, .struct_type => { @@ -1701,117 +1726,117 @@ pub const DeclGen = struct { switch (loaded_struct.layout) { .auto, .@"extern" => { if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } - try writer.writeByte('{'); + try w.writeByte('{'); var field_it = loaded_struct.iterateRuntimeOrder(ip); var need_comma = false; while (field_it.next()) |field_index| { const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; - if (need_comma) try writer.writeByte(','); + if (need_comma) try w.writeByte(','); need_comma = true; - try dg.renderUndefValue(writer, field_ty, initializer_type); + try dg.renderUndefValue(w, field_ty, initializer_type); } - return writer.writeByte('}'); + return w.writeByte('}'); }, - .@"packed" => return writer.print("{x}", .{ - try dg.fmtIntLiteral(try pt.undefValue(ty), .Other), + .@"packed" => return w.print("{f}", .{ + try dg.fmtIntLiteralHex(try pt.undefValue(ty), .Other), }), } }, .tuple_type => |tuple_info| { if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } - try writer.writeByte('{'); + try w.writeByte('{'); var need_comma = false; for (0..tuple_info.types.len) |field_index| { if (tuple_info.values.get(ip)[field_index] != .none) continue; const field_ty: Type = .fromInterned(tuple_info.types.get(ip)[field_index]); if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; - if (need_comma) try writer.writeByte(','); + if (need_comma) try w.writeByte(','); need_comma = true; - try dg.renderUndefValue(writer, field_ty, initializer_type); + try dg.renderUndefValue(w, field_ty, initializer_type); } - return writer.writeByte('}'); + return w.writeByte('}'); }, .union_type => { const loaded_union = ip.loadUnionType(ty.toIntern()); switch (loaded_union.flagsUnordered(ip).layout) { .auto, .@"extern" => { if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } const has_tag = loaded_union.hasTag(ip); - if (has_tag) try writer.writeByte('{'); + if (has_tag) try w.writeByte('{'); const aggregate = ctype.info(ctype_pool).aggregate; for (0..if (has_tag) aggregate.fields.len else 1) |outer_field_index| { - if (outer_field_index > 0) try writer.writeByte(','); + if (outer_field_index > 0) try w.writeByte(','); switch (if (has_tag) aggregate.fields.at(outer_field_index, ctype_pool).name.index else .payload) { .tag => try dg.renderUndefValue( - writer, + w, .fromInterned(loaded_union.enum_tag_ty), initializer_type, ), .payload => { - try writer.writeByte('{'); + try w.writeByte('{'); for (0..loaded_union.field_types.len) |inner_field_index| { const inner_field_ty: Type = .fromInterned( loaded_union.field_types.get(ip)[inner_field_index], ); if (!inner_field_ty.hasRuntimeBits(pt.zcu)) continue; try dg.renderUndefValue( - writer, + w, inner_field_ty, initializer_type, ); break; } - try writer.writeByte('}'); + try w.writeByte('}'); }, else => unreachable, } } - if (has_tag) try writer.writeByte('}'); + if (has_tag) try w.writeByte('}'); }, - .@"packed" => return writer.print("{x}", .{ - try dg.fmtIntLiteral(try pt.undefValue(ty), .Other), + .@"packed" => return w.print("{f}", .{ + try dg.fmtIntLiteralHex(try pt.undefValue(ty), .Other), }), } }, .error_union_type => |error_union_type| switch (ctype.info(ctype_pool)) { .basic => try dg.renderUndefValue( - writer, + w, .fromInterned(error_union_type.error_set_type), location, ), .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable, .aggregate => |aggregate| { if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } - try writer.writeByte('{'); + try w.writeByte('{'); for (0..aggregate.fields.len) |field_index| { - if (field_index > 0) try writer.writeByte(','); + if (field_index > 0) try w.writeByte(','); try dg.renderUndefValue( - writer, + w, .fromInterned( switch (aggregate.fields.at(field_index, ctype_pool).name.index) { .@"error" => error_union_type.error_set_type, @@ -1822,14 +1847,14 @@ pub const DeclGen = struct { initializer_type, ); } - try writer.writeByte('}'); + try w.writeByte('}'); }, }, .array_type, .vector_type => { const ai = ty.arrayInfo(zcu); if (ai.elem_type.eql(.u8, zcu)) { const c_len = ty.arrayLenIncludingSentinel(zcu); - var literal = stringLiteral(writer, c_len); + var literal: StringLiteral = .init(w, @intCast(c_len)); try literal.start(); var index: u64 = 0; while (index < c_len) : (index += 1) @@ -1837,19 +1862,19 @@ pub const DeclGen = struct { return literal.end(); } else { if (!location.isInitializer()) { - try writer.writeByte('('); - try dg.renderCType(writer, ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try dg.renderCType(w, ctype); + try w.writeByte(')'); } - try writer.writeByte('{'); + try w.writeByte('{'); const c_len = ty.arrayLenIncludingSentinel(zcu); var index: u64 = 0; while (index < c_len) : (index += 1) { - if (index > 0) try writer.writeAll(", "); - try dg.renderUndefValue(writer, ty.childType(zcu), initializer_type); + if (index > 0) try w.writeAll(", "); + try dg.renderUndefValue(w, ty.childType(zcu), initializer_type); } - return writer.writeByte('}'); + return w.writeByte('}'); } }, .anyframe_type, @@ -1882,13 +1907,13 @@ pub const DeclGen = struct { fn renderFunctionSignature( dg: *DeclGen, - w: anytype, + w: *Writer, fn_val: Value, fn_align: InternPool.Alignment, kind: CType.Kind, name: union(enum) { nav: InternPool.Nav.Index, - fmt_ctype_pool_string: std.fmt.Formatter(formatCTypePoolString), + fmt_ctype_pool_string: std.fmt.Formatter(CTypePoolStringFormatData, formatCTypePoolString), @"export": struct { main_name: InternPool.NullTerminatedString, extern_name: InternPool.NullTerminatedString, @@ -1925,15 +1950,15 @@ pub const DeclGen = struct { var trailing = try renderTypePrefix(dg.pass, &dg.ctype_pool, zcu, w, fn_ctype, .suffix, .{}); if (toCallingConvention(fn_info.cc, zcu)) |call_conv| { - try w.print("{}zig_callconv({s})", .{ trailing, call_conv }); + try w.print("{f}zig_callconv({s})", .{ trailing, call_conv }); trailing = .maybe_space; } - try w.print("{}", .{trailing}); + try w.print("{f}", .{trailing}); switch (name) { .nav => |nav| try dg.renderNavName(w, nav), - .fmt_ctype_pool_string => |fmt| try w.print("{ }", .{fmt}), - .@"export" => |@"export"| try w.print("{ }", .{fmtIdent(@"export".extern_name.toSlice(ip))}), + .fmt_ctype_pool_string => |fmt| try w.print("{f}", .{fmt}), + .@"export" => |@"export"| try w.print("{f}", .{fmtIdentSolo(@"export".extern_name.toSlice(ip))}), } try renderTypeSuffix( @@ -1960,17 +1985,17 @@ pub const DeclGen = struct { const is_mangled = isMangledIdent(extern_name, true); const is_export = @"export".extern_name != @"export".main_name; if (is_mangled and is_export) { - try w.print(" zig_mangled_export({ }, {s}, {s})", .{ - fmtIdent(extern_name), + try w.print(" zig_mangled_export({f}, {f}, {f})", .{ + fmtIdentSolo(extern_name), fmtStringLiteral(extern_name, null), fmtStringLiteral(@"export".main_name.toSlice(ip), null), }); } else if (is_mangled) { - try w.print(" zig_mangled({ }, {s})", .{ - fmtIdent(extern_name), fmtStringLiteral(extern_name, null), + try w.print(" zig_mangled({f}, {f})", .{ + fmtIdentSolo(extern_name), fmtStringLiteral(extern_name, null), }); } else if (is_export) { - try w.print(" zig_export({s}, {s})", .{ + try w.print(" zig_export({f}, {f})", .{ fmtStringLiteral(@"export".main_name.toSlice(ip), null), fmtStringLiteral(extern_name, null), }); @@ -2003,11 +2028,11 @@ pub const DeclGen = struct { /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | /// | `renderType` | "uint8_t *" | "uint8_t *[10]" | /// - fn renderType(dg: *DeclGen, w: anytype, t: Type) error{OutOfMemory}!void { + fn renderType(dg: *DeclGen, w: *Writer, t: Type) Error!void { try dg.renderCType(w, try dg.ctypeFromType(t, .complete)); } - fn renderCType(dg: *DeclGen, w: anytype, ctype: CType) error{OutOfMemory}!void { + fn renderCType(dg: *DeclGen, w: *Writer, ctype: CType) Error!void { _ = try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.pt.zcu, w, ctype, .suffix, .{}); try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.pt.zcu, w, ctype, .suffix, .{}); } @@ -2022,7 +2047,7 @@ pub const DeclGen = struct { value: Value, }, - pub fn writeValue(self: *const IntCastContext, dg: *DeclGen, w: anytype, location: ValueRenderLocation) !void { + pub fn writeValue(self: *const IntCastContext, dg: *DeclGen, w: *Writer, location: ValueRenderLocation) !void { switch (self.*) { .c_value => |v| { try v.f.writeCValue(w, v.value, location); @@ -2068,7 +2093,7 @@ pub const DeclGen = struct { /// | > 64 bit integer | > 64 bit integer | zig_make_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src)) fn renderIntCast( dg: *DeclGen, - w: anytype, + w: *Writer, dest_ty: Type, context: IntCastContext, src_ty: Type, @@ -2118,7 +2143,7 @@ pub const DeclGen = struct { } else if (dest_bits > 64 and src_bits <= 64) { try w.writeAll("zig_make_"); try dg.renderTypeForBuiltinFnName(w, dest_ty); - try w.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral? + try w.writeAll("(0, "); if (src_is_ptr) { try w.writeByte('('); try dg.renderType(w, src_eff_ty); @@ -2152,13 +2177,13 @@ pub const DeclGen = struct { /// fn renderTypeAndName( dg: *DeclGen, - w: anytype, + w: *Writer, ty: Type, name: CValue, qualifiers: CQualifiers, alignment: Alignment, kind: CType.Kind, - ) error{ OutOfMemory, AnalysisFail }!void { + ) !void { try dg.renderCTypeAndName( w, try dg.ctypeFromType(ty, kind), @@ -2173,12 +2198,12 @@ pub const DeclGen = struct { fn renderCTypeAndName( dg: *DeclGen, - w: anytype, + w: *Writer, ctype: CType, name: CValue, qualifiers: CQualifiers, alignas: CType.AlignAs, - ) error{ OutOfMemory, AnalysisFail }!void { + ) !void { const zcu = dg.pt.zcu; switch (alignas.abiOrder()) { .lt => try w.print("zig_under_align({}) ", .{alignas.toByteUnits()}), @@ -2186,24 +2211,24 @@ pub const DeclGen = struct { .gt => try w.print("zig_align({}) ", .{alignas.toByteUnits()}), } - try w.print("{}", .{ + try w.print("{f}", .{ try renderTypePrefix(dg.pass, &dg.ctype_pool, zcu, w, ctype, .suffix, qualifiers), }); try dg.writeName(w, name); try renderTypeSuffix(dg.pass, &dg.ctype_pool, zcu, w, ctype, .suffix, .{}); } - fn writeName(dg: *DeclGen, w: anytype, c_value: CValue) !void { + fn writeName(dg: *DeclGen, w: *Writer, c_value: CValue) !void { switch (c_value) { .new_local, .local => |i| try w.print("t{d}", .{i}), .constant => |uav| try renderUavName(w, uav), .nav => |nav| try dg.renderNavName(w, nav), - .identifier => |ident| try w.print("{ }", .{fmtIdent(ident)}), + .identifier => |ident| try w.print("{f}", .{fmtIdentSolo(ident)}), else => unreachable, } } - fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void { + fn writeCValue(dg: *DeclGen, w: *Writer, c_value: CValue) Error!void { switch (c_value) { .none, .new_local, .local, .local_ref => unreachable, .constant => |uav| try renderUavName(w, uav), @@ -2215,18 +2240,18 @@ pub const DeclGen = struct { try dg.renderNavName(w, nav); }, .undef => |ty| try dg.renderUndefValue(w, ty, .Other), - .identifier => |ident| try w.print("{ }", .{fmtIdent(ident)}), - .payload_identifier => |ident| try w.print("{ }.{ }", .{ - fmtIdent("payload"), - fmtIdent(ident), + .identifier => |ident| try w.print("{f}", .{fmtIdentSolo(ident)}), + .payload_identifier => |ident| try w.print("{f}.{f}", .{ + fmtIdentSolo("payload"), + fmtIdentSolo(ident), }), - .ctype_pool_string => |string| try w.print("{ }", .{ - fmtCTypePoolString(string, &dg.ctype_pool), + .ctype_pool_string => |string| try w.print("{f}", .{ + fmtCTypePoolString(string, &dg.ctype_pool, true), }), } } - fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void { + fn writeCValueDeref(dg: *DeclGen, w: *Writer, c_value: CValue) !void { switch (c_value) { .none, .new_local, @@ -2245,26 +2270,31 @@ pub const DeclGen = struct { }, .nav_ref => |nav| try dg.renderNavName(w, nav), .undef => unreachable, - .identifier => |ident| try w.print("(*{ })", .{fmtIdent(ident)}), - .payload_identifier => |ident| try w.print("(*{ }.{ })", .{ - fmtIdent("payload"), - fmtIdent(ident), + .identifier => |ident| try w.print("(*{f})", .{fmtIdentSolo(ident)}), + .payload_identifier => |ident| try w.print("(*{f}.{f})", .{ + fmtIdentSolo("payload"), + fmtIdentSolo(ident), }), } } fn writeCValueMember( dg: *DeclGen, - writer: anytype, + w: *Writer, c_value: CValue, member: CValue, - ) error{ OutOfMemory, AnalysisFail }!void { - try dg.writeCValue(writer, c_value); - try writer.writeByte('.'); - try dg.writeCValue(writer, member); + ) Error!void { + try dg.writeCValue(w, c_value); + try w.writeByte('.'); + try dg.writeCValue(w, member); } - fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { + fn writeCValueDerefMember( + dg: *DeclGen, + w: *Writer, + c_value: CValue, + member: CValue, + ) !void { switch (c_value) { .none, .new_local, @@ -2278,15 +2308,15 @@ pub const DeclGen = struct { .ctype_pool_string, => unreachable, .nav, .identifier, .payload_identifier => { - try dg.writeCValue(writer, c_value); - try writer.writeAll("->"); + try dg.writeCValue(w, c_value); + try w.writeAll("->"); }, .nav_ref => { - try dg.writeCValueDeref(writer, c_value); - try writer.writeByte('.'); + try dg.writeCValueDeref(w, c_value); + try w.writeByte('.'); }, } - try dg.writeCValue(writer, member); + try dg.writeCValue(w, member); } fn renderFwdDecl( @@ -2302,7 +2332,7 @@ pub const DeclGen = struct { const zcu = dg.pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - const fwd = dg.fwdDeclWriter(); + const fwd = &dg.fwd_decl.writer; try fwd.writeAll(switch (flags.linkage) { .internal => "static ", .strong, .weak, .link_once => "zig_extern ", @@ -2328,36 +2358,36 @@ pub const DeclGen = struct { try fwd.writeAll(";\n"); } - fn renderNavName(dg: *DeclGen, writer: anytype, nav_index: InternPool.Nav.Index) !void { + fn renderNavName(dg: *DeclGen, w: *Writer, nav_index: InternPool.Nav.Index) !void { const zcu = dg.pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); if (nav.getExtern(ip)) |@"extern"| { - try writer.print("{ }", .{ - fmtIdent(ip.getNav(@"extern".owner_nav).name.toSlice(ip)), + try w.print("{f}", .{ + fmtIdentSolo(ip.getNav(@"extern".owner_nav).name.toSlice(ip)), }); } else { // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case), // expand to 3x the length of its input, but let's cut it off at a much shorter limit. const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip); - try writer.print("{}__{d}", .{ - fmtIdent(fqn_slice[0..@min(fqn_slice.len, 100)]), + try w.print("{f}__{d}", .{ + fmtIdentUnsolo(fqn_slice[0..@min(fqn_slice.len, 100)]), @intFromEnum(nav_index), }); } } - fn renderUavName(writer: anytype, uav: Value) !void { - try writer.print("__anon_{d}", .{@intFromEnum(uav.toIntern())}); + fn renderUavName(w: *Writer, uav: Value) !void { + try w.print("__anon_{d}", .{@intFromEnum(uav.toIntern())}); } - fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void { - try dg.renderCTypeForBuiltinFnName(writer, try dg.ctypeFromType(ty, .complete)); + fn renderTypeForBuiltinFnName(dg: *DeclGen, w: *Writer, ty: Type) !void { + try dg.renderCTypeForBuiltinFnName(w, try dg.ctypeFromType(ty, .complete)); } - fn renderCTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ctype: CType) !void { + fn renderCTypeForBuiltinFnName(dg: *DeclGen, w: *Writer, ctype: CType) !void { switch (ctype.info(&dg.ctype_pool)) { - else => |ctype_info| try writer.print("{c}{d}", .{ + else => |ctype_info| try w.print("{c}{d}", .{ if (ctype.isBool()) signAbbrev(.unsigned) else if (ctype.isInteger()) @@ -2370,11 +2400,11 @@ pub const DeclGen = struct { return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for {s} type", .{@tagName(ctype_info)}), if (ctype.isFloat()) ctype.floatActiveBits(dg.mod) else dg.byteSize(ctype) * 8, }), - .array => try writer.writeAll("big"), + .array => try w.writeAll("big"), } } - fn renderBuiltinInfo(dg: *DeclGen, writer: anytype, ty: Type, info: BuiltinInfo) !void { + fn renderBuiltinInfo(dg: *DeclGen, w: *Writer, ty: Type, info: BuiltinInfo) !void { const ctype = try dg.ctypeFromType(ty, .complete); const is_big = ctype.info(&dg.ctype_pool) == .array; switch (info) { @@ -2389,8 +2419,8 @@ pub const DeclGen = struct { .bits = @intCast(ty.bitSize(zcu)), }; - if (is_big) try writer.print(", {}", .{int_info.signedness == .signed}); - try writer.print(", {}", .{try dg.fmtIntLiteral( + if (is_big) try w.print(", {}", .{int_info.signedness == .signed}); + try w.print(", {f}", .{try dg.fmtIntLiteralDec( try pt.intValue(if (is_big) .u16 else .u8, int_info.bits), .FunctionArgument, )}); @@ -2400,18 +2430,38 @@ pub const DeclGen = struct { dg: *DeclGen, val: Value, loc: ValueRenderLocation, - ) !std.fmt.Formatter(formatIntLiteral) { + base: u8, + case: std.fmt.Case, + ) !std.fmt.Formatter(FormatIntLiteralContext, formatIntLiteral) { const zcu = dg.pt.zcu; const kind = loc.toCTypeKind(); const ty = val.typeOf(zcu); - return std.fmt.Formatter(formatIntLiteral){ .data = .{ + return .{ .data = .{ .dg = dg, .int_info = ty.intInfo(zcu), .kind = kind, .ctype = try dg.ctypeFromType(ty, kind), .val = val, + .base = base, + .case = case, } }; } + + fn fmtIntLiteralDec( + dg: *DeclGen, + val: Value, + loc: ValueRenderLocation, + ) !std.fmt.Formatter(FormatIntLiteralContext, formatIntLiteral) { + return fmtIntLiteral(dg, val, loc, 10, .lower); + } + + fn fmtIntLiteralHex( + dg: *DeclGen, + val: Value, + loc: ValueRenderLocation, + ) !std.fmt.Formatter(FormatIntLiteralContext, formatIntLiteral) { + return fmtIntLiteral(dg, val, loc, 16, .lower); + } }; const CTypeFix = enum { prefix, suffix }; @@ -2421,28 +2471,19 @@ const RenderCTypeTrailing = enum { no_space, maybe_space, - pub fn format( - self: @This(), - comptime fmt: []const u8, - _: std.fmt.FormatOptions, - w: anytype, - ) @TypeOf(w).Error!void { - if (fmt.len != 0) - @compileError("invalid format string '" ++ fmt ++ "' for type '" ++ - @typeName(@This()) ++ "'"); - comptime assert(fmt.len == 0); + pub fn format(self: @This(), w: *Writer) Writer.Error!void { switch (self) { .no_space => {}, .maybe_space => try w.writeByte(' '), } } }; -fn renderAlignedTypeName(w: anytype, ctype: CType) !void { +fn renderAlignedTypeName(w: *Writer, ctype: CType) !void { try w.print("anon__aligned_{d}", .{@intFromEnum(ctype.index)}); } fn renderFwdDeclTypeName( zcu: *Zcu, - w: anytype, + w: *Writer, ctype: CType, fwd_decl: CType.Info.FwdDecl, attributes: []const u8, @@ -2451,8 +2492,8 @@ fn renderFwdDeclTypeName( try w.print("{s} {s}", .{ @tagName(fwd_decl.tag), attributes }); switch (fwd_decl.name) { .anon => try w.print("anon__lazy_{d}", .{@intFromEnum(ctype.index)}), - .index => |index| try w.print("{}__{d}", .{ - fmtIdent(Type.fromInterned(index).containerTypeName(ip).toSlice(&zcu.intern_pool)), + .index => |index| try w.print("{f}__{d}", .{ + fmtIdentUnsolo(Type.fromInterned(index).containerTypeName(ip).toSlice(&zcu.intern_pool)), @intFromEnum(index), }), } @@ -2461,17 +2502,17 @@ fn renderTypePrefix( pass: DeclGen.Pass, ctype_pool: *const CType.Pool, zcu: *Zcu, - w: anytype, + w: *Writer, ctype: CType, parent_fix: CTypeFix, qualifiers: CQualifiers, -) @TypeOf(w).Error!RenderCTypeTrailing { +) Writer.Error!RenderCTypeTrailing { var trailing = RenderCTypeTrailing.maybe_space; switch (ctype.info(ctype_pool)) { .basic => |basic_info| try w.writeAll(@tagName(basic_info)), .pointer => |pointer_info| { - try w.print("{}*", .{try renderTypePrefix( + try w.print("{f}*", .{try renderTypePrefix( pass, ctype_pool, zcu, @@ -2508,7 +2549,7 @@ fn renderTypePrefix( ); switch (parent_fix) { .prefix => { - try w.print("{}(", .{child_trailing}); + try w.print("{f}(", .{child_trailing}); return .no_space; }, .suffix => return child_trailing, @@ -2560,7 +2601,7 @@ fn renderTypePrefix( ); switch (parent_fix) { .prefix => { - try w.print("{}(", .{child_trailing}); + try w.print("{f}(", .{child_trailing}); return .no_space; }, .suffix => return child_trailing, @@ -2569,7 +2610,7 @@ fn renderTypePrefix( } var qualifier_it = qualifiers.iterator(); while (qualifier_it.next()) |qualifier| { - try w.print("{}{s}", .{ trailing, @tagName(qualifier) }); + try w.print("{f}{s}", .{ trailing, @tagName(qualifier) }); trailing = .maybe_space; } return trailing; @@ -2578,11 +2619,11 @@ fn renderTypeSuffix( pass: DeclGen.Pass, ctype_pool: *const CType.Pool, zcu: *Zcu, - w: anytype, + w: *Writer, ctype: CType, parent_fix: CTypeFix, qualifiers: CQualifiers, -) @TypeOf(w).Error!void { +) Writer.Error!void { switch (ctype.info(ctype_pool)) { .basic, .aligned, .fwd_decl, .aggregate => {}, .pointer => |pointer_info| try renderTypeSuffix( @@ -2617,7 +2658,7 @@ fn renderTypeSuffix( need_comma = true; const trailing = try renderTypePrefix(pass, ctype_pool, zcu, w, param_type, .suffix, qualifiers); - if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_index }); + if (qualifiers.contains(.@"const")) try w.print("{f}a{d}", .{ trailing, param_index }); try renderTypeSuffix(pass, ctype_pool, zcu, w, param_type, .suffix, .{}); } if (function_info.varargs) { @@ -2634,49 +2675,49 @@ fn renderTypeSuffix( } fn renderFields( zcu: *Zcu, - writer: anytype, + w: *Writer, ctype_pool: *const CType.Pool, aggregate_info: CType.Info.Aggregate, indent: usize, ) !void { - try writer.writeAll("{\n"); + try w.writeAll("{\n"); for (0..aggregate_info.fields.len) |field_index| { const field_info = aggregate_info.fields.at(field_index, ctype_pool); - try writer.writeByteNTimes(' ', indent + 1); + try w.splatByteAll(' ', indent + 1); switch (field_info.alignas.abiOrder()) { .lt => { std.debug.assert(aggregate_info.@"packed"); - if (field_info.alignas.@"align" != .@"1") try writer.print("zig_under_align({}) ", .{ + if (field_info.alignas.@"align" != .@"1") try w.print("zig_under_align({}) ", .{ field_info.alignas.toByteUnits(), }); }, .eq => if (aggregate_info.@"packed" and field_info.alignas.@"align" != .@"1") - try writer.print("zig_align({}) ", .{field_info.alignas.toByteUnits()}), + try w.print("zig_align({}) ", .{field_info.alignas.toByteUnits()}), .gt => { std.debug.assert(field_info.alignas.@"align" != .@"1"); - try writer.print("zig_align({}) ", .{field_info.alignas.toByteUnits()}); + try w.print("zig_align({}) ", .{field_info.alignas.toByteUnits()}); }, } const trailing = try renderTypePrefix( .flush, ctype_pool, zcu, - writer, + w, field_info.ctype, .suffix, .{}, ); - try writer.print("{}{ }", .{ trailing, fmtCTypePoolString(field_info.name, ctype_pool) }); - try renderTypeSuffix(.flush, ctype_pool, zcu, writer, field_info.ctype, .suffix, .{}); - try writer.writeAll(";\n"); + try w.print("{f}{f}", .{ trailing, fmtCTypePoolString(field_info.name, ctype_pool, true) }); + try renderTypeSuffix(.flush, ctype_pool, zcu, w, field_info.ctype, .suffix, .{}); + try w.writeAll(";\n"); } - try writer.writeByteNTimes(' ', indent); - try writer.writeByte('}'); + try w.splatByteAll(' ', indent); + try w.writeByte('}'); } pub fn genTypeDecl( zcu: *Zcu, - writer: anytype, + w: *Writer, global_ctype_pool: *const CType.Pool, global_ctype: CType, pass: DeclGen.Pass, @@ -2689,27 +2730,27 @@ pub fn genTypeDecl( .aligned => |aligned_info| { if (!found_existing) { std.debug.assert(aligned_info.alignas.abiOrder().compare(.lt)); - try writer.print("typedef zig_under_align({d}) ", .{aligned_info.alignas.toByteUnits()}); - try writer.print("{}", .{try renderTypePrefix( + try w.print("typedef zig_under_align({d}) ", .{aligned_info.alignas.toByteUnits()}); + try w.print("{f}", .{try renderTypePrefix( .flush, global_ctype_pool, zcu, - writer, + w, aligned_info.ctype, .suffix, .{}, )}); - try renderAlignedTypeName(writer, global_ctype); - try renderTypeSuffix(.flush, global_ctype_pool, zcu, writer, aligned_info.ctype, .suffix, .{}); - try writer.writeAll(";\n"); + try renderAlignedTypeName(w, global_ctype); + try renderTypeSuffix(.flush, global_ctype_pool, zcu, w, aligned_info.ctype, .suffix, .{}); + try w.writeAll(";\n"); } switch (pass) { .nav, .uav => { - try writer.writeAll("typedef "); - _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{}); - try writer.writeByte(' '); - _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, writer, decl_ctype, .suffix, .{}); - try writer.writeAll(";\n"); + try w.writeAll("typedef "); + _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, w, global_ctype, .suffix, .{}); + try w.writeByte(' '); + _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, w, decl_ctype, .suffix, .{}); + try w.writeAll(";\n"); }, .flush => {}, } @@ -2717,24 +2758,24 @@ pub fn genTypeDecl( .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) { .anon => switch (pass) { .nav, .uav => { - try writer.writeAll("typedef "); - _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{}); - try writer.writeByte(' '); - _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, writer, decl_ctype, .suffix, .{}); - try writer.writeAll(";\n"); + try w.writeAll("typedef "); + _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, w, global_ctype, .suffix, .{}); + try w.writeByte(' '); + _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, w, decl_ctype, .suffix, .{}); + try w.writeAll(";\n"); }, .flush => {}, }, .index => |index| if (!found_existing) { const ip = &zcu.intern_pool; const ty: Type = .fromInterned(index); - _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{}); - try writer.writeByte(';'); + _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, w, global_ctype, .suffix, .{}); + try w.writeByte(';'); const file_scope = ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip); - if (!zcu.fileByIndex(file_scope).mod.?.strip) try writer.print(" /* {} */", .{ + if (!zcu.fileByIndex(file_scope).mod.?.strip) try w.print(" /* {f} */", .{ ty.containerTypeName(ip).fmt(ip), }); - try writer.writeByte('\n'); + try w.writeByte('\n'); }, }, .aggregate => |aggregate_info| switch (aggregate_info.name) { @@ -2742,38 +2783,39 @@ pub fn genTypeDecl( .fwd_decl => |fwd_decl| if (!found_existing) { try renderFwdDeclTypeName( zcu, - writer, + w, fwd_decl, fwd_decl.info(global_ctype_pool).fwd_decl, if (aggregate_info.@"packed") "zig_packed(" else "", ); - try writer.writeByte(' '); - try renderFields(zcu, writer, global_ctype_pool, aggregate_info, 0); - if (aggregate_info.@"packed") try writer.writeByte(')'); - try writer.writeAll(";\n"); + try w.writeByte(' '); + try renderFields(zcu, w, global_ctype_pool, aggregate_info, 0); + if (aggregate_info.@"packed") try w.writeByte(')'); + try w.writeAll(";\n"); }, }, } } -pub fn genGlobalAsm(zcu: *Zcu, writer: anytype) !void { +pub fn genGlobalAsm(zcu: *Zcu, w: *Writer) !void { for (zcu.global_assembly.values()) |asm_source| { - try writer.print("__asm({s});\n", .{fmtStringLiteral(asm_source, null)}); + try w.print("__asm({f});\n", .{fmtStringLiteral(asm_source, null)}); } } -pub fn genErrDecls(o: *Object) !void { +pub fn genErrDecls(o: *Object) Error!void { const pt = o.dg.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; - const writer = o.writer(); + const w = &o.code.writer; var max_name_len: usize = 0; // do not generate an invalid empty enum when the global error set is empty const names = ip.global_error_set.getNamesFromMainThread(); if (names.len > 0) { - try writer.writeAll("enum {\n"); - o.indent_writer.pushIndent(); + try w.writeAll("enum {"); + o.indent(); + try o.newline(); for (names, 1..) |name_nts, value| { const name = name_nts.toSlice(ip); max_name_len = @max(name.len, max_name_len); @@ -2781,11 +2823,13 @@ pub fn genErrDecls(o: *Object) !void { .ty = .anyerror_type, .name = name_nts, } }); - try o.dg.renderValue(writer, Value.fromInterned(err_val), .Other); - try writer.print(" = {d}u,\n", .{value}); + try o.dg.renderValue(w, Value.fromInterned(err_val), .Other); + try w.print(" = {d}u,", .{value}); + try o.newline(); } - o.indent_writer.popIndent(); - try writer.writeAll("};\n"); + try o.outdent(); + try w.writeAll("};"); + try o.newline(); } const array_identifier = "zig_errorName"; const name_prefix = array_identifier ++ "_"; @@ -2808,18 +2852,19 @@ pub fn genErrDecls(o: *Object) !void { .storage = .{ .bytes = name.toString() }, } }); - try writer.writeAll("static "); + try w.writeAll("static "); try o.dg.renderTypeAndName( - writer, + w, name_ty, .{ .identifier = identifier }, Const, .none, .complete, ); - try writer.writeAll(" = "); - try o.dg.renderValue(writer, Value.fromInterned(name_val), .StaticInitializer); - try writer.writeAll(";\n"); + try w.writeAll(" = "); + try o.dg.renderValue(w, Value.fromInterned(name_val), .StaticInitializer); + try w.writeByte(';'); + try o.newline(); } const name_array_ty = try pt.arrayType(.{ @@ -2827,33 +2872,34 @@ pub fn genErrDecls(o: *Object) !void { .child = .slice_const_u8_sentinel_0_type, }); - try writer.writeAll("static "); + try w.writeAll("static "); try o.dg.renderTypeAndName( - writer, + w, name_array_ty, .{ .identifier = array_identifier }, Const, .none, .complete, ); - try writer.writeAll(" = {"); + try w.writeAll(" = {"); for (names, 1..) |name_nts, val| { const name = name_nts.toSlice(ip); - if (val > 1) try writer.writeAll(", "); - try writer.print("{{" ++ name_prefix ++ "{}, {}}}", .{ - fmtIdent(name), - try o.dg.fmtIntLiteral(try pt.intValue(.usize, name.len), .StaticInitializer), + if (val > 1) try w.writeAll(", "); + try w.print("{{" ++ name_prefix ++ "{f}, {f}}}", .{ + fmtIdentUnsolo(name), + try o.dg.fmtIntLiteralDec(try pt.intValue(.usize, name.len), .StaticInitializer), }); } - try writer.writeAll("};\n"); + try w.writeAll("};"); + try o.newline(); } -pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFnMap.Entry) !void { +pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFnMap.Entry) Error!void { const pt = o.dg.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; const ctype_pool = &o.dg.ctype_pool; - const w = o.writer(); + const w = &o.code.writer; const key = lazy_fn.key_ptr.*; const val = lazy_fn.value_ptr; switch (key) { @@ -2863,9 +2909,14 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn try w.writeAll("static "); try o.dg.renderType(w, name_slice_ty); - try w.print(" {}(", .{val.fn_name.fmt(lazy_ctype_pool)}); + try w.print(" {f}(", .{val.fn_name.fmt(lazy_ctype_pool)}); try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete); - try w.writeAll(") {\n switch (tag) {\n"); + try w.writeAll(") {"); + o.indent(); + try o.newline(); + try w.writeAll("switch (tag) {"); + o.indent(); + try o.newline(); const tag_names = enum_ty.enumFields(zcu); for (0..tag_names.len) |tag_index| { const tag_name = tag_names.get(ip)[tag_index]; @@ -2882,34 +2933,43 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn .storage = .{ .bytes = tag_name.toString() }, } }); - try w.print(" case {}: {{\n static ", .{ - try o.dg.fmtIntLiteral(try tag_val.intFromEnum(enum_ty, pt), .Other), + try w.print("case {f}: {{", .{ + try o.dg.fmtIntLiteralDec(try tag_val.intFromEnum(enum_ty, pt), .Other), }); + o.indent(); + try o.newline(); + try w.writeAll("static "); try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, .none, .complete); try w.writeAll(" = "); try o.dg.renderValue(w, Value.fromInterned(name_val), .StaticInitializer); - try w.writeAll(";\n return ("); + try w.writeByte(';'); + try o.newline(); + try w.writeAll("return ("); try o.dg.renderType(w, name_slice_ty); - try w.print("){{{}, {}}};\n", .{ - fmtIdent("name"), - try o.dg.fmtIntLiteral(try pt.intValue(.usize, tag_name_len), .Other), + try w.print("){{{f}, {f}}};", .{ + fmtIdentUnsolo("name"), + try o.dg.fmtIntLiteralDec(try pt.intValue(.usize, tag_name_len), .Other), }); - - try w.writeAll(" }\n"); + try o.newline(); + try o.outdent(); + try w.writeByte('}'); + try o.newline(); } - try w.writeAll(" }\n while ("); - try o.dg.renderValue(w, Value.true, .Other); - try w.writeAll(") "); - _ = try airBreakpoint(w); - try w.writeAll("}\n"); + try o.outdent(); + try w.writeByte('}'); + try o.newline(); + try airUnreach(o); + try o.outdent(); + try w.writeByte('}'); + try o.newline(); }, .never_tail, .never_inline => |fn_nav_index| { const fn_val = zcu.navValue(fn_nav_index); const fn_ctype = try o.dg.ctypeFromType(fn_val.typeOf(zcu), .complete); const fn_info = fn_ctype.info(ctype_pool).function; - const fn_name = fmtCTypePoolString(val.fn_name, lazy_ctype_pool); + const fn_name = fmtCTypePoolString(val.fn_name, lazy_ctype_pool, true); - const fwd = o.dg.fwdDeclWriter(); + const fwd = &o.dg.fwd_decl.writer; try fwd.print("static zig_{s} ", .{@tagName(key)}); try o.dg.renderFunctionSignature(fwd, fn_val, ip.getNav(fn_nav_index).getAlignment(), .forward, .{ .fmt_ctype_pool_string = fn_name, @@ -2920,14 +2980,21 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn try o.dg.renderFunctionSignature(w, fn_val, .none, .complete, .{ .fmt_ctype_pool_string = fn_name, }); - try w.writeAll(" {\n return "); + try w.writeAll(" {"); + o.indent(); + try o.newline(); + try w.writeAll("return "); try o.dg.renderNavName(w, fn_nav_index); try w.writeByte('('); for (0..fn_info.param_ctypes.len) |arg| { if (arg > 0) try w.writeAll(", "); try w.print("a{d}", .{arg}); } - try w.writeAll(");\n}\n"); + try w.writeAll(");"); + try o.newline(); + try o.outdent(); + try w.writeByte('}'); + try o.newline(); }, } } @@ -2967,12 +3034,14 @@ pub fn generate( .scratch = .empty, .uavs = .empty, }, + .code_header = .init(gpa), .code = .init(gpa), - .indent_writer = undefined, // set later so we can get a pointer to object.code + .indent_counter = 0, }, .lazy_fns = .empty, }; defer { + function.object.code_header.deinit(); function.object.code.deinit(); function.object.dg.fwd_decl.deinit(); function.object.dg.ctype_pool.deinit(gpa); @@ -2981,22 +3050,24 @@ pub fn generate( function.deinit(); } try function.object.dg.ctype_pool.init(gpa); - function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() }; genFunc(&function) catch |err| switch (err) { error.AnalysisFail => return zcu.codegenFailMsg(func.owner_nav, function.object.dg.error_msg.?), - error.OutOfMemory => |e| return e, + error.OutOfMemory => return error.OutOfMemory, + error.WriteFailed => return error.OutOfMemory, }; var mir: Mir = .{ .uavs = .empty, .code = &.{}, + .code_header = &.{}, .fwd_decl = &.{}, .ctype_pool = .empty, .lazy_fns = .empty, }; errdefer mir.deinit(gpa); mir.uavs = function.object.dg.uavs.move(); + mir.code_header = try function.object.code_header.toOwnedSlice(); mir.code = try function.object.code.toOwnedSlice(); mir.fwd_decl = try function.object.dg.fwd_decl.toOwnedSlice(); mir.ctype_pool = function.object.dg.ctype_pool.move(); @@ -3004,7 +3075,7 @@ pub fn generate( return mir; } -fn genFunc(f: *Function) !void { +pub fn genFunc(f: *Function) Error!void { const tracy = trace(@src()); defer tracy.end(); @@ -3016,10 +3087,7 @@ fn genFunc(f: *Function) !void { const nav_val = zcu.navValue(nav_index); const nav = ip.getNav(nav_index); - o.code_header = std.ArrayList(u8).init(gpa); - defer o.code_header.deinit(); - - const fwd = o.dg.fwdDeclWriter(); + const fwd = &o.dg.fwd_decl.writer; try fwd.writeAll("static "); try o.dg.renderFunctionSignature( fwd, @@ -3030,29 +3098,26 @@ fn genFunc(f: *Function) !void { ); try fwd.writeAll(";\n"); + const ch = &o.code_header.writer; if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |s| - try o.writer().print("zig_linksection_fn({s}) ", .{fmtStringLiteral(s, null)}); + try ch.print("zig_linksection_fn({f}) ", .{fmtStringLiteral(s, null)}); try o.dg.renderFunctionSignature( - o.writer(), + ch, nav_val, .none, .complete, .{ .nav = nav_index }, ); - try o.writer().writeByte(' '); - - // In case we need to use the header, populate it with a copy of the function - // signature here. We anticipate a brace, newline, and space. - try o.code_header.ensureUnusedCapacity(o.code.items.len + 3); - o.code_header.appendSliceAssumeCapacity(o.code.items); - o.code_header.appendSliceAssumeCapacity("{\n "); - const empty_header_len = o.code_header.items.len; + try ch.writeAll(" {\n "); f.free_locals_map.clearRetainingCapacity(); const main_body = f.air.getMainBody(); - try genBodyResolveState(f, undefined, &.{}, main_body, false); - try o.indent_writer.insertNewline(); + o.indent(); + try genBodyResolveState(f, undefined, &.{}, main_body, true); + try o.outdent(); + try o.code.writer.writeByte('}'); + try o.newline(); if (o.dg.expected_block) |_| return f.fail("runtime code not allowed in naked function", .{}); @@ -3083,24 +3148,16 @@ fn genFunc(f: *Function) !void { }; free_locals.sort(SortContext{ .keys = free_locals.keys() }); - const w = o.codeHeaderWriter(); for (free_locals.values()) |list| { for (list.keys()) |local_index| { const local = f.locals.items[local_index]; - try o.dg.renderCTypeAndName(w, local.ctype, .{ .local = local_index }, .{}, local.flags.alignas); - try w.writeAll(";\n "); + try o.dg.renderCTypeAndName(ch, local.ctype, .{ .local = local_index }, .{}, local.flags.alignas); + try ch.writeAll(";\n "); } } - - // If we have a header to insert, append the body to the header - // and then return the result, freeing the body. - if (o.code_header.items.len > empty_header_len) { - try o.code_header.appendSlice(o.code.items[empty_header_len..]); - mem.swap(std.ArrayList(u8), &o.code, &o.code_header); - } } -pub fn genDecl(o: *Object) !void { +pub fn genDecl(o: *Object) Error!void { const tracy = trace(@src()); defer tracy.end(); @@ -3120,7 +3177,7 @@ pub fn genDecl(o: *Object) !void { .visibility = @"extern".visibility, }); - const fwd = o.dg.fwdDeclWriter(); + const fwd = &o.dg.fwd_decl.writer; try fwd.writeAll("zig_extern "); try o.dg.renderFunctionSignature( fwd, @@ -3141,10 +3198,10 @@ pub fn genDecl(o: *Object) !void { .linkage = .internal, .visibility = .default, }); - const w = o.writer(); + const w = &o.code.writer; if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal "); if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s| - try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)}); + try w.print("zig_linksection({f}) ", .{fmtStringLiteral(s, null)}); try o.dg.renderTypeAndName( w, nav_ty, @@ -3156,7 +3213,7 @@ pub fn genDecl(o: *Object) !void { try w.writeAll(" = "); try o.dg.renderValue(w, Value.fromInterned(variable.init), .StaticInitializer); try w.writeByte(';'); - try o.indent_writer.insertNewline(); + try o.newline(); }, else => try genDeclValue( o, @@ -3174,28 +3231,29 @@ pub fn genDeclValue( decl_c_value: CValue, alignment: Alignment, @"linksection": InternPool.OptionalNullTerminatedString, -) !void { +) Error!void { const zcu = o.dg.pt.zcu; const ty = val.typeOf(zcu); - const fwd = o.dg.fwdDeclWriter(); + const fwd = &o.dg.fwd_decl.writer; try fwd.writeAll("static "); try o.dg.renderTypeAndName(fwd, ty, decl_c_value, Const, alignment, .complete); try fwd.writeAll(";\n"); - const w = o.writer(); + const w = &o.code.writer; if (@"linksection".toSlice(&zcu.intern_pool)) |s| - try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)}); + try w.print("zig_linksection({f}) ", .{fmtStringLiteral(s, null)}); try o.dg.renderTypeAndName(w, ty, decl_c_value, Const, alignment, .complete); try w.writeAll(" = "); try o.dg.renderValue(w, val, .StaticInitializer); - try w.writeAll(";\n"); + try w.writeByte(';'); + try o.newline(); } pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const Zcu.Export.Index) !void { const zcu = dg.pt.zcu; const ip = &zcu.intern_pool; - const fwd = dg.fwdDeclWriter(); + const fwd = &dg.fwd_decl.writer; const main_name = export_indices[0].ptr(zcu).opts.name; try fwd.writeAll("#define "); @@ -3204,7 +3262,7 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const .uav => |uav| try DeclGen.renderUavName(fwd, Value.fromInterned(uav)), } try fwd.writeByte(' '); - try fwd.print("{ }", .{fmtIdent(main_name.toSlice(ip))}); + try fwd.print("{f}", .{fmtIdentSolo(main_name.toSlice(ip))}); try fwd.writeByte('\n'); const exported_val = exported.getValue(zcu); @@ -3234,7 +3292,7 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const const @"export" = export_index.ptr(zcu); try fwd.writeAll("zig_extern "); if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage "); - if (@"export".opts.section.toSlice(ip)) |s| try fwd.print("zig_linksection({s}) ", .{ + if (@"export".opts.section.toSlice(ip)) |s| try fwd.print("zig_linksection({f}) ", .{ fmtStringLiteral(s, null), }); const extern_name = @"export".opts.name.toSlice(ip); @@ -3249,17 +3307,17 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const .complete, ); if (is_mangled and is_export) { - try fwd.print(" zig_mangled_export({ }, {s}, {s})", .{ - fmtIdent(extern_name), + try fwd.print(" zig_mangled_export({f}, {f}, {f})", .{ + fmtIdentSolo(extern_name), fmtStringLiteral(extern_name, null), fmtStringLiteral(main_name.toSlice(ip), null), }); } else if (is_mangled) { - try fwd.print(" zig_mangled({ }, {s})", .{ - fmtIdent(extern_name), fmtStringLiteral(extern_name, null), + try fwd.print(" zig_mangled({f}, {f})", .{ + fmtIdentSolo(extern_name), fmtStringLiteral(extern_name, null), }); } else if (is_export) { - try fwd.print(" zig_export({s}, {s})", .{ + try fwd.print(" zig_export({f}, {f})", .{ fmtStringLiteral(main_name.toSlice(ip), null), fmtStringLiteral(extern_name, null), }); @@ -3272,16 +3330,17 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const /// `value_map` and `free_locals_map` are undefined after the generation, and new locals may not /// have been added to `free_locals_map`. For a version of this function that restores this state, /// see `genBodyResolveState`. -fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void { - const writer = f.object.writer(); +fn genBody(f: *Function, body: []const Air.Inst.Index) Error!void { + const w = &f.object.code.writer; if (body.len == 0) { - try writer.writeAll("{}"); + try w.writeAll("{}"); } else { - try writer.writeAll("{\n"); - f.object.indent_writer.pushIndent(); + try w.writeByte('{'); + f.object.indent(); + try f.object.newline(); try genBodyInner(f, body); - f.object.indent_writer.popIndent(); - try writer.writeByte('}'); + try f.object.outdent(); + try w.writeByte('}'); } } @@ -3291,10 +3350,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO /// `leading_deaths` have their deaths processed before the body is generated. /// A scope is introduced (using braces) only if `inner` is `false`. /// If `leading_deaths` is empty, `inst` may be `undefined`. -fn genBodyResolveState(f: *Function, inst: Air.Inst.Index, leading_deaths: []const Air.Inst.Index, body: []const Air.Inst.Index, inner: bool) error{ AnalysisFail, OutOfMemory }!void { +fn genBodyResolveState(f: *Function, inst: Air.Inst.Index, leading_deaths: []const Air.Inst.Index, body: []const Air.Inst.Index, inner: bool) Error!void { if (body.len == 0) { // Don't go to the expense of cloning everything! - if (!inner) try f.object.writer().writeAll("{}"); + if (!inner) try f.object.code.writer.writeAll("{}"); return; } @@ -3340,7 +3399,7 @@ fn genBodyResolveState(f: *Function, inst: Air.Inst.Index, leading_deaths: []con } } -fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void { +fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { const zcu = f.object.dg.pt.zcu; const ip = &zcu.intern_pool; const air_tags = f.air.instructions.items(.tag); @@ -3358,7 +3417,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, .arg => try airArg(f, inst), - .breakpoint => try airBreakpoint(f.object.writer()), + .breakpoint => try airBreakpoint(f), .ret_addr => try airRetAddr(f, inst), .frame_addr => try airFrameAddress(f, inst), @@ -3611,8 +3670,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, .ret => return airRet(f, inst, false), .ret_safe => return airRet(f, inst, false), // TODO .ret_load => return airRet(f, inst, true), - .trap => return airTrap(f, f.object.writer()), - .unreach => return airUnreach(f), + .trap => return airTrap(f, &f.object.code.writer), + .unreach => return airUnreach(&f.object), // Instructions which may be `noreturn`. .block => res: { @@ -3655,16 +3714,16 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [ const operand = try f.resolveInst(ty_op.operand); try reap(f, inst, &.{ty_op.operand}); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete)); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); if (is_ptr) { - try writer.writeByte('&'); - try f.writeCValueDerefMember(writer, operand, .{ .identifier = field_name }); - } else try f.writeCValueMember(writer, operand, .{ .identifier = field_name }); - try a.end(f, writer); + try w.writeByte('&'); + try f.writeCValueDerefMember(w, operand, .{ .identifier = field_name }); + } else try f.writeCValueMember(w, operand, .{ .identifier = field_name }); + try a.end(f, w); return local; } @@ -3681,16 +3740,16 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue { const index = try f.resolveInst(bin_op.rhs); try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); - try f.writeCValue(writer, ptr, .Other); - try writer.writeByte('['); - try f.writeCValue(writer, index, .Other); - try writer.writeByte(']'); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete)); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); + try f.writeCValue(w, ptr, .Other); + try w.writeByte('['); + try f.writeCValue(w, index, .Other); + try w.writeByte(']'); + try a.end(f, w); return local; } @@ -3708,25 +3767,25 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { const index = try f.resolveInst(bin_op.rhs); try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); - try writer.writeByte('('); - try f.renderType(writer, inst_ty); - try writer.writeByte(')'); - if (elem_has_bits) try writer.writeByte('&'); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete)); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); + try w.writeByte('('); + try f.renderType(w, inst_ty); + try w.writeByte(')'); + if (elem_has_bits) try w.writeByte('&'); if (elem_has_bits and ptr_ty.ptrSize(zcu) == .one) { // It's a pointer to an array, so we need to de-reference. - try f.writeCValueDeref(writer, ptr); - } else try f.writeCValue(writer, ptr, .Other); + try f.writeCValueDeref(w, ptr); + } else try f.writeCValue(w, ptr, .Other); if (elem_has_bits) { - try writer.writeByte('['); - try f.writeCValue(writer, index, .Other); - try writer.writeByte(']'); + try w.writeByte('['); + try f.writeCValue(w, index, .Other); + try w.writeByte(']'); } - try a.end(f, writer); + try a.end(f, w); return local; } @@ -3743,16 +3802,16 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { const index = try f.resolveInst(bin_op.rhs); try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); - try f.writeCValueMember(writer, slice, .{ .identifier = "ptr" }); - try writer.writeByte('['); - try f.writeCValue(writer, index, .Other); - try writer.writeByte(']'); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete)); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); + try f.writeCValueMember(w, slice, .{ .identifier = "ptr" }); + try w.writeByte('['); + try f.writeCValue(w, index, .Other); + try w.writeByte(']'); + try a.end(f, w); return local; } @@ -3771,19 +3830,19 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { const index = try f.resolveInst(bin_op.rhs); try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); - if (elem_has_bits) try writer.writeByte('&'); - try f.writeCValueMember(writer, slice, .{ .identifier = "ptr" }); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete)); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); + if (elem_has_bits) try w.writeByte('&'); + try f.writeCValueMember(w, slice, .{ .identifier = "ptr" }); if (elem_has_bits) { - try writer.writeByte('['); - try f.writeCValue(writer, index, .Other); - try writer.writeByte(']'); + try w.writeByte('['); + try f.writeCValue(w, index, .Other); + try w.writeByte(']'); } - try a.end(f, writer); + try a.end(f, w); return local; } @@ -3800,16 +3859,16 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { const index = try f.resolveInst(bin_op.rhs); try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); - try f.writeCValue(writer, array, .Other); - try writer.writeByte('['); - try f.writeCValue(writer, index, .Other); - try writer.writeByte(']'); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete)); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); + try f.writeCValue(w, array, .Other); + try w.writeByte('['); + try f.writeCValue(w, index, .Other); + try w.writeByte(']'); + try a.end(f, w); return local; } @@ -3863,12 +3922,13 @@ fn airArg(f: *Function, inst: Air.Inst.Index) !CValue { .{ .arg_array = i }; if (f.liveness.isUnused(inst)) { - const writer = f.object.writer(); - try writer.writeByte('('); - try f.renderType(writer, .void); - try writer.writeByte(')'); - try f.writeCValue(writer, result, .Other); - try writer.writeAll(";\n"); + const w = &f.object.code.writer; + try w.writeByte('('); + try f.renderType(w, .void); + try w.writeByte(')'); + try f.writeCValue(w, result, .Other); + try w.writeByte(';'); + try f.object.newline(); return .none; } @@ -3901,21 +3961,21 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { const is_array = lowersToArray(src_ty, pt); const need_memcpy = !is_aligned or is_array; - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, src_ty); - const v = try Vectorize.start(f, inst, writer, ptr_ty); + const v = try Vectorize.start(f, inst, w, ptr_ty); if (need_memcpy) { - try writer.writeAll("memcpy("); - if (!is_array) try writer.writeByte('&'); - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try writer.writeAll(", (const char *)"); - try f.writeCValue(writer, operand, .Other); - try v.elem(f, writer); - try writer.writeAll(", sizeof("); - try f.renderType(writer, src_ty); - try writer.writeAll("))"); + try w.writeAll("memcpy("); + if (!is_array) try w.writeByte('&'); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try w.writeAll(", (const char *)"); + try f.writeCValue(w, operand, .Other); + try v.elem(f, w); + try w.writeAll(", sizeof("); + try f.renderType(w, src_ty); + try w.writeAll("))"); } else if (ptr_info.packed_offset.host_size > 0 and ptr_info.flags.vector_index == .none) { const host_bits: u16 = ptr_info.packed_offset.host_size * 8; const host_ty = try pt.intType(.unsigned, host_bits); @@ -3925,40 +3985,41 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { const field_ty = try pt.intType(.unsigned, @as(u16, @intCast(src_ty.bitSize(zcu)))); - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try writer.writeAll(" = ("); - try f.renderType(writer, src_ty); - try writer.writeAll(")zig_wrap_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty); - try writer.writeAll("(("); - try f.renderType(writer, field_ty); - try writer.writeByte(')'); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try w.writeAll(" = ("); + try f.renderType(w, src_ty); + try w.writeAll(")zig_wrap_"); + try f.object.dg.renderTypeForBuiltinFnName(w, field_ty); + try w.writeAll("(("); + try f.renderType(w, field_ty); + try w.writeByte(')'); const cant_cast = host_ty.isInt(zcu) and host_ty.bitSize(zcu) > 64; if (cant_cast) { if (field_ty.bitSize(zcu) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); - try writer.writeAll("zig_lo_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); - try writer.writeByte('('); + try w.writeAll("zig_lo_"); + try f.object.dg.renderTypeForBuiltinFnName(w, host_ty); + try w.writeByte('('); } - try writer.writeAll("zig_shr_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); - try writer.writeByte('('); - try f.writeCValueDeref(writer, operand); - try v.elem(f, writer); - try writer.print(", {})", .{try f.fmtIntLiteral(bit_offset_val)}); - if (cant_cast) try writer.writeByte(')'); - try f.object.dg.renderBuiltinInfo(writer, field_ty, .bits); - try writer.writeByte(')'); + try w.writeAll("zig_shr_"); + try f.object.dg.renderTypeForBuiltinFnName(w, host_ty); + try w.writeByte('('); + try f.writeCValueDeref(w, operand); + try v.elem(f, w); + try w.print(", {f})", .{try f.fmtIntLiteralDec(bit_offset_val)}); + if (cant_cast) try w.writeByte(')'); + try f.object.dg.renderBuiltinInfo(w, field_ty, .bits); + try w.writeByte(')'); } else { - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try writer.writeAll(" = "); - try f.writeCValueDeref(writer, operand); - try v.elem(f, writer); - } - try writer.writeAll(";\n"); - try v.end(f, inst, writer); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try w.writeAll(" = "); + try f.writeCValueDeref(w, operand); + try v.elem(f, w); + } + try w.writeByte(';'); + try f.object.newline(); + try v.end(f, inst, w); return local; } @@ -3967,7 +4028,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void { const pt = f.object.dg.pt; const zcu = pt.zcu; const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const writer = f.object.writer(); + const w = &f.object.code.writer; const op_inst = un_op.toIndex(); const op_ty = f.typeOf(un_op); const ret_ty = if (is_ptr) op_ty.childType(zcu) else op_ty; @@ -3986,33 +4047,34 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void { .ctype = ret_ctype, .alignas = CType.AlignAs.fromAbiAlignment(ret_ty.abiAlignment(zcu)), }); - try writer.writeAll("memcpy("); - try f.writeCValueMember(writer, array_local, .{ .identifier = "array" }); - try writer.writeAll(", "); + try w.writeAll("memcpy("); + try f.writeCValueMember(w, array_local, .{ .identifier = "array" }); + try w.writeAll(", "); if (deref) - try f.writeCValueDeref(writer, operand) + try f.writeCValueDeref(w, operand) else - try f.writeCValue(writer, operand, .FunctionArgument); + try f.writeCValue(w, operand, .FunctionArgument); deref = false; - try writer.writeAll(", sizeof("); - try f.renderType(writer, ret_ty); - try writer.writeAll("));\n"); + try w.writeAll(", sizeof("); + try f.renderType(w, ret_ty); + try w.writeAll("));"); + try f.object.newline(); break :ret_val array_local; } else operand; - try writer.writeAll("return "); + try w.writeAll("return "); if (deref) - try f.writeCValueDeref(writer, ret_val) + try f.writeCValueDeref(w, ret_val) else - try f.writeCValue(writer, ret_val, .Other); - try writer.writeAll(";\n"); + try f.writeCValue(w, ret_val, .Other); + try w.writeAll(";\n"); if (is_array) { try freeLocal(f, inst, ret_val.new_local, null); } } else { try reap(f, inst, &.{un_op}); // Not even allowed to return void in a naked function. - if (!f.object.dg.is_naked_fn) try writer.writeAll("return;\n"); + if (!f.object.dg.is_naked_fn) try w.writeAll("return;\n"); } } @@ -4031,16 +4093,16 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { if (f.object.dg.intCastIsNoop(inst_scalar_ty, scalar_ty)) return f.moveCValue(inst, inst_ty, operand); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, writer, operand_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(scalar_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try a.assign(f, writer); - try f.renderIntCast(writer, inst_scalar_ty, operand, v, scalar_ty, .Other); - try a.end(f, writer); - try v.end(f, inst, writer); + const v = try Vectorize.start(f, inst, w, operand_ty); + const a = try Assignment.start(f, w, try f.ctypeFromType(scalar_ty, .complete)); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try a.assign(f, w); + try f.renderIntCast(w, inst_scalar_ty, operand, v, scalar_ty, .Other); + try a.end(f, w); + try v.end(f, inst, w); return local; } @@ -4067,35 +4129,35 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { const need_mask = dest_bits < 8 or !std.math.isPowerOfTwo(dest_bits); if (!need_cast and !need_lo and !need_mask) return f.moveCValue(inst, inst_ty, operand); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, writer, operand_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_scalar_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try a.assign(f, writer); + const v = try Vectorize.start(f, inst, w, operand_ty); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_scalar_ty, .complete)); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try a.assign(f, w); if (need_cast) { - try writer.writeByte('('); - try f.renderType(writer, inst_scalar_ty); - try writer.writeByte(')'); + try w.writeByte('('); + try f.renderType(w, inst_scalar_ty); + try w.writeByte(')'); } if (need_lo) { - try writer.writeAll("zig_lo_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); - try writer.writeByte('('); + try w.writeAll("zig_lo_"); + try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty); + try w.writeByte('('); } if (!need_mask) { - try f.writeCValue(writer, operand, .Other); - try v.elem(f, writer); + try f.writeCValue(w, operand, .Other); + try v.elem(f, w); } else switch (dest_int_info.signedness) { .unsigned => { - try writer.writeAll("zig_and_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); - try writer.writeByte('('); - try f.writeCValue(writer, operand, .FunctionArgument); - try v.elem(f, writer); - try writer.print(", {x})", .{ - try f.fmtIntLiteral(try inst_scalar_ty.maxIntScalar(pt, scalar_ty)), + try w.writeAll("zig_and_"); + try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty); + try w.writeByte('('); + try f.writeCValue(w, operand, .FunctionArgument); + try v.elem(f, w); + try w.print(", {f})", .{ + try f.fmtIntLiteralHex(try inst_scalar_ty.maxIntScalar(pt, scalar_ty)), }); }, .signed => { @@ -4103,30 +4165,30 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); const shift_val = try pt.intValue(.u8, c_bits - dest_bits); - try writer.writeAll("zig_shr_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); + try w.writeAll("zig_shr_"); + try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty); if (c_bits == 128) { - try writer.print("(zig_bitCast_i{d}(", .{c_bits}); + try w.print("(zig_bitCast_i{d}(", .{c_bits}); } else { - try writer.print("((int{d}_t)", .{c_bits}); + try w.print("((int{d}_t)", .{c_bits}); } - try writer.print("zig_shl_u{d}(", .{c_bits}); + try w.print("zig_shl_u{d}(", .{c_bits}); if (c_bits == 128) { - try writer.print("zig_bitCast_u{d}(", .{c_bits}); + try w.print("zig_bitCast_u{d}(", .{c_bits}); } else { - try writer.print("(uint{d}_t)", .{c_bits}); + try w.print("(uint{d}_t)", .{c_bits}); } - try f.writeCValue(writer, operand, .FunctionArgument); - try v.elem(f, writer); - if (c_bits == 128) try writer.writeByte(')'); - try writer.print(", {})", .{try f.fmtIntLiteral(shift_val)}); - if (c_bits == 128) try writer.writeByte(')'); - try writer.print(", {})", .{try f.fmtIntLiteral(shift_val)}); + try f.writeCValue(w, operand, .FunctionArgument); + try v.elem(f, w); + if (c_bits == 128) try w.writeByte(')'); + try w.print(", {f})", .{try f.fmtIntLiteralDec(shift_val)}); + if (c_bits == 128) try w.writeByte(')'); + try w.print(", {f})", .{try f.fmtIntLiteralDec(shift_val)}); }, } - if (need_lo) try writer.writeByte(')'); - try a.end(f, writer); - try v.end(f, inst, writer); + if (need_lo) try w.writeByte(')'); + try a.end(f, w); + try v.end(f, inst, w); return local; } @@ -4145,15 +4207,16 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { const val_is_undef = if (try f.air.value(bin_op.rhs, pt)) |v| v.isUndefDeep(zcu) else false; + const w = &f.object.code.writer; if (val_is_undef) { try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); if (safety and ptr_info.packed_offset.host_size == 0) { - const writer = f.object.writer(); - try writer.writeAll("memset("); - try f.writeCValue(writer, ptr_val, .FunctionArgument); - try writer.writeAll(", 0xaa, sizeof("); - try f.renderType(writer, .fromInterned(ptr_info.child)); - try writer.writeAll("));\n"); + try w.writeAll("memset("); + try f.writeCValue(w, ptr_val, .FunctionArgument); + try w.writeAll(", 0xaa, sizeof("); + try f.renderType(w, .fromInterned(ptr_info.child)); + try w.writeAll("));"); + try f.object.newline(); } return .none; } @@ -4169,7 +4232,6 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); const src_scalar_ctype = try f.ctypeFromType(src_ty.scalarType(zcu), .complete); - const writer = f.object.writer(); if (need_memcpy) { // For this memcpy to safely work we need the rhs to have the same // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). @@ -4180,28 +4242,30 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { // TODO this should be done by manually initializing elements of the dest array const array_src = if (src_val == .constant) blk: { const new_local = try f.allocLocal(inst, src_ty); - try f.writeCValue(writer, new_local, .Other); - try writer.writeAll(" = "); - try f.writeCValue(writer, src_val, .Other); - try writer.writeAll(";\n"); + try f.writeCValue(w, new_local, .Other); + try w.writeAll(" = "); + try f.writeCValue(w, src_val, .Other); + try w.writeByte(';'); + try f.object.newline(); break :blk new_local; } else src_val; - const v = try Vectorize.start(f, inst, writer, ptr_ty); - try writer.writeAll("memcpy((char *)"); - try f.writeCValue(writer, ptr_val, .FunctionArgument); - try v.elem(f, writer); - try writer.writeAll(", "); - if (!is_array) try writer.writeByte('&'); - try f.writeCValue(writer, array_src, .FunctionArgument); - try v.elem(f, writer); - try writer.writeAll(", sizeof("); - try f.renderType(writer, src_ty); - try writer.writeAll("))"); + const v = try Vectorize.start(f, inst, w, ptr_ty); + try w.writeAll("memcpy((char *)"); + try f.writeCValue(w, ptr_val, .FunctionArgument); + try v.elem(f, w); + try w.writeAll(", "); + if (!is_array) try w.writeByte('&'); + try f.writeCValue(w, array_src, .FunctionArgument); + try v.elem(f, w); + try w.writeAll(", sizeof("); + try f.renderType(w, src_ty); + try w.writeAll("))"); try f.freeCValue(inst, array_src); - try writer.writeAll(";\n"); - try v.end(f, inst, writer); + try w.writeByte(';'); + try f.object.newline(); + try v.end(f, inst, w); } else if (ptr_info.packed_offset.host_size > 0 and ptr_info.flags.vector_index == .none) { const host_bits = ptr_info.packed_offset.host_size * 8; const host_ty = try pt.intType(.unsigned, host_bits); @@ -4218,50 +4282,50 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { var mask = try BigInt.Managed.initCapacity(stack.get(), BigInt.calcTwosCompLimbCount(host_bits)); defer mask.deinit(); - try mask.setTwosCompIntLimit(.max, .unsigned, @as(usize, @intCast(src_bits))); + try mask.setTwosCompIntLimit(.max, .unsigned, @intCast(src_bits)); try mask.shiftLeft(&mask, ptr_info.packed_offset.bit_offset); try mask.bitNotWrap(&mask, .unsigned, host_bits); const mask_val = try pt.intValue_big(host_ty, mask.toConst()); - const v = try Vectorize.start(f, inst, writer, ptr_ty); - const a = try Assignment.start(f, writer, src_scalar_ctype); - try f.writeCValueDeref(writer, ptr_val); - try v.elem(f, writer); - try a.assign(f, writer); - try writer.writeAll("zig_or_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); - try writer.writeAll("(zig_and_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); - try writer.writeByte('('); - try f.writeCValueDeref(writer, ptr_val); - try v.elem(f, writer); - try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(mask_val)}); - try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); - try writer.writeByte('('); + const v = try Vectorize.start(f, inst, w, ptr_ty); + const a = try Assignment.start(f, w, src_scalar_ctype); + try f.writeCValueDeref(w, ptr_val); + try v.elem(f, w); + try a.assign(f, w); + try w.writeAll("zig_or_"); + try f.object.dg.renderTypeForBuiltinFnName(w, host_ty); + try w.writeAll("(zig_and_"); + try f.object.dg.renderTypeForBuiltinFnName(w, host_ty); + try w.writeByte('('); + try f.writeCValueDeref(w, ptr_val); + try v.elem(f, w); + try w.print(", {f}), zig_shl_", .{try f.fmtIntLiteralHex(mask_val)}); + try f.object.dg.renderTypeForBuiltinFnName(w, host_ty); + try w.writeByte('('); const cant_cast = host_ty.isInt(zcu) and host_ty.bitSize(zcu) > 64; if (cant_cast) { if (src_ty.bitSize(zcu) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); - try writer.writeAll("zig_make_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); - try writer.writeAll("(0, "); + try w.writeAll("zig_make_"); + try f.object.dg.renderTypeForBuiltinFnName(w, host_ty); + try w.writeAll("(0, "); } else { - try writer.writeByte('('); - try f.renderType(writer, host_ty); - try writer.writeByte(')'); + try w.writeByte('('); + try f.renderType(w, host_ty); + try w.writeByte(')'); } if (src_ty.isPtrAtRuntime(zcu)) { - try writer.writeByte('('); - try f.renderType(writer, .usize); - try writer.writeByte(')'); + try w.writeByte('('); + try f.renderType(w, .usize); + try w.writeByte(')'); } - try f.writeCValue(writer, src_val, .Other); - try v.elem(f, writer); - if (cant_cast) try writer.writeByte(')'); - try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_val)}); - try a.end(f, writer); - try v.end(f, inst, writer); + try f.writeCValue(w, src_val, .Other); + try v.elem(f, w); + if (cant_cast) try w.writeByte(')'); + try w.print(", {f}))", .{try f.fmtIntLiteralDec(bit_offset_val)}); + try a.end(f, w); + try v.end(f, inst, w); } else { switch (ptr_val) { .local_ref => |ptr_local_index| switch (src_val) { @@ -4271,15 +4335,15 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { }, else => {}, } - const v = try Vectorize.start(f, inst, writer, ptr_ty); - const a = try Assignment.start(f, writer, src_scalar_ctype); - try f.writeCValueDeref(writer, ptr_val); - try v.elem(f, writer); - try a.assign(f, writer); - try f.writeCValue(writer, src_val, .Other); - try v.elem(f, writer); - try a.end(f, writer); - try v.end(f, inst, writer); + const v = try Vectorize.start(f, inst, w, ptr_ty); + const a = try Assignment.start(f, w, src_scalar_ctype); + try f.writeCValueDeref(w, ptr_val); + try v.elem(f, w); + try a.assign(f, w); + try f.writeCValue(w, src_val, .Other); + try v.elem(f, w); + try a.end(f, w); + try v.end(f, inst, w); } return .none; } @@ -4298,7 +4362,7 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: const operand_ty = f.typeOf(bin_op.lhs); const scalar_ty = operand_ty.scalarType(zcu); - const w = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); const v = try Vectorize.start(f, inst, w, operand_ty); try f.writeCValueMember(w, local, .{ .field = 1 }); @@ -4317,7 +4381,8 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: try f.writeCValue(w, rhs, .FunctionArgument); if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w); try f.object.dg.renderBuiltinInfo(w, scalar_ty, info); - try w.writeAll(");\n"); + try w.writeAll(");"); + try f.object.newline(); try v.end(f, inst, w); return local; @@ -4336,17 +4401,18 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { const inst_ty = f.typeOfIndex(inst); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, writer, operand_ty); - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try writer.writeAll(" = "); - try writer.writeByte('!'); - try f.writeCValue(writer, op, .Other); - try v.elem(f, writer); - try writer.writeAll(";\n"); - try v.end(f, inst, writer); + const v = try Vectorize.start(f, inst, w, operand_ty); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try w.writeAll(" = "); + try w.writeByte('!'); + try f.writeCValue(w, op, .Other); + try v.elem(f, w); + try w.writeByte(';'); + try f.object.newline(); + try v.end(f, inst, w); return local; } @@ -4372,21 +4438,22 @@ fn airBinOp( const inst_ty = f.typeOfIndex(inst); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, writer, operand_ty); - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try writer.writeAll(" = "); - try f.writeCValue(writer, lhs, .Other); - try v.elem(f, writer); - try writer.writeByte(' '); - try writer.writeAll(operator); - try writer.writeByte(' '); - try f.writeCValue(writer, rhs, .Other); - try v.elem(f, writer); - try writer.writeAll(";\n"); - try v.end(f, inst, writer); + const v = try Vectorize.start(f, inst, w, operand_ty); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try w.writeAll(" = "); + try f.writeCValue(w, lhs, .Other); + try v.elem(f, w); + try w.writeByte(' '); + try w.writeAll(operator); + try w.writeByte(' '); + try f.writeCValue(w, rhs, .Other); + try v.elem(f, w); + try w.writeByte(';'); + try f.object.newline(); + try v.end(f, inst, w); return local; } @@ -4422,27 +4489,27 @@ fn airCmpOp( const rhs_ty = f.typeOf(data.rhs); const need_cast = lhs_ty.isSinglePointer(zcu) or rhs_ty.isSinglePointer(zcu); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, writer, lhs_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(scalar_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try a.assign(f, writer); - if (lhs != .undef and lhs.eql(rhs)) try writer.writeAll(switch (operator) { + const v = try Vectorize.start(f, inst, w, lhs_ty); + const a = try Assignment.start(f, w, try f.ctypeFromType(scalar_ty, .complete)); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try a.assign(f, w); + if (lhs != .undef and lhs.eql(rhs)) try w.writeAll(switch (operator) { .lt, .neq, .gt => "false", .lte, .eq, .gte => "true", }) else { - if (need_cast) try writer.writeAll("(void*)"); - try f.writeCValue(writer, lhs, .Other); - try v.elem(f, writer); - try writer.writeAll(compareOperatorC(operator)); - if (need_cast) try writer.writeAll("(void*)"); - try f.writeCValue(writer, rhs, .Other); - try v.elem(f, writer); - } - try a.end(f, writer); - try v.end(f, inst, writer); + if (need_cast) try w.writeAll("(void*)"); + try f.writeCValue(w, lhs, .Other); + try v.elem(f, w); + try w.writeAll(compareOperatorC(operator)); + if (need_cast) try w.writeAll("(void*)"); + try f.writeCValue(w, rhs, .Other); + try v.elem(f, w); + } + try a.end(f, w); + try v.end(f, inst, w); return local; } @@ -4475,41 +4542,41 @@ fn airEquality( const rhs = try f.resolveInst(bin_op.rhs); try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, .bool); - const a = try Assignment.start(f, writer, .bool); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); + const a = try Assignment.start(f, w, .bool); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); const operand_ctype = try f.ctypeFromType(operand_ty, .complete); - if (lhs != .undef and lhs.eql(rhs)) try writer.writeAll(switch (operator) { + if (lhs != .undef and lhs.eql(rhs)) try w.writeAll(switch (operator) { .lt, .lte, .gte, .gt => unreachable, .neq => "false", .eq => "true", }) else switch (operand_ctype.info(ctype_pool)) { .basic, .pointer => { - try f.writeCValue(writer, lhs, .Other); - try writer.writeAll(compareOperatorC(operator)); - try f.writeCValue(writer, rhs, .Other); + try f.writeCValue(w, lhs, .Other); + try w.writeAll(compareOperatorC(operator)); + try f.writeCValue(w, rhs, .Other); }, .aligned, .array, .vector, .fwd_decl, .function => unreachable, .aggregate => |aggregate| if (aggregate.fields.len == 2 and (aggregate.fields.at(0, ctype_pool).name.index == .is_null or aggregate.fields.at(1, ctype_pool).name.index == .is_null)) { - try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" }); - try writer.writeAll(" || "); - try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" }); - try writer.writeAll(" ? "); - try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" }); - try writer.writeAll(compareOperatorC(operator)); - try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" }); - try writer.writeAll(" : "); - try f.writeCValueMember(writer, lhs, .{ .identifier = "payload" }); - try writer.writeAll(compareOperatorC(operator)); - try f.writeCValueMember(writer, rhs, .{ .identifier = "payload" }); + try f.writeCValueMember(w, lhs, .{ .identifier = "is_null" }); + try w.writeAll(" || "); + try f.writeCValueMember(w, rhs, .{ .identifier = "is_null" }); + try w.writeAll(" ? "); + try f.writeCValueMember(w, lhs, .{ .identifier = "is_null" }); + try w.writeAll(compareOperatorC(operator)); + try f.writeCValueMember(w, rhs, .{ .identifier = "is_null" }); + try w.writeAll(" : "); + try f.writeCValueMember(w, lhs, .{ .identifier = "payload" }); + try w.writeAll(compareOperatorC(operator)); + try f.writeCValueMember(w, rhs, .{ .identifier = "payload" }); } else for (0..aggregate.fields.len) |field_index| { - if (field_index > 0) try writer.writeAll(switch (operator) { + if (field_index > 0) try w.writeAll(switch (operator) { .lt, .lte, .gte, .gt => unreachable, .eq => " && ", .neq => " || ", @@ -4517,12 +4584,12 @@ fn airEquality( const field_name: CValue = .{ .ctype_pool_string = aggregate.fields.at(field_index, ctype_pool).name, }; - try f.writeCValueMember(writer, lhs, field_name); - try writer.writeAll(compareOperatorC(operator)); - try f.writeCValueMember(writer, rhs, field_name); + try f.writeCValueMember(w, lhs, field_name); + try w.writeAll(compareOperatorC(operator)); + try f.writeCValueMember(w, rhs, field_name); }, } - try a.end(f, writer); + try a.end(f, w); return local; } @@ -4533,12 +4600,13 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { const operand = try f.resolveInst(un_op); try reap(f, inst, &.{un_op}); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, .bool); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = "); - try f.writeCValue(writer, operand, .Other); - try writer.print(" < sizeof({ }) / sizeof(*{0 });\n", .{fmtIdent("zig_errorName")}); + try f.writeCValue(w, local, .Other); + try w.writeAll(" = "); + try f.writeCValue(w, operand, .Other); + try w.print(" < sizeof({f}) / sizeof(*{0f});", .{fmtIdentSolo("zig_errorName")}); + try f.object.newline(); return local; } @@ -4559,30 +4627,30 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete); const local = try f.allocLocal(inst, inst_ty); - const writer = f.object.writer(); - const v = try Vectorize.start(f, inst, writer, inst_ty); - const a = try Assignment.start(f, writer, inst_scalar_ctype); - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try a.assign(f, writer); + const w = &f.object.code.writer; + const v = try Vectorize.start(f, inst, w, inst_ty); + const a = try Assignment.start(f, w, inst_scalar_ctype); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try a.assign(f, w); // We must convert to and from integer types to prevent UB if the operation // results in a NULL pointer, or if LHS is NULL. The operation is only UB // if the result is NULL and then dereferenced. - try writer.writeByte('('); - try f.renderCType(writer, inst_scalar_ctype); - try writer.writeAll(")(((uintptr_t)"); - try f.writeCValue(writer, lhs, .Other); - try v.elem(f, writer); - try writer.writeAll(") "); - try writer.writeByte(operator); - try writer.writeAll(" ("); - try f.writeCValue(writer, rhs, .Other); - try v.elem(f, writer); - try writer.writeAll("*sizeof("); - try f.renderType(writer, elem_ty); - try writer.writeAll(")))"); - try a.end(f, writer); - try v.end(f, inst, writer); + try w.writeByte('('); + try f.renderCType(w, inst_scalar_ctype); + try w.writeAll(")(((uintptr_t)"); + try f.writeCValue(w, lhs, .Other); + try v.elem(f, w); + try w.writeAll(") "); + try w.writeByte(operator); + try w.writeAll(" ("); + try f.writeCValue(w, rhs, .Other); + try v.elem(f, w); + try w.writeAll("*sizeof("); + try f.renderType(w, elem_ty); + try w.writeAll(")))"); + try a.end(f, w); + try v.end(f, inst, w); return local; } @@ -4601,28 +4669,29 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons const rhs = try f.resolveInst(bin_op.rhs); try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, writer, inst_ty); - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); + const v = try Vectorize.start(f, inst, w, inst_ty); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); // (lhs <> rhs) ? lhs : rhs - try writer.writeAll(" = ("); - try f.writeCValue(writer, lhs, .Other); - try v.elem(f, writer); - try writer.writeByte(' '); - try writer.writeByte(operator); - try writer.writeByte(' '); - try f.writeCValue(writer, rhs, .Other); - try v.elem(f, writer); - try writer.writeAll(") ? "); - try f.writeCValue(writer, lhs, .Other); - try v.elem(f, writer); - try writer.writeAll(" : "); - try f.writeCValue(writer, rhs, .Other); - try v.elem(f, writer); - try writer.writeAll(";\n"); - try v.end(f, inst, writer); + try w.writeAll(" = ("); + try f.writeCValue(w, lhs, .Other); + try v.elem(f, w); + try w.writeByte(' '); + try w.writeByte(operator); + try w.writeByte(' '); + try f.writeCValue(w, rhs, .Other); + try v.elem(f, w); + try w.writeAll(") ? "); + try f.writeCValue(w, lhs, .Other); + try v.elem(f, w); + try w.writeAll(" : "); + try f.writeCValue(w, rhs, .Other); + try v.elem(f, w); + try w.writeByte(';'); + try f.object.newline(); + try v.end(f, inst, w); return local; } @@ -4640,21 +4709,21 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { const inst_ty = f.typeOfIndex(inst); const ptr_ty = inst_ty.slicePtrFieldType(zcu); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); { - const a = try Assignment.start(f, writer, try f.ctypeFromType(ptr_ty, .complete)); - try f.writeCValueMember(writer, local, .{ .identifier = "ptr" }); - try a.assign(f, writer); - try f.writeCValue(writer, ptr, .Other); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(ptr_ty, .complete)); + try f.writeCValueMember(w, local, .{ .identifier = "ptr" }); + try a.assign(f, w); + try f.writeCValue(w, ptr, .Other); + try a.end(f, w); } { - const a = try Assignment.start(f, writer, .usize); - try f.writeCValueMember(writer, local, .{ .identifier = "len" }); - try a.assign(f, writer); - try f.writeCValue(writer, len, .Other); - try a.end(f, writer); + const a = try Assignment.start(f, w, .usize); + try f.writeCValueMember(w, local, .{ .identifier = "len" }); + try a.assign(f, w); + try f.writeCValue(w, len, .Other); + try a.end(f, w); } return local; } @@ -4671,7 +4740,7 @@ fn airCall( if (f.object.dg.is_naked_fn) return .none; const gpa = f.object.dg.gpa; - const writer = f.object.writer(); + const w = &f.object.code.writer; const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const extra = f.air.extraData(Air.Call, pl_op.payload); @@ -4692,13 +4761,14 @@ fn airCall( .ctype = arg_ctype, .alignas = CType.AlignAs.fromAbiAlignment(arg_ty.abiAlignment(zcu)), }); - try writer.writeAll("memcpy("); - try f.writeCValueMember(writer, array_local, .{ .identifier = "array" }); - try writer.writeAll(", "); - try f.writeCValue(writer, resolved_arg.*, .FunctionArgument); - try writer.writeAll(", sizeof("); - try f.renderCType(writer, arg_ctype); - try writer.writeAll("));\n"); + try w.writeAll("memcpy("); + try f.writeCValueMember(w, array_local, .{ .identifier = "array" }); + try w.writeAll(", "); + try f.writeCValue(w, resolved_arg.*, .FunctionArgument); + try w.writeAll(", sizeof("); + try f.renderCType(w, arg_ctype); + try w.writeAll("));"); + try f.object.newline(); resolved_arg.* = array_local; } } @@ -4726,22 +4796,22 @@ fn airCall( const result_local = result: { if (modifier == .always_tail) { - try writer.writeAll("zig_always_tail return "); + try w.writeAll("zig_always_tail return "); break :result .none; } else if (ret_ctype.index == .void) { break :result .none; } else if (f.liveness.isUnused(inst)) { - try writer.writeByte('('); - try f.renderCType(writer, .void); - try writer.writeByte(')'); + try w.writeByte('('); + try f.renderCType(w, .void); + try w.writeByte(')'); break :result .none; } else { const local = try f.allocAlignedLocal(inst, .{ .ctype = ret_ctype, .alignas = CType.AlignAs.fromAbiAlignment(ret_ty.abiAlignment(zcu)), }); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = "); + try f.writeCValue(w, local, .Other); + try w.writeAll(" = "); break :result local; } }; @@ -4761,17 +4831,17 @@ fn airCall( else => break :known, }; if (need_cast) { - try writer.writeAll("(("); - try f.renderType(writer, if (callee_is_ptr) callee_ty else try pt.singleConstPtrType(callee_ty)); - try writer.writeByte(')'); - if (!callee_is_ptr) try writer.writeByte('&'); + try w.writeAll("(("); + try f.renderType(w, if (callee_is_ptr) callee_ty else try pt.singleConstPtrType(callee_ty)); + try w.writeByte(')'); + if (!callee_is_ptr) try w.writeByte('&'); } switch (modifier) { - .auto, .always_tail => try f.object.dg.renderNavName(writer, fn_nav), - inline .never_tail, .never_inline => |m| try writer.writeAll(try f.getLazyFnName(@unionInit(LazyFnKey, @tagName(m), fn_nav))), + .auto, .always_tail => try f.object.dg.renderNavName(w, fn_nav), + inline .never_tail, .never_inline => |m| try w.writeAll(try f.getLazyFnName(@unionInit(LazyFnKey, @tagName(m), fn_nav))), else => unreachable, } - if (need_cast) try writer.writeByte(')'); + if (need_cast) try w.writeByte(')'); break :callee; } switch (modifier) { @@ -4781,32 +4851,37 @@ fn airCall( else => unreachable, } // Fall back to function pointer call. - try f.writeCValue(writer, callee, .Other); + try f.writeCValue(w, callee, .Other); } - try writer.writeByte('('); + try w.writeByte('('); var need_comma = false; for (resolved_args) |resolved_arg| { if (resolved_arg == .none) continue; - if (need_comma) try writer.writeAll(", "); + if (need_comma) try w.writeAll(", "); need_comma = true; - try f.writeCValue(writer, resolved_arg, .FunctionArgument); + try f.writeCValue(w, resolved_arg, .FunctionArgument); try f.freeCValue(inst, resolved_arg); } - try writer.writeAll(");\n"); + try w.writeAll(");"); + switch (modifier) { + .always_tail => try w.writeByte('\n'), + else => try f.object.newline(), + } const result = result: { if (result_local == .none or !lowersToArray(ret_ty, pt)) break :result result_local; const array_local = try f.allocLocal(inst, ret_ty); - try writer.writeAll("memcpy("); - try f.writeCValue(writer, array_local, .FunctionArgument); - try writer.writeAll(", "); - try f.writeCValueMember(writer, result_local, .{ .identifier = "array" }); - try writer.writeAll(", sizeof("); - try f.renderType(writer, ret_ty); - try writer.writeAll("));\n"); + try w.writeAll("memcpy("); + try f.writeCValue(w, array_local, .FunctionArgument); + try w.writeAll(", "); + try f.writeCValueMember(w, result_local, .{ .identifier = "array" }); + try w.writeAll(", sizeof("); + try f.renderType(w, ret_ty); + try w.writeAll("));"); + try f.object.newline(); try freeLocal(f, inst, result_local.new_local, null); break :result array_local; }; @@ -4816,7 +4891,7 @@ fn airCall( fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { const dbg_stmt = f.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt; - const writer = f.object.writer(); + const w = &f.object.code.writer; // TODO re-evaluate whether to emit these or not. If we naively emit // these directives, the output file will report bogus line numbers because // every newline after the #line directive adds one to the line. @@ -4824,13 +4899,16 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { // If we wanted to go this route, we would need to go all the way and not output // newlines until the next dbg_stmt occurs. // Perhaps an additional compilation option is in order? - //try writer.print("#line {d}\n", .{dbg_stmt.line + 1}); - try writer.print("/* file:{d}:{d} */\n", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 }); + //try w.print("#line {d}", .{dbg_stmt.line + 1}); + //try f.object.newline(); + try w.print("/* file:{d}:{d} */", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 }); + try f.object.newline(); return .none; } fn airDbgEmptyStmt(f: *Function, _: Air.Inst.Index) !CValue { - try f.object.writer().writeAll("(void)0;\n"); + try f.object.code.writer.writeAll("(void)0;"); + try f.object.newline(); return .none; } @@ -4841,8 +4919,9 @@ fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue { const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = f.air.extraData(Air.DbgInlineBlock, ty_pl.payload); const owner_nav = ip.getNav(zcu.funcInfo(extra.data.func).owner_nav); - const writer = f.object.writer(); - try writer.print("/* inline:{} */\n", .{owner_nav.fqn.fmt(&zcu.intern_pool)}); + const w = &f.object.code.writer; + try w.print("/* inline:{f} */", .{owner_nav.fqn.fmt(&zcu.intern_pool)}); + try f.object.newline(); return lowerBlock(f, inst, @ptrCast(f.air.extra.items[extra.end..][0..extra.data.body_len])); } @@ -4856,8 +4935,9 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { if (!operand_is_undef) _ = try f.resolveInst(pl_op.operand); try reap(f, inst, &.{pl_op.operand}); - const writer = f.object.writer(); - try writer.print("/* {s}:{s} */\n", .{ @tagName(tag), name.toSlice(f.air) }); + const w = &f.object.code.writer; + try w.print("/* {s}:{s} */", .{ @tagName(tag), name.toSlice(f.air) }); + try f.object.newline(); return .none; } @@ -4874,7 +4954,7 @@ fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index) const block_id = f.next_block_index; f.next_block_index += 1; - const writer = f.object.writer(); + const w = &f.object.code.writer; const inst_ty = f.typeOfIndex(inst); const result = if (inst_ty.hasRuntimeBitsIgnoreComptime(zcu) and !f.liveness.isUnused(inst)) @@ -4896,8 +4976,6 @@ fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index) try die(f, inst, death.toRef()); } - try f.object.indent_writer.insertNewline(); - // noreturn blocks have no `br` instructions reaching them, so we don't want a label if (f.object.dg.is_naked_fn) { if (f.object.dg.expected_block) |expected_block| { @@ -4907,7 +4985,8 @@ fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index) } } else if (!f.typeOfIndex(inst).isNoReturn(zcu)) { // label must be followed by an expression, include an empty one. - try writer.print("zig_block_{d}:;\n", .{block_id}); + try w.print("\nzig_block_{d}:;", .{block_id}); + try f.object.newline(); } return result; @@ -4944,31 +5023,31 @@ fn lowerTry( const err_union = try f.resolveInst(operand); const inst_ty = f.typeOfIndex(inst); const liveness_condbr = f.liveness.getCondBr(inst); - const writer = f.object.writer(); + const w = &f.object.code.writer; const payload_ty = err_union_ty.errorUnionPayload(zcu); const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(zcu); if (!err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) { - try writer.writeAll("if ("); + try w.writeAll("if ("); if (!payload_has_bits) { if (is_ptr) - try f.writeCValueDeref(writer, err_union) + try f.writeCValueDeref(w, err_union) else - try f.writeCValue(writer, err_union, .Other); + try f.writeCValue(w, err_union, .Other); } else { // Reap the operand so that it can be reused inside genBody. // Remember we must avoid calling reap() twice for the same operand // in this function. try reap(f, inst, &.{operand}); if (is_ptr) - try f.writeCValueDerefMember(writer, err_union, .{ .identifier = "error" }) + try f.writeCValueDerefMember(w, err_union, .{ .identifier = "error" }) else - try f.writeCValueMember(writer, err_union, .{ .identifier = "error" }); + try f.writeCValueMember(w, err_union, .{ .identifier = "error" }); } - try writer.writeAll(") "); + try w.writeAll(") "); try genBodyResolveState(f, inst, liveness_condbr.else_deaths, body, false); - try f.object.indent_writer.insertNewline(); + try f.object.newline(); if (f.object.dg.expected_block) |_| return f.fail("runtime code not allowed in naked function", .{}); } @@ -4991,14 +5070,14 @@ fn lowerTry( if (f.liveness.isUnused(inst)) return .none; const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete)); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); if (is_ptr) { - try writer.writeByte('&'); - try f.writeCValueDerefMember(writer, err_union, .{ .identifier = "payload" }); - } else try f.writeCValueMember(writer, err_union, .{ .identifier = "payload" }); - try a.end(f, writer); + try w.writeByte('&'); + try f.writeCValueDerefMember(w, err_union, .{ .identifier = "payload" }); + } else try f.writeCValueMember(w, err_union, .{ .identifier = "payload" }); + try a.end(f, w); return local; } @@ -5006,7 +5085,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !void { const branch = f.air.instructions.items(.data)[@intFromEnum(inst)].br; const block = f.blocks.get(branch.block_inst).?; const result = block.result; - const writer = f.object.writer(); + const w = &f.object.code.writer; if (f.object.dg.is_naked_fn) { if (result != .none) return f.fail("runtime code not allowed in naked function", .{}); @@ -5020,27 +5099,26 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !void { const operand = try f.resolveInst(branch.operand); try reap(f, inst, &.{branch.operand}); - const a = try Assignment.start(f, writer, try f.ctypeFromType(operand_ty, .complete)); - try f.writeCValue(writer, result, .Other); - try a.assign(f, writer); - try f.writeCValue(writer, operand, .Other); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(operand_ty, .complete)); + try f.writeCValue(w, result, .Other); + try a.assign(f, w); + try f.writeCValue(w, operand, .Other); + try a.end(f, w); } - try writer.print("goto zig_block_{d};\n", .{block.block_id}); + try w.print("goto zig_block_{d};\n", .{block.block_id}); } fn airRepeat(f: *Function, inst: Air.Inst.Index) !void { const repeat = f.air.instructions.items(.data)[@intFromEnum(inst)].repeat; - const writer = f.object.writer(); - try writer.print("goto zig_loop_{d};\n", .{@intFromEnum(repeat.loop_inst)}); + try f.object.code.writer.print("goto zig_loop_{d};\n", .{@intFromEnum(repeat.loop_inst)}); } fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void { const pt = f.object.dg.pt; const zcu = pt.zcu; const br = f.air.instructions.items(.data)[@intFromEnum(inst)].br; - const writer = f.object.writer(); + const w = &f.object.code.writer; if (try f.air.value(br.operand, pt)) |cond_val| { // Comptime-known dispatch. Iterate the cases to find the correct @@ -5062,18 +5140,19 @@ fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void { } } } else switch_br.cases_len; - try writer.print("goto zig_switch_{d}_dispatch_{d};\n", .{ @intFromEnum(br.block_inst), target_case_idx }); + try w.print("goto zig_switch_{d}_dispatch_{d};\n", .{ @intFromEnum(br.block_inst), target_case_idx }); return; } // Runtime-known dispatch. Set the switch condition, and branch back. const cond = try f.resolveInst(br.operand); const cond_local = f.loop_switch_conds.get(br.block_inst).?; - try f.writeCValue(writer, .{ .local = cond_local }, .Other); - try writer.writeAll(" = "); - try f.writeCValue(writer, cond, .Other); - try writer.writeAll(";\n"); - try writer.print("goto zig_switch_{d}_loop;", .{@intFromEnum(br.block_inst)}); + try f.writeCValue(w, .{ .local = cond_local }, .Other); + try w.writeAll(" = "); + try f.writeCValue(w, cond, .Other); + try w.writeByte(';'); + try f.object.newline(); + try w.print("goto zig_switch_{d}_loop;\n", .{@intFromEnum(br.block_inst)}); } fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { @@ -5093,7 +5172,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal const zcu = pt.zcu; const target = &f.object.dg.mod.resolved_target.result; const ctype_pool = &f.object.dg.ctype_pool; - const writer = f.object.writer(); + const w = &f.object.code.writer; if (operand_ty.isAbiInt(zcu) and dest_ty.isAbiInt(zcu)) { const src_info = dest_ty.intInfo(zcu); @@ -5104,35 +5183,38 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal if (dest_ty.isPtrAtRuntime(zcu) or operand_ty.isPtrAtRuntime(zcu)) { const local = try f.allocLocal(null, dest_ty); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = ("); - try f.renderType(writer, dest_ty); - try writer.writeByte(')'); - try f.writeCValue(writer, operand, .Other); - try writer.writeAll(";\n"); + try f.writeCValue(w, local, .Other); + try w.writeAll(" = ("); + try f.renderType(w, dest_ty); + try w.writeByte(')'); + try f.writeCValue(w, operand, .Other); + try w.writeByte(';'); + try f.object.newline(); return local; } const operand_lval = if (operand == .constant) blk: { const operand_local = try f.allocLocal(null, operand_ty); - try f.writeCValue(writer, operand_local, .Other); - try writer.writeAll(" = "); - try f.writeCValue(writer, operand, .Other); - try writer.writeAll(";\n"); + try f.writeCValue(w, operand_local, .Other); + try w.writeAll(" = "); + try f.writeCValue(w, operand, .Other); + try w.writeByte(';'); + try f.object.newline(); break :blk operand_local; } else operand; const local = try f.allocLocal(null, dest_ty); - try writer.writeAll("memcpy(&"); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(", &"); - try f.writeCValue(writer, operand_lval, .Other); - try writer.writeAll(", sizeof("); + try w.writeAll("memcpy(&"); + try f.writeCValue(w, local, .Other); + try w.writeAll(", &"); + try f.writeCValue(w, operand_lval, .Other); + try w.writeAll(", sizeof("); try f.renderType( - writer, + w, if (dest_ty.abiSize(zcu) <= operand_ty.abiSize(zcu)) dest_ty else operand_ty, ); - try writer.writeAll("));\n"); + try w.writeAll("));"); + try f.object.newline(); // Ensure padding bits have the expected value. if (dest_ty.isAbiInt(zcu)) { @@ -5142,11 +5224,11 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal var wrap_ctype: ?CType = null; var need_bitcasts = false; - try f.writeCValue(writer, local, .Other); + try f.writeCValue(w, local, .Other); switch (dest_ctype.info(ctype_pool)) { else => {}, .array => |array_info| { - try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) { + try w.print("[{d}]", .{switch (target.cpu.arch.endian()) { .little => array_info.len - 1, .big => 0, }}); @@ -5157,92 +5239,98 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal bits += 1; }, } - try writer.writeAll(" = "); + try w.writeAll(" = "); if (need_bitcasts) { - try writer.writeAll("zig_bitCast_"); - try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_ctype.?.toUnsigned()); - try writer.writeByte('('); + try w.writeAll("zig_bitCast_"); + try f.object.dg.renderCTypeForBuiltinFnName(w, wrap_ctype.?.toUnsigned()); + try w.writeByte('('); } - try writer.writeAll("zig_wrap_"); + try w.writeAll("zig_wrap_"); const info_ty = try pt.intType(dest_info.signedness, bits); if (wrap_ctype) |ctype| - try f.object.dg.renderCTypeForBuiltinFnName(writer, ctype) + try f.object.dg.renderCTypeForBuiltinFnName(w, ctype) else - try f.object.dg.renderTypeForBuiltinFnName(writer, info_ty); - try writer.writeByte('('); + try f.object.dg.renderTypeForBuiltinFnName(w, info_ty); + try w.writeByte('('); if (need_bitcasts) { - try writer.writeAll("zig_bitCast_"); - try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_ctype.?); - try writer.writeByte('('); + try w.writeAll("zig_bitCast_"); + try f.object.dg.renderCTypeForBuiltinFnName(w, wrap_ctype.?); + try w.writeByte('('); } - try f.writeCValue(writer, local, .Other); + try f.writeCValue(w, local, .Other); switch (dest_ctype.info(ctype_pool)) { else => {}, - .array => |array_info| try writer.print("[{d}]", .{ + .array => |array_info| try w.print("[{d}]", .{ switch (target.cpu.arch.endian()) { .little => array_info.len - 1, .big => 0, }, }), } - if (need_bitcasts) try writer.writeByte(')'); - try f.object.dg.renderBuiltinInfo(writer, info_ty, .bits); - if (need_bitcasts) try writer.writeByte(')'); - try writer.writeAll(");\n"); + if (need_bitcasts) try w.writeByte(')'); + try f.object.dg.renderBuiltinInfo(w, info_ty, .bits); + if (need_bitcasts) try w.writeByte(')'); + try w.writeAll(");"); + try f.object.newline(); } try f.freeCValue(null, operand_lval); return local; } -fn airTrap(f: *Function, writer: anytype) !void { +fn airTrap(f: *Function, w: *Writer) !void { // Not even allowed to call trap in a naked function. if (f.object.dg.is_naked_fn) return; - try writer.writeAll("zig_trap();\n"); + try w.writeAll("zig_trap();\n"); } -fn airBreakpoint(writer: anytype) !CValue { - try writer.writeAll("zig_breakpoint();\n"); +fn airBreakpoint(f: *Function) !CValue { + const w = &f.object.code.writer; + try w.writeAll("zig_breakpoint();"); + try f.object.newline(); return .none; } fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue { - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, .usize); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = ("); - try f.renderType(writer, .usize); - try writer.writeAll(")zig_return_address();\n"); + try f.writeCValue(w, local, .Other); + try w.writeAll(" = ("); + try f.renderType(w, .usize); + try w.writeAll(")zig_return_address();"); + try f.object.newline(); return local; } fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue { - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, .usize); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = ("); - try f.renderType(writer, .usize); - try writer.writeAll(")zig_frame_address();\n"); + try f.writeCValue(w, local, .Other); + try w.writeAll(" = ("); + try f.renderType(w, .usize); + try w.writeAll(")zig_frame_address();"); + try f.object.newline(); return local; } -fn airUnreach(f: *Function) !void { +fn airUnreach(o: *Object) !void { // Not even allowed to call unreachable in a naked function. - if (f.object.dg.is_naked_fn) return; - try f.object.writer().writeAll("zig_unreachable();\n"); + if (o.dg.is_naked_fn) return; + try o.code.writer.writeAll("zig_unreachable();\n"); } fn airLoop(f: *Function, inst: Air.Inst.Index) !void { const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const loop = f.air.extraData(Air.Block, ty_pl.payload); const body: []const Air.Inst.Index = @ptrCast(f.air.extra.items[loop.end..][0..loop.data.body_len]); - const writer = f.object.writer(); + const w = &f.object.code.writer; // `repeat` instructions matching this loop will branch to // this label. Since we need a label for arbitrary `repeat` // anyway, there's actually no need to use a "real" looping // construct at all! - try writer.print("zig_loop_{d}:\n", .{@intFromEnum(inst)}); + try w.print("zig_loop_{d}:", .{@intFromEnum(inst)}); + try f.object.newline(); try genBodyInner(f, body); // no need to restore state, we're noreturn } @@ -5254,14 +5342,14 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !void { const then_body: []const Air.Inst.Index = @ptrCast(f.air.extra.items[extra.end..][0..extra.data.then_body_len]); const else_body: []const Air.Inst.Index = @ptrCast(f.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]); const liveness_condbr = f.liveness.getCondBr(inst); - const writer = f.object.writer(); + const w = &f.object.code.writer; - try writer.writeAll("if ("); - try f.writeCValue(writer, cond, .Other); - try writer.writeAll(") "); + try w.writeAll("if ("); + try f.writeCValue(w, cond, .Other); + try w.writeAll(") "); try genBodyResolveState(f, inst, liveness_condbr.then_deaths, then_body, false); - try writer.writeByte('\n'); + try f.object.newline(); if (else_body.len > 0) if (f.object.dg.expected_block) |_| return f.fail("runtime code not allowed in naked function", .{}); @@ -5287,7 +5375,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void const init_condition = try f.resolveInst(switch_br.operand); try reap(f, inst, &.{switch_br.operand}); const condition_ty = f.typeOf(switch_br.operand); - const writer = f.object.writer(); + const w = &f.object.code.writer; // For dispatches, we will create a local alloc to contain the condition value. // This may not result in optimal codegen for switch loops, but it minimizes the @@ -5295,7 +5383,8 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void const condition = if (is_dispatch_loop) cond: { const new_local = try f.allocLocal(inst, condition_ty); try f.copyCValue(try f.ctypeFromType(condition_ty, .complete), new_local, init_condition); - try writer.print("zig_switch_{d}_loop:\n", .{@intFromEnum(inst)}); + try w.print("zig_switch_{d}_loop:", .{@intFromEnum(inst)}); + try f.object.newline(); try f.loop_switch_conds.put(gpa, inst, new_local.new_local); break :cond new_local; } else init_condition; @@ -5304,7 +5393,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void assert(f.loop_switch_conds.remove(inst)); }; - try writer.writeAll("switch ("); + try w.writeAll("switch ("); const lowered_condition_ty: Type = if (condition_ty.toIntern() == .bool_type) .u1 @@ -5313,13 +5402,13 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void else condition_ty; if (condition_ty.toIntern() != lowered_condition_ty.toIntern()) { - try writer.writeByte('('); - try f.renderType(writer, lowered_condition_ty); - try writer.writeByte(')'); + try w.writeByte('('); + try f.renderType(w, lowered_condition_ty); + try w.writeByte(')'); } - try f.writeCValue(writer, condition, .Other); - try writer.writeAll(") {"); - f.object.indent_writer.pushIndent(); + try f.writeCValue(w, condition, .Other); + try w.writeAll(") {"); + f.object.indent(); const liveness = try f.liveness.getSwitchBr(gpa, inst, switch_br.cases_len + 1); defer gpa.free(liveness.deaths); @@ -5332,35 +5421,37 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void continue; } for (case.items) |item| { - try f.object.indent_writer.insertNewline(); - try writer.writeAll("case "); + try f.object.newline(); + try w.writeAll("case "); const item_value = try f.air.value(item, pt); // If `item_value` is a pointer with a known integer address, print the address // with no cast to avoid a warning. write_val: { if (condition_ty.isPtrAtRuntime(zcu)) { if (item_value.?.getUnsignedInt(zcu)) |item_int| { - try writer.print("{}", .{try f.fmtIntLiteral(try pt.intValue(lowered_condition_ty, item_int))}); + try w.print("{f}", .{try f.fmtIntLiteralDec(try pt.intValue(lowered_condition_ty, item_int))}); break :write_val; } } if (condition_ty.isPtrAtRuntime(zcu)) { - try writer.writeByte('('); - try f.renderType(writer, .usize); - try writer.writeByte(')'); + try w.writeByte('('); + try f.renderType(w, .usize); + try w.writeByte(')'); } - try f.object.dg.renderValue(writer, (try f.air.value(item, pt)).?, .Other); + try f.object.dg.renderValue(w, (try f.air.value(item, pt)).?, .Other); } - try writer.writeByte(':'); + try w.writeByte(':'); } - try writer.writeAll(" {\n"); - f.object.indent_writer.pushIndent(); + try w.writeAll(" {"); + f.object.indent(); + try f.object.newline(); if (is_dispatch_loop) { - try writer.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), case.idx }); + try w.print("zig_switch_{d}_dispatch_{d}:;", .{ @intFromEnum(inst), case.idx }); + try f.object.newline(); } try genBodyResolveState(f, inst, liveness.deaths[case.idx], case.body, true); - f.object.indent_writer.popIndent(); - try writer.writeByte('}'); + try f.object.outdent(); + try w.writeByte('}'); if (f.object.dg.expected_block) |_| return f.fail("runtime code not allowed in naked function", .{}); @@ -5368,9 +5459,9 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void } const else_body = it.elseBody(); - try f.object.indent_writer.insertNewline(); + try f.object.newline(); - try writer.writeAll("default: "); + try w.writeAll("default: "); if (any_range_cases) { // We will iterate the cases again to handle those with ranges, and generate // code using conditions rather than switch cases for such cases. @@ -5378,40 +5469,41 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void while (it.next()) |case| { if (case.ranges.len == 0) continue; // handled above - try writer.writeAll("if ("); + try w.writeAll("if ("); for (case.items, 0..) |item, item_i| { - if (item_i != 0) try writer.writeAll(" || "); - try f.writeCValue(writer, condition, .Other); - try writer.writeAll(" == "); - try f.object.dg.renderValue(writer, (try f.air.value(item, pt)).?, .Other); + if (item_i != 0) try w.writeAll(" || "); + try f.writeCValue(w, condition, .Other); + try w.writeAll(" == "); + try f.object.dg.renderValue(w, (try f.air.value(item, pt)).?, .Other); } for (case.ranges, 0..) |range, range_i| { - if (case.items.len != 0 or range_i != 0) try writer.writeAll(" || "); + if (case.items.len != 0 or range_i != 0) try w.writeAll(" || "); // "(x >= lower && x <= upper)" - try writer.writeByte('('); - try f.writeCValue(writer, condition, .Other); - try writer.writeAll(" >= "); - try f.object.dg.renderValue(writer, (try f.air.value(range[0], pt)).?, .Other); - try writer.writeAll(" && "); - try f.writeCValue(writer, condition, .Other); - try writer.writeAll(" <= "); - try f.object.dg.renderValue(writer, (try f.air.value(range[1], pt)).?, .Other); - try writer.writeByte(')'); + try w.writeByte('('); + try f.writeCValue(w, condition, .Other); + try w.writeAll(" >= "); + try f.object.dg.renderValue(w, (try f.air.value(range[0], pt)).?, .Other); + try w.writeAll(" && "); + try f.writeCValue(w, condition, .Other); + try w.writeAll(" <= "); + try f.object.dg.renderValue(w, (try f.air.value(range[1], pt)).?, .Other); + try w.writeByte(')'); } - try writer.writeAll(") {\n"); - f.object.indent_writer.pushIndent(); + try w.writeAll(") {"); + f.object.indent(); + try f.object.newline(); if (is_dispatch_loop) { - try writer.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), case.idx }); + try w.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), case.idx }); } try genBodyResolveState(f, inst, liveness.deaths[case.idx], case.body, true); - f.object.indent_writer.popIndent(); - try writer.writeByte('}'); + try f.object.outdent(); + try w.writeByte('}'); if (f.object.dg.expected_block) |_| return f.fail("runtime code not allowed in naked function", .{}); } } if (is_dispatch_loop) { - try writer.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), switch_br.cases_len }); + try w.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), switch_br.cases_len }); } if (else_body.len > 0) { // Note that this must be the last case, so we do not need to use `genBodyResolveState` since @@ -5422,13 +5514,10 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void try genBody(f, else_body); if (f.object.dg.expected_block) |_| return f.fail("runtime code not allowed in naked function", .{}); - } else { - try writer.writeAll("zig_unreachable();"); - } - try f.object.indent_writer.insertNewline(); - - f.object.indent_writer.popIndent(); - try writer.writeAll("}\n"); + } else try airUnreach(&f.object); + try f.object.newline(); + try f.object.outdent(); + try w.writeAll("}\n"); } fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool { @@ -5466,7 +5555,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { extra_i += inputs.len; const result = result: { - const writer = f.object.writer(); + const w = &f.object.code.writer; const inst_ty = f.typeOfIndex(inst); const inst_local = if (inst_ty.hasRuntimeBitsIgnoreComptime(zcu)) local: { const inst_local = try f.allocLocalValue(.{ @@ -5474,10 +5563,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { .alignas = CType.AlignAs.fromAbiAlignment(inst_ty.abiAlignment(zcu)), }); if (f.wantSafety()) { - try f.writeCValue(writer, inst_local, .Other); - try writer.writeAll(" = "); - try f.writeCValue(writer, .{ .undef = inst_ty }, .Other); - try writer.writeAll(";\n"); + try f.writeCValue(w, inst_local, .Other); + try w.writeAll(" = "); + try f.writeCValue(w, .{ .undef = inst_ty }, .Other); + try w.writeByte(';'); + try f.object.newline(); } break :local inst_local; } else .none; @@ -5501,21 +5591,22 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { const is_reg = constraint[1] == '{'; if (is_reg) { const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(zcu); - try writer.writeAll("register "); + try w.writeAll("register "); const output_local = try f.allocLocalValue(.{ .ctype = try f.ctypeFromType(output_ty, .complete), .alignas = CType.AlignAs.fromAbiAlignment(output_ty.abiAlignment(zcu)), }); try f.allocs.put(gpa, output_local.new_local, false); - try f.object.dg.renderTypeAndName(writer, output_ty, output_local, .{}, .none, .complete); - try writer.writeAll(" __asm(\""); - try writer.writeAll(constraint["={".len .. constraint.len - "}".len]); - try writer.writeAll("\")"); + try f.object.dg.renderTypeAndName(w, output_ty, output_local, .{}, .none, .complete); + try w.writeAll(" __asm(\""); + try w.writeAll(constraint["={".len .. constraint.len - "}".len]); + try w.writeAll("\")"); if (f.wantSafety()) { - try writer.writeAll(" = "); - try f.writeCValue(writer, .{ .undef = output_ty }, .Other); + try w.writeAll(" = "); + try f.writeCValue(w, .{ .undef = output_ty }, .Other); } - try writer.writeAll(";\n"); + try w.writeByte(';'); + try f.object.newline(); } } for (inputs) |input| { @@ -5536,21 +5627,22 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { const input_val = try f.resolveInst(input); if (asmInputNeedsLocal(f, constraint, input_val)) { const input_ty = f.typeOf(input); - if (is_reg) try writer.writeAll("register "); + if (is_reg) try w.writeAll("register "); const input_local = try f.allocLocalValue(.{ .ctype = try f.ctypeFromType(input_ty, .complete), .alignas = CType.AlignAs.fromAbiAlignment(input_ty.abiAlignment(zcu)), }); try f.allocs.put(gpa, input_local.new_local, false); - try f.object.dg.renderTypeAndName(writer, input_ty, input_local, Const, .none, .complete); + try f.object.dg.renderTypeAndName(w, input_ty, input_local, Const, .none, .complete); if (is_reg) { - try writer.writeAll(" __asm(\""); - try writer.writeAll(constraint["{".len .. constraint.len - "}".len]); - try writer.writeAll("\")"); + try w.writeAll(" __asm(\""); + try w.writeAll(constraint["{".len .. constraint.len - "}".len]); + try w.writeAll("\")"); } - try writer.writeAll(" = "); - try f.writeCValue(writer, input_val, .Other); - try writer.writeAll(";\n"); + try w.writeAll(" = "); + try f.writeCValue(w, input_val, .Other); + try w.writeByte(';'); + try f.object.newline(); } } for (0..clobbers_len) |_| { @@ -5610,14 +5702,14 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { } } - try writer.writeAll("__asm"); - if (is_volatile) try writer.writeAll(" volatile"); - try writer.print("({s}", .{fmtStringLiteral(fixed_asm_source[0..dst_i], null)}); + try w.writeAll("__asm"); + if (is_volatile) try w.writeAll(" volatile"); + try w.print("({f}", .{fmtStringLiteral(fixed_asm_source[0..dst_i], null)}); } extra_i = constraints_extra_begin; var locals_index = locals_begin; - try writer.writeByte(':'); + try w.writeByte(':'); for (outputs, 0..) |output, index| { const extra_bytes = mem.sliceAsBytes(f.air.extra.items[extra_i..]); const constraint = mem.sliceTo(extra_bytes, 0); @@ -5626,22 +5718,22 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { // for the string, we still use the next u32 for the null terminator. extra_i += (constraint.len + name.len + (2 + 3)) / 4; - if (index > 0) try writer.writeByte(','); - try writer.writeByte(' '); - if (!mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name}); + if (index > 0) try w.writeByte(','); + try w.writeByte(' '); + if (!mem.eql(u8, name, "_")) try w.print("[{s}]", .{name}); const is_reg = constraint[1] == '{'; - try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint, null)}); + try w.print("{f}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint, null)}); if (is_reg) { - try f.writeCValue(writer, .{ .local = locals_index }, .Other); + try f.writeCValue(w, .{ .local = locals_index }, .Other); locals_index += 1; } else if (output == .none) { - try f.writeCValue(writer, inst_local, .FunctionArgument); + try f.writeCValue(w, inst_local, .FunctionArgument); } else { - try f.writeCValueDeref(writer, try f.resolveInst(output)); + try f.writeCValueDeref(w, try f.resolveInst(output)); } - try writer.writeByte(')'); + try w.writeByte(')'); } - try writer.writeByte(':'); + try w.writeByte(':'); for (inputs, 0..) |input, index| { const extra_bytes = mem.sliceAsBytes(f.air.extra.items[extra_i..]); const constraint = mem.sliceTo(extra_bytes, 0); @@ -5650,21 +5742,21 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { // for the string, we still use the next u32 for the null terminator. extra_i += (constraint.len + name.len + (2 + 3)) / 4; - if (index > 0) try writer.writeByte(','); - try writer.writeByte(' '); - if (!mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name}); + if (index > 0) try w.writeByte(','); + try w.writeByte(' '); + if (!mem.eql(u8, name, "_")) try w.print("[{s}]", .{name}); const is_reg = constraint[0] == '{'; const input_val = try f.resolveInst(input); - try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint, null)}); - try f.writeCValue(writer, if (asmInputNeedsLocal(f, constraint, input_val)) local: { + try w.print("{f}(", .{fmtStringLiteral(if (is_reg) "r" else constraint, null)}); + try f.writeCValue(w, if (asmInputNeedsLocal(f, constraint, input_val)) local: { const input_local_idx = locals_index; locals_index += 1; break :local .{ .local = input_local_idx }; } else input_val, .Other); - try writer.writeByte(')'); + try w.writeByte(')'); } - try writer.writeByte(':'); + try w.writeByte(':'); for (0..clobbers_len) |clobber_i| { const clobber = mem.sliceTo(mem.sliceAsBytes(f.air.extra.items[extra_i..]), 0); // This equation accounts for the fact that even if we have exactly 4 bytes @@ -5673,10 +5765,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { if (clobber.len == 0) continue; - if (clobber_i > 0) try writer.writeByte(','); - try writer.print(" {s}", .{fmtStringLiteral(clobber, null)}); + if (clobber_i > 0) try w.writeByte(','); + try w.print(" {f}", .{fmtStringLiteral(clobber, null)}); } - try writer.writeAll(");\n"); + try w.writeAll(");"); + try f.object.newline(); extra_i = constraints_extra_begin; locals_index = locals_begin; @@ -5690,14 +5783,15 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { const is_reg = constraint[1] == '{'; if (is_reg) { - try f.writeCValueDeref(writer, if (output == .none) + try f.writeCValueDeref(w, if (output == .none) .{ .local_ref = inst_local.new_local } else try f.resolveInst(output)); - try writer.writeAll(" = "); - try f.writeCValue(writer, .{ .local = locals_index }, .Other); + try w.writeAll(" = "); + try f.writeCValue(w, .{ .local = locals_index }, .Other); locals_index += 1; - try writer.writeAll(";\n"); + try w.writeByte(';'); + try f.object.newline(); } } @@ -5727,14 +5821,14 @@ fn airIsNull( const ctype_pool = &f.object.dg.ctype_pool; const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const writer = f.object.writer(); + const w = &f.object.code.writer; const operand = try f.resolveInst(un_op); try reap(f, inst, &.{un_op}); const local = try f.allocLocal(inst, .bool); - const a = try Assignment.start(f, writer, .bool); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); + const a = try Assignment.start(f, w, .bool); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); const operand_ty = f.typeOf(un_op); const optional_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty; @@ -5742,9 +5836,9 @@ fn airIsNull( const rhs = switch (opt_ctype.info(ctype_pool)) { .basic, .pointer => rhs: { if (is_ptr) - try f.writeCValueDeref(writer, operand) + try f.writeCValueDeref(w, operand) else - try f.writeCValue(writer, operand, .Other); + try f.writeCValue(w, operand, .Other); break :rhs if (opt_ctype.isBool()) "true" else if (opt_ctype.isInteger()) @@ -5756,24 +5850,24 @@ fn airIsNull( .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) { .is_null, .payload => rhs: { if (is_ptr) - try f.writeCValueDerefMember(writer, operand, .{ .identifier = "is_null" }) + try f.writeCValueDerefMember(w, operand, .{ .identifier = "is_null" }) else - try f.writeCValueMember(writer, operand, .{ .identifier = "is_null" }); + try f.writeCValueMember(w, operand, .{ .identifier = "is_null" }); break :rhs "true"; }, .ptr, .len => rhs: { if (is_ptr) - try f.writeCValueDerefMember(writer, operand, .{ .identifier = "ptr" }) + try f.writeCValueDerefMember(w, operand, .{ .identifier = "ptr" }) else - try f.writeCValueMember(writer, operand, .{ .identifier = "ptr" }); + try f.writeCValueMember(w, operand, .{ .identifier = "ptr" }); break :rhs "NULL"; }, else => unreachable, }, }; - try writer.writeAll(compareOperatorC(operator)); - try writer.writeAll(rhs); - try a.end(f, writer); + try w.writeAll(compareOperatorC(operator)); + try w.writeAll(rhs); + try a.end(f, w); return local; } @@ -5795,16 +5889,16 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue .aligned, .array, .vector, .fwd_decl, .function => unreachable, .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) { .is_null, .payload => { - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete)); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); if (is_ptr) { - try writer.writeByte('&'); - try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" }); - } else try f.writeCValueMember(writer, operand, .{ .identifier = "payload" }); - try a.end(f, writer); + try w.writeByte('&'); + try f.writeCValueDerefMember(w, operand, .{ .identifier = "payload" }); + } else try f.writeCValueMember(w, operand, .{ .identifier = "payload" }); + try a.end(f, w); return local; }, .ptr, .len => return f.moveCValue(inst, inst_ty, operand), @@ -5817,7 +5911,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { const pt = f.object.dg.pt; const zcu = pt.zcu; const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const writer = f.object.writer(); + const w = &f.object.code.writer; const operand = try f.resolveInst(ty_op.operand); try reap(f, inst, &.{ty_op.operand}); const operand_ty = f.typeOf(ty_op.operand); @@ -5826,40 +5920,40 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { const opt_ctype = try f.ctypeFromType(operand_ty.childType(zcu), .complete); switch (opt_ctype.info(&f.object.dg.ctype_pool)) { .basic => { - const a = try Assignment.start(f, writer, opt_ctype); - try f.writeCValueDeref(writer, operand); - try a.assign(f, writer); - try f.object.dg.renderValue(writer, Value.false, .Other); - try a.end(f, writer); + const a = try Assignment.start(f, w, opt_ctype); + try f.writeCValueDeref(w, operand); + try a.assign(f, w); + try f.object.dg.renderValue(w, Value.false, .Other); + try a.end(f, w); return .none; }, .pointer => { if (f.liveness.isUnused(inst)) return .none; const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, opt_ctype); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); - try f.writeCValue(writer, operand, .Other); - try a.end(f, writer); + const a = try Assignment.start(f, w, opt_ctype); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); + try f.writeCValue(w, operand, .Other); + try a.end(f, w); return local; }, .aligned, .array, .vector, .fwd_decl, .function => unreachable, .aggregate => { { - const a = try Assignment.start(f, writer, opt_ctype); - try f.writeCValueDerefMember(writer, operand, .{ .identifier = "is_null" }); - try a.assign(f, writer); - try f.object.dg.renderValue(writer, Value.false, .Other); - try a.end(f, writer); + const a = try Assignment.start(f, w, opt_ctype); + try f.writeCValueDerefMember(w, operand, .{ .identifier = "is_null" }); + try a.assign(f, w); + try f.object.dg.renderValue(w, Value.false, .Other); + try a.end(f, w); } if (f.liveness.isUnused(inst)) return .none; const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, opt_ctype); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); - try writer.writeByte('&'); - try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" }); - try a.end(f, writer); + const a = try Assignment.start(f, w, opt_ctype); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); + try w.writeByte('&'); + try f.writeCValueDerefMember(w, operand, .{ .identifier = "payload" }); + try a.end(f, w); return local; }, } @@ -5967,42 +6061,43 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { const field_ptr_val = try f.resolveInst(extra.field_ptr); try reap(f, inst, &.{extra.field_ptr}); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, container_ptr_ty); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = ("); - try f.renderType(writer, container_ptr_ty); - try writer.writeByte(')'); + try f.writeCValue(w, local, .Other); + try w.writeAll(" = ("); + try f.renderType(w, container_ptr_ty); + try w.writeByte(')'); switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, pt)) { - .begin => try f.writeCValue(writer, field_ptr_val, .Other), + .begin => try f.writeCValue(w, field_ptr_val, .Other), .field => |field| { const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8); - try writer.writeAll("(("); - try f.renderType(writer, u8_ptr_ty); - try writer.writeByte(')'); - try f.writeCValue(writer, field_ptr_val, .Other); - try writer.writeAll(" - offsetof("); - try f.renderType(writer, container_ty); - try writer.writeAll(", "); - try f.writeCValue(writer, field, .Other); - try writer.writeAll("))"); + try w.writeAll("(("); + try f.renderType(w, u8_ptr_ty); + try w.writeByte(')'); + try f.writeCValue(w, field_ptr_val, .Other); + try w.writeAll(" - offsetof("); + try f.renderType(w, container_ty); + try w.writeAll(", "); + try f.writeCValue(w, field, .Other); + try w.writeAll("))"); }, .byte_offset => |byte_offset| { const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8); - try writer.writeAll("(("); - try f.renderType(writer, u8_ptr_ty); - try writer.writeByte(')'); - try f.writeCValue(writer, field_ptr_val, .Other); - try writer.print(" - {})", .{ - try f.fmtIntLiteral(try pt.intValue(.usize, byte_offset)), + try w.writeAll("(("); + try f.renderType(w, u8_ptr_ty); + try w.writeByte(')'); + try f.writeCValue(w, field_ptr_val, .Other); + try w.print(" - {f})", .{ + try f.fmtIntLiteralDec(try pt.intValue(.usize, byte_offset)), }); }, } - try writer.writeAll(";\n"); + try w.writeByte(';'); + try f.object.newline(); return local; } @@ -6021,33 +6116,34 @@ fn fieldPtr( // Ensure complete type definition is visible before accessing fields. _ = try f.ctypeFromType(container_ty, .complete); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, field_ptr_ty); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = ("); - try f.renderType(writer, field_ptr_ty); - try writer.writeByte(')'); + try f.writeCValue(w, local, .Other); + try w.writeAll(" = ("); + try f.renderType(w, field_ptr_ty); + try w.writeByte(')'); switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, pt)) { - .begin => try f.writeCValue(writer, container_ptr_val, .Other), + .begin => try f.writeCValue(w, container_ptr_val, .Other), .field => |field| { - try writer.writeByte('&'); - try f.writeCValueDerefMember(writer, container_ptr_val, field); + try w.writeByte('&'); + try f.writeCValueDerefMember(w, container_ptr_val, field); }, .byte_offset => |byte_offset| { const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8); - try writer.writeAll("(("); - try f.renderType(writer, u8_ptr_ty); - try writer.writeByte(')'); - try f.writeCValue(writer, container_ptr_val, .Other); - try writer.print(" + {})", .{ - try f.fmtIntLiteral(try pt.intValue(.usize, byte_offset)), + try w.writeAll("(("); + try f.renderType(w, u8_ptr_ty); + try w.writeByte(')'); + try f.writeCValue(w, container_ptr_val, .Other); + try w.print(" + {f})", .{ + try f.fmtIntLiteralDec(try pt.intValue(.usize, byte_offset)), }); }, } - try writer.writeAll(";\n"); + try w.writeByte(';'); + try f.object.newline(); return local; } @@ -6067,7 +6163,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { const struct_byval = try f.resolveInst(extra.struct_operand); try reap(f, inst, &.{extra.struct_operand}); const struct_ty = f.typeOf(extra.struct_operand); - const writer = f.object.writer(); + const w = &f.object.code.writer; // Ensure complete type definition is visible before accessing fields. _ = try f.ctypeFromType(struct_ty, .complete); @@ -6094,42 +6190,44 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { const field_int_ty = try pt.intType(field_int_signedness, @as(u16, @intCast(inst_ty.bitSize(zcu)))); const temp_local = try f.allocLocal(inst, field_int_ty); - try f.writeCValue(writer, temp_local, .Other); - try writer.writeAll(" = zig_wrap_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty); - try writer.writeAll("(("); - try f.renderType(writer, field_int_ty); - try writer.writeByte(')'); + try f.writeCValue(w, temp_local, .Other); + try w.writeAll(" = zig_wrap_"); + try f.object.dg.renderTypeForBuiltinFnName(w, field_int_ty); + try w.writeAll("(("); + try f.renderType(w, field_int_ty); + try w.writeByte(')'); const cant_cast = int_info.bits > 64; if (cant_cast) { if (field_int_ty.bitSize(zcu) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); - try writer.writeAll("zig_lo_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); - try writer.writeByte('('); + try w.writeAll("zig_lo_"); + try f.object.dg.renderTypeForBuiltinFnName(w, struct_ty); + try w.writeByte('('); } if (bit_offset > 0) { - try writer.writeAll("zig_shr_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); - try writer.writeByte('('); + try w.writeAll("zig_shr_"); + try f.object.dg.renderTypeForBuiltinFnName(w, struct_ty); + try w.writeByte('('); } - try f.writeCValue(writer, struct_byval, .Other); - if (bit_offset > 0) try writer.print(", {})", .{ - try f.fmtIntLiteral(try pt.intValue(bit_offset_ty, bit_offset)), + try f.writeCValue(w, struct_byval, .Other); + if (bit_offset > 0) try w.print(", {f})", .{ + try f.fmtIntLiteralDec(try pt.intValue(bit_offset_ty, bit_offset)), }); - if (cant_cast) try writer.writeByte(')'); - try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .bits); - try writer.writeAll(");\n"); + if (cant_cast) try w.writeByte(')'); + try f.object.dg.renderBuiltinInfo(w, field_int_ty, .bits); + try w.writeAll(");"); + try f.object.newline(); if (inst_ty.eql(field_int_ty, zcu)) return temp_local; const local = try f.allocLocal(inst, inst_ty); if (local.new_local != temp_local.new_local) { - try writer.writeAll("memcpy("); - try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument); - try writer.writeAll(", "); - try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument); - try writer.writeAll(", sizeof("); - try f.renderType(writer, inst_ty); - try writer.writeAll("));\n"); + try w.writeAll("memcpy("); + try f.writeCValue(w, .{ .local_ref = local.new_local }, .FunctionArgument); + try w.writeAll(", "); + try f.writeCValue(w, .{ .local_ref = temp_local.new_local }, .FunctionArgument); + try w.writeAll(", sizeof("); + try f.renderType(w, inst_ty); + try w.writeAll("));"); + try f.object.newline(); } try freeLocal(f, inst, temp_local.new_local, null); return local; @@ -6150,10 +6248,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { .@"packed" => { const operand_lval = if (struct_byval == .constant) blk: { const operand_local = try f.allocLocal(inst, struct_ty); - try f.writeCValue(writer, operand_local, .Other); - try writer.writeAll(" = "); - try f.writeCValue(writer, struct_byval, .Other); - try writer.writeAll(";\n"); + try f.writeCValue(w, operand_local, .Other); + try w.writeAll(" = "); + try f.writeCValue(w, struct_byval, .Other); + try w.writeByte(';'); + try f.object.newline(); break :blk operand_local; } else struct_byval; const local = try f.allocLocal(inst, inst_ty); @@ -6164,13 +6263,14 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { }, else => true, }) { - try writer.writeAll("memcpy(&"); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(", &"); - try f.writeCValue(writer, operand_lval, .Other); - try writer.writeAll(", sizeof("); - try f.renderType(writer, inst_ty); - try writer.writeAll("));\n"); + try w.writeAll("memcpy(&"); + try f.writeCValue(w, local, .Other); + try w.writeAll(", &"); + try f.writeCValue(w, operand_lval, .Other); + try w.writeAll(", sizeof("); + try f.renderType(w, inst_ty); + try w.writeAll("));"); + try f.object.newline(); } try f.freeCValue(inst, operand_lval); return local; @@ -6181,11 +6281,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { }; const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); - try f.writeCValueMember(writer, struct_byval, field_name); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete)); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); + try f.writeCValueMember(w, struct_byval, field_name); + try a.end(f, w); return local; } @@ -6212,21 +6312,22 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { return local; } - const writer = f.object.writer(); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = "); + const w = &f.object.code.writer; + try f.writeCValue(w, local, .Other); + try w.writeAll(" = "); if (!payload_ty.hasRuntimeBits(zcu)) - try f.writeCValue(writer, operand, .Other) + try f.writeCValue(w, operand, .Other) else if (error_ty.errorSetIsEmpty(zcu)) - try writer.print("{}", .{ - try f.fmtIntLiteral(try pt.intValue(try pt.errorIntType(), 0)), + try w.print("{f}", .{ + try f.fmtIntLiteralDec(try pt.intValue(try pt.errorIntType(), 0)), }) else if (operand_is_ptr) - try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }) + try f.writeCValueDerefMember(w, operand, .{ .identifier = "error" }) else - try f.writeCValueMember(writer, operand, .{ .identifier = "error" }); - try writer.writeAll(";\n"); + try f.writeCValueMember(w, operand, .{ .identifier = "error" }); + try w.writeByte(';'); + try f.object.newline(); return local; } @@ -6241,29 +6342,30 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu const operand_ty = f.typeOf(ty_op.operand); const error_union_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty; - const writer = f.object.writer(); + const w = &f.object.code.writer; if (!error_union_ty.errorUnionPayload(zcu).hasRuntimeBits(zcu)) { if (!is_ptr) return .none; const local = try f.allocLocal(inst, inst_ty); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = ("); - try f.renderType(writer, inst_ty); - try writer.writeByte(')'); - try f.writeCValue(writer, operand, .Other); - try writer.writeAll(";\n"); + try f.writeCValue(w, local, .Other); + try w.writeAll(" = ("); + try f.renderType(w, inst_ty); + try w.writeByte(')'); + try f.writeCValue(w, operand, .Other); + try w.writeByte(';'); + try f.object.newline(); return local; } const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete)); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); if (is_ptr) { - try writer.writeByte('&'); - try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" }); - } else try f.writeCValueMember(writer, operand, .{ .identifier = "payload" }); - try a.end(f, writer); + try w.writeByte('&'); + try f.writeCValueDerefMember(w, operand, .{ .identifier = "payload" }); + } else try f.writeCValueMember(w, operand, .{ .identifier = "payload" }); + try a.end(f, w); return local; } @@ -6282,21 +6384,21 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) { .is_null, .payload => { const operand_ctype = try f.ctypeFromType(f.typeOf(ty_op.operand), .complete); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); { - const a = try Assignment.start(f, writer, .bool); - try f.writeCValueMember(writer, local, .{ .identifier = "is_null" }); - try a.assign(f, writer); - try writer.writeAll("false"); - try a.end(f, writer); + const a = try Assignment.start(f, w, .bool); + try f.writeCValueMember(w, local, .{ .identifier = "is_null" }); + try a.assign(f, w); + try w.writeAll("false"); + try a.end(f, w); } { - const a = try Assignment.start(f, writer, operand_ctype); - try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); - try a.assign(f, writer); - try f.writeCValue(writer, operand, .Other); - try a.end(f, writer); + const a = try Assignment.start(f, w, operand_ctype); + try f.writeCValueMember(w, local, .{ .identifier = "payload" }); + try a.assign(f, w); + try f.writeCValue(w, operand, .Other); + try a.end(f, w); } return local; }, @@ -6318,7 +6420,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { const err = try f.resolveInst(ty_op.operand); try reap(f, inst, &.{ty_op.operand}); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); if (repr_is_err and err == .local and err.local == local.new_local) { @@ -6327,21 +6429,21 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { } if (!repr_is_err) { - const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete)); - try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); - try a.assign(f, writer); - try f.object.dg.renderUndefValue(writer, payload_ty, .Other); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(payload_ty, .complete)); + try f.writeCValueMember(w, local, .{ .identifier = "payload" }); + try a.assign(f, w); + try f.object.dg.renderUndefValue(w, payload_ty, .Other); + try a.end(f, w); } { - const a = try Assignment.start(f, writer, try f.ctypeFromType(err_ty, .complete)); + const a = try Assignment.start(f, w, try f.ctypeFromType(err_ty, .complete)); if (repr_is_err) - try f.writeCValue(writer, local, .Other) + try f.writeCValue(w, local, .Other) else - try f.writeCValueMember(writer, local, .{ .identifier = "error" }); - try a.assign(f, writer); - try f.writeCValue(writer, err, .Other); - try a.end(f, writer); + try f.writeCValueMember(w, local, .{ .identifier = "error" }); + try a.assign(f, w); + try f.writeCValue(w, err, .Other); + try a.end(f, w); } return local; } @@ -6349,7 +6451,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { const pt = f.object.dg.pt; const zcu = pt.zcu; - const writer = f.object.writer(); + const w = &f.object.code.writer; const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const inst_ty = f.typeOfIndex(inst); const operand = try f.resolveInst(ty_op.operand); @@ -6363,31 +6465,31 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { // First, set the non-error value. if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { - const a = try Assignment.start(f, writer, try f.ctypeFromType(operand_ty, .complete)); - try f.writeCValueDeref(writer, operand); - try a.assign(f, writer); - try writer.print("{}", .{try f.fmtIntLiteral(no_err)}); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(operand_ty, .complete)); + try f.writeCValueDeref(w, operand); + try a.assign(f, w); + try w.print("{f}", .{try f.fmtIntLiteralDec(no_err)}); + try a.end(f, w); return .none; } { - const a = try Assignment.start(f, writer, try f.ctypeFromType(err_int_ty, .complete)); - try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }); - try a.assign(f, writer); - try writer.print("{}", .{try f.fmtIntLiteral(no_err)}); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(err_int_ty, .complete)); + try f.writeCValueDerefMember(w, operand, .{ .identifier = "error" }); + try a.assign(f, w); + try w.print("{f}", .{try f.fmtIntLiteralDec(no_err)}); + try a.end(f, w); } // Then return the payload pointer (only if it is used) if (f.liveness.isUnused(inst)) return .none; const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); - try writer.writeByte('&'); - try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" }); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete)); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); + try w.writeByte('&'); + try f.writeCValueDerefMember(w, operand, .{ .identifier = "payload" }); + try a.end(f, w); return local; } @@ -6418,24 +6520,24 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { const err_ty = inst_ty.errorUnionSet(zcu); try reap(f, inst, &.{ty_op.operand}); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); if (!repr_is_err) { - const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete)); - try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); - try a.assign(f, writer); - try f.writeCValue(writer, payload, .Other); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(payload_ty, .complete)); + try f.writeCValueMember(w, local, .{ .identifier = "payload" }); + try a.assign(f, w); + try f.writeCValue(w, payload, .Other); + try a.end(f, w); } { - const a = try Assignment.start(f, writer, try f.ctypeFromType(err_ty, .complete)); + const a = try Assignment.start(f, w, try f.ctypeFromType(err_ty, .complete)); if (repr_is_err) - try f.writeCValue(writer, local, .Other) + try f.writeCValue(w, local, .Other) else - try f.writeCValueMember(writer, local, .{ .identifier = "error" }); - try a.assign(f, writer); - try f.object.dg.renderValue(writer, try pt.intValue(try pt.errorIntType(), 0), .Other); - try a.end(f, writer); + try f.writeCValueMember(w, local, .{ .identifier = "error" }); + try a.assign(f, w); + try f.object.dg.renderValue(w, try pt.intValue(try pt.errorIntType(), 0), .Other); + try a.end(f, w); } return local; } @@ -6445,7 +6547,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const const zcu = pt.zcu; const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const writer = f.object.writer(); + const w = &f.object.code.writer; const operand = try f.resolveInst(un_op); try reap(f, inst, &.{un_op}); const operand_ty = f.typeOf(un_op); @@ -6454,25 +6556,25 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const const payload_ty = err_union_ty.errorUnionPayload(zcu); const error_ty = err_union_ty.errorUnionSet(zcu); - const a = try Assignment.start(f, writer, .bool); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); + const a = try Assignment.start(f, w, .bool); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); const err_int_ty = try pt.errorIntType(); if (!error_ty.errorSetIsEmpty(zcu)) if (payload_ty.hasRuntimeBits(zcu)) if (is_ptr) - try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }) + try f.writeCValueDerefMember(w, operand, .{ .identifier = "error" }) else - try f.writeCValueMember(writer, operand, .{ .identifier = "error" }) + try f.writeCValueMember(w, operand, .{ .identifier = "error" }) else - try f.writeCValue(writer, operand, .Other) + try f.writeCValue(w, operand, .Other) else - try f.object.dg.renderValue(writer, try pt.intValue(err_int_ty, 0), .Other); - try writer.writeByte(' '); - try writer.writeAll(operator); - try writer.writeByte(' '); - try f.object.dg.renderValue(writer, try pt.intValue(err_int_ty, 0), .Other); - try a.end(f, writer); + try f.object.dg.renderValue(w, try pt.intValue(err_int_ty, 0), .Other); + try w.writeByte(' '); + try w.writeAll(operator); + try w.writeByte(' '); + try f.object.dg.renderValue(w, try pt.intValue(err_int_ty, 0), .Other); + try a.end(f, w); return local; } @@ -6486,45 +6588,45 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { try reap(f, inst, &.{ty_op.operand}); const inst_ty = f.typeOfIndex(inst); const ptr_ty = inst_ty.slicePtrFieldType(zcu); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); const operand_ty = f.typeOf(ty_op.operand); const array_ty = operand_ty.childType(zcu); { - const a = try Assignment.start(f, writer, try f.ctypeFromType(ptr_ty, .complete)); - try f.writeCValueMember(writer, local, .{ .identifier = "ptr" }); - try a.assign(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(ptr_ty, .complete)); + try f.writeCValueMember(w, local, .{ .identifier = "ptr" }); + try a.assign(f, w); if (operand == .undef) { - try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(zcu) }, .Other); + try f.writeCValue(w, .{ .undef = inst_ty.slicePtrFieldType(zcu) }, .Other); } else { const ptr_ctype = try f.ctypeFromType(ptr_ty, .complete); const ptr_child_ctype = ptr_ctype.info(ctype_pool).pointer.elem_ctype; const elem_ty = array_ty.childType(zcu); const elem_ctype = try f.ctypeFromType(elem_ty, .complete); if (!ptr_child_ctype.eql(elem_ctype)) { - try writer.writeByte('('); - try f.renderCType(writer, ptr_ctype); - try writer.writeByte(')'); + try w.writeByte('('); + try f.renderCType(w, ptr_ctype); + try w.writeByte(')'); } const operand_ctype = try f.ctypeFromType(operand_ty, .complete); const operand_child_ctype = operand_ctype.info(ctype_pool).pointer.elem_ctype; if (operand_child_ctype.info(ctype_pool) == .array) { - try writer.writeByte('&'); - try f.writeCValueDeref(writer, operand); - try writer.print("[{}]", .{try f.fmtIntLiteral(.zero_usize)}); - } else try f.writeCValue(writer, operand, .Other); + try w.writeByte('&'); + try f.writeCValueDeref(w, operand); + try w.print("[{f}]", .{try f.fmtIntLiteralDec(.zero_usize)}); + } else try f.writeCValue(w, operand, .Other); } - try a.end(f, writer); + try a.end(f, w); } { - const a = try Assignment.start(f, writer, .usize); - try f.writeCValueMember(writer, local, .{ .identifier = "len" }); - try a.assign(f, writer); - try writer.print("{}", .{ - try f.fmtIntLiteral(try pt.intValue(.usize, array_ty.arrayLen(zcu))), + const a = try Assignment.start(f, w, .usize); + try f.writeCValueMember(w, local, .{ .identifier = "len" }); + try a.assign(f, w); + try w.print("{f}", .{ + try f.fmtIntLiteralDec(try pt.intValue(.usize, array_ty.arrayLen(zcu))), }); - try a.end(f, writer); + try a.end(f, w); } return local; @@ -6551,32 +6653,32 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { else unreachable; - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, writer, operand_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(scalar_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try a.assign(f, writer); + const v = try Vectorize.start(f, inst, w, operand_ty); + const a = try Assignment.start(f, w, try f.ctypeFromType(scalar_ty, .complete)); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try a.assign(f, w); if (inst_scalar_ty.isInt(zcu) and scalar_ty.isRuntimeFloat()) { - try writer.writeAll("zig_wrap_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, inst_scalar_ty); - try writer.writeByte('('); - } - try writer.writeAll("zig_"); - try writer.writeAll(operation); - try writer.writeAll(compilerRtAbbrev(scalar_ty, zcu, target)); - try writer.writeAll(compilerRtAbbrev(inst_scalar_ty, zcu, target)); - try writer.writeByte('('); - try f.writeCValue(writer, operand, .FunctionArgument); - try v.elem(f, writer); - try writer.writeByte(')'); + try w.writeAll("zig_wrap_"); + try f.object.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty); + try w.writeByte('('); + } + try w.writeAll("zig_"); + try w.writeAll(operation); + try w.writeAll(compilerRtAbbrev(scalar_ty, zcu, target)); + try w.writeAll(compilerRtAbbrev(inst_scalar_ty, zcu, target)); + try w.writeByte('('); + try f.writeCValue(w, operand, .FunctionArgument); + try v.elem(f, w); + try w.writeByte(')'); if (inst_scalar_ty.isInt(zcu) and scalar_ty.isRuntimeFloat()) { - try f.object.dg.renderBuiltinInfo(writer, inst_scalar_ty, .bits); - try writer.writeByte(')'); + try f.object.dg.renderBuiltinInfo(w, inst_scalar_ty, .bits); + try w.writeByte(')'); } - try a.end(f, writer); - try v.end(f, inst, writer); + try a.end(f, w); + try v.end(f, inst, w); return local; } @@ -6601,27 +6703,28 @@ fn airUnBuiltinCall( const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete); const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array; - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, writer, operand_ty); + const v = try Vectorize.start(f, inst, w, operand_ty); if (!ref_ret) { - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try writer.writeAll(" = "); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try w.writeAll(" = "); } - try writer.print("zig_{s}_", .{operation}); - try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); - try writer.writeByte('('); + try w.print("zig_{s}_", .{operation}); + try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty); + try w.writeByte('('); if (ref_ret) { - try f.writeCValue(writer, local, .FunctionArgument); - try v.elem(f, writer); - try writer.writeAll(", "); + try f.writeCValue(w, local, .FunctionArgument); + try v.elem(f, w); + try w.writeAll(", "); } - try f.writeCValue(writer, operand, .FunctionArgument); - try v.elem(f, writer); - try f.object.dg.renderBuiltinInfo(writer, scalar_ty, info); - try writer.writeAll(");\n"); - try v.end(f, inst, writer); + try f.writeCValue(w, operand, .FunctionArgument); + try v.elem(f, w); + try f.object.dg.renderBuiltinInfo(w, scalar_ty, info); + try w.writeAll(");"); + try f.object.newline(); + try v.end(f, inst, w); return local; } @@ -6651,31 +6754,31 @@ fn airBinBuiltinCall( const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete); const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array; - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); if (is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); - const v = try Vectorize.start(f, inst, writer, operand_ty); + const v = try Vectorize.start(f, inst, w, operand_ty); if (!ref_ret) { - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try writer.writeAll(" = "); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try w.writeAll(" = "); } - try writer.print("zig_{s}_", .{operation}); - try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); - try writer.writeByte('('); + try w.print("zig_{s}_", .{operation}); + try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty); + try w.writeByte('('); if (ref_ret) { - try f.writeCValue(writer, local, .FunctionArgument); - try v.elem(f, writer); - try writer.writeAll(", "); - } - try f.writeCValue(writer, lhs, .FunctionArgument); - try v.elem(f, writer); - try writer.writeAll(", "); - try f.writeCValue(writer, rhs, .FunctionArgument); - if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, writer); - try f.object.dg.renderBuiltinInfo(writer, scalar_ty, info); - try writer.writeAll(");\n"); - try v.end(f, inst, writer); + try f.writeCValue(w, local, .FunctionArgument); + try v.elem(f, w); + try w.writeAll(", "); + } + try f.writeCValue(w, lhs, .FunctionArgument); + try v.elem(f, w); + try w.writeAll(", "); + try f.writeCValue(w, rhs, .FunctionArgument); + if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w); + try f.object.dg.renderBuiltinInfo(w, scalar_ty, info); + try w.writeAll(");\n"); + try v.end(f, inst, w); return local; } @@ -6702,38 +6805,39 @@ fn airCmpBuiltinCall( const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete); const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array; - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, writer, operand_ty); + const v = try Vectorize.start(f, inst, w, operand_ty); if (!ref_ret) { - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try writer.writeAll(" = "); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try w.writeAll(" = "); } - try writer.print("zig_{s}_", .{switch (operation) { + try w.print("zig_{s}_", .{switch (operation) { else => @tagName(operation), .operator => compareOperatorAbbrev(operator), }}); - try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); - try writer.writeByte('('); + try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty); + try w.writeByte('('); if (ref_ret) { - try f.writeCValue(writer, local, .FunctionArgument); - try v.elem(f, writer); - try writer.writeAll(", "); - } - try f.writeCValue(writer, lhs, .FunctionArgument); - try v.elem(f, writer); - try writer.writeAll(", "); - try f.writeCValue(writer, rhs, .FunctionArgument); - try v.elem(f, writer); - try f.object.dg.renderBuiltinInfo(writer, scalar_ty, info); - try writer.writeByte(')'); - if (!ref_ret) try writer.print("{s}{}", .{ + try f.writeCValue(w, local, .FunctionArgument); + try v.elem(f, w); + try w.writeAll(", "); + } + try f.writeCValue(w, lhs, .FunctionArgument); + try v.elem(f, w); + try w.writeAll(", "); + try f.writeCValue(w, rhs, .FunctionArgument); + try v.elem(f, w); + try f.object.dg.renderBuiltinInfo(w, scalar_ty, info); + try w.writeByte(')'); + if (!ref_ret) try w.print("{s}{f}", .{ compareOperatorC(operator), - try f.fmtIntLiteral(try pt.intValue(.i32, 0)), + try f.fmtIntLiteralDec(try pt.intValue(.i32, 0)), }); - try writer.writeAll(";\n"); - try v.end(f, inst, writer); + try w.writeByte(';'); + try f.object.newline(); + try v.end(f, inst, w); return local; } @@ -6751,7 +6855,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue const ty = ptr_ty.childType(zcu); const ctype = try f.ctypeFromType(ty, .complete); - const writer = f.object.writer(); + const w = &f.object.code.writer; const new_value_mat = try Materialize.start(f, inst, ty, new_value); try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value }); @@ -6763,76 +6867,78 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue const local = try f.allocLocal(inst, inst_ty); if (inst_ty.isPtrLikeOptional(zcu)) { { - const a = try Assignment.start(f, writer, ctype); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); - try f.writeCValue(writer, expected_value, .Other); - try a.end(f, writer); + const a = try Assignment.start(f, w, ctype); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); + try f.writeCValue(w, expected_value, .Other); + try a.end(f, w); } - try writer.writeAll("if ("); - try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); - try f.renderType(writer, ty); - try writer.writeByte(')'); - if (ptr_ty.isVolatilePtr(zcu)) try writer.writeAll(" volatile"); - try writer.writeAll(" *)"); - try f.writeCValue(writer, ptr, .Other); - try writer.writeAll(", "); - try f.writeCValue(writer, local, .FunctionArgument); - try writer.writeAll(", "); - try new_value_mat.mat(f, writer); - try writer.writeAll(", "); - try writeMemoryOrder(writer, extra.successOrder()); - try writer.writeAll(", "); - try writeMemoryOrder(writer, extra.failureOrder()); - try writer.writeAll(", "); - try f.object.dg.renderTypeForBuiltinFnName(writer, ty); - try writer.writeAll(", "); - try f.renderType(writer, repr_ty); - try writer.writeByte(')'); - try writer.writeAll(") {\n"); - f.object.indent_writer.pushIndent(); + try w.writeAll("if ("); + try w.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); + try f.renderType(w, ty); + try w.writeByte(')'); + if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile"); + try w.writeAll(" *)"); + try f.writeCValue(w, ptr, .Other); + try w.writeAll(", "); + try f.writeCValue(w, local, .FunctionArgument); + try w.writeAll(", "); + try new_value_mat.mat(f, w); + try w.writeAll(", "); + try writeMemoryOrder(w, extra.successOrder()); + try w.writeAll(", "); + try writeMemoryOrder(w, extra.failureOrder()); + try w.writeAll(", "); + try f.object.dg.renderTypeForBuiltinFnName(w, ty); + try w.writeAll(", "); + try f.renderType(w, repr_ty); + try w.writeByte(')'); + try w.writeAll(") {"); + f.object.indent(); + try f.object.newline(); { - const a = try Assignment.start(f, writer, ctype); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); - try writer.writeAll("NULL"); - try a.end(f, writer); + const a = try Assignment.start(f, w, ctype); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); + try w.writeAll("NULL"); + try a.end(f, w); } - f.object.indent_writer.popIndent(); - try writer.writeAll("}\n"); + try f.object.outdent(); + try w.writeByte('}'); + try f.object.newline(); } else { { - const a = try Assignment.start(f, writer, ctype); - try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); - try a.assign(f, writer); - try f.writeCValue(writer, expected_value, .Other); - try a.end(f, writer); + const a = try Assignment.start(f, w, ctype); + try f.writeCValueMember(w, local, .{ .identifier = "payload" }); + try a.assign(f, w); + try f.writeCValue(w, expected_value, .Other); + try a.end(f, w); } { - const a = try Assignment.start(f, writer, .bool); - try f.writeCValueMember(writer, local, .{ .identifier = "is_null" }); - try a.assign(f, writer); - try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); - try f.renderType(writer, ty); - try writer.writeByte(')'); - if (ptr_ty.isVolatilePtr(zcu)) try writer.writeAll(" volatile"); - try writer.writeAll(" *)"); - try f.writeCValue(writer, ptr, .Other); - try writer.writeAll(", "); - try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); - try writer.writeAll(", "); - try new_value_mat.mat(f, writer); - try writer.writeAll(", "); - try writeMemoryOrder(writer, extra.successOrder()); - try writer.writeAll(", "); - try writeMemoryOrder(writer, extra.failureOrder()); - try writer.writeAll(", "); - try f.object.dg.renderTypeForBuiltinFnName(writer, ty); - try writer.writeAll(", "); - try f.renderType(writer, repr_ty); - try writer.writeByte(')'); - try a.end(f, writer); + const a = try Assignment.start(f, w, .bool); + try f.writeCValueMember(w, local, .{ .identifier = "is_null" }); + try a.assign(f, w); + try w.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); + try f.renderType(w, ty); + try w.writeByte(')'); + if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile"); + try w.writeAll(" *)"); + try f.writeCValue(w, ptr, .Other); + try w.writeAll(", "); + try f.writeCValueMember(w, local, .{ .identifier = "payload" }); + try w.writeAll(", "); + try new_value_mat.mat(f, w); + try w.writeAll(", "); + try writeMemoryOrder(w, extra.successOrder()); + try w.writeAll(", "); + try writeMemoryOrder(w, extra.failureOrder()); + try w.writeAll(", "); + try f.object.dg.renderTypeForBuiltinFnName(w, ty); + try w.writeAll(", "); + try f.renderType(w, repr_ty); + try w.writeByte(')'); + try a.end(f, w); } } try new_value_mat.end(f, inst); @@ -6856,7 +6962,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { const ptr = try f.resolveInst(pl_op.operand); const operand = try f.resolveInst(extra.operand); - const writer = f.object.writer(); + const w = &f.object.code.writer; const operand_mat = try Materialize.start(f, inst, ty, operand); try reap(f, inst, &.{ pl_op.operand, extra.operand }); @@ -6866,31 +6972,32 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { const repr_ty = if (is_float) pt.intType(.unsigned, repr_bits) catch unreachable else ty; const local = try f.allocLocal(inst, inst_ty); - try writer.print("zig_atomicrmw_{s}", .{toAtomicRmwSuffix(extra.op())}); - if (is_float) try writer.writeAll("_float") else if (is_128) try writer.writeAll("_int128"); - try writer.writeByte('('); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(", ("); + try w.print("zig_atomicrmw_{s}", .{toAtomicRmwSuffix(extra.op())}); + if (is_float) try w.writeAll("_float") else if (is_128) try w.writeAll("_int128"); + try w.writeByte('('); + try f.writeCValue(w, local, .Other); + try w.writeAll(", ("); const use_atomic = switch (extra.op()) { else => true, // These are missing from stdatomic.h, so no atomic types unless a fallback is used. .Nand, .Min, .Max => is_float or is_128, }; - if (use_atomic) try writer.writeAll("zig_atomic("); - try f.renderType(writer, ty); - if (use_atomic) try writer.writeByte(')'); - if (ptr_ty.isVolatilePtr(zcu)) try writer.writeAll(" volatile"); - try writer.writeAll(" *)"); - try f.writeCValue(writer, ptr, .Other); - try writer.writeAll(", "); - try operand_mat.mat(f, writer); - try writer.writeAll(", "); - try writeMemoryOrder(writer, extra.ordering()); - try writer.writeAll(", "); - try f.object.dg.renderTypeForBuiltinFnName(writer, ty); - try writer.writeAll(", "); - try f.renderType(writer, repr_ty); - try writer.writeAll(");\n"); + if (use_atomic) try w.writeAll("zig_atomic("); + try f.renderType(w, ty); + if (use_atomic) try w.writeByte(')'); + if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile"); + try w.writeAll(" *)"); + try f.writeCValue(w, ptr, .Other); + try w.writeAll(", "); + try operand_mat.mat(f, w); + try w.writeAll(", "); + try writeMemoryOrder(w, extra.ordering()); + try w.writeAll(", "); + try f.object.dg.renderTypeForBuiltinFnName(w, ty); + try w.writeAll(", "); + try f.renderType(w, repr_ty); + try w.writeAll(");"); + try f.object.newline(); try operand_mat.end(f, inst); if (f.liveness.isUnused(inst)) { @@ -6916,24 +7023,25 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { ty; const inst_ty = f.typeOfIndex(inst); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - try writer.writeAll("zig_atomic_load("); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(", (zig_atomic("); - try f.renderType(writer, ty); - try writer.writeByte(')'); - if (ptr_ty.isVolatilePtr(zcu)) try writer.writeAll(" volatile"); - try writer.writeAll(" *)"); - try f.writeCValue(writer, ptr, .Other); - try writer.writeAll(", "); - try writeMemoryOrder(writer, atomic_load.order); - try writer.writeAll(", "); - try f.object.dg.renderTypeForBuiltinFnName(writer, ty); - try writer.writeAll(", "); - try f.renderType(writer, repr_ty); - try writer.writeAll(");\n"); + try w.writeAll("zig_atomic_load("); + try f.writeCValue(w, local, .Other); + try w.writeAll(", (zig_atomic("); + try f.renderType(w, ty); + try w.writeByte(')'); + if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile"); + try w.writeAll(" *)"); + try f.writeCValue(w, ptr, .Other); + try w.writeAll(", "); + try writeMemoryOrder(w, atomic_load.order); + try w.writeAll(", "); + try f.object.dg.renderTypeForBuiltinFnName(w, ty); + try w.writeAll(", "); + try f.renderType(w, repr_ty); + try w.writeAll(");"); + try f.object.newline(); return local; } @@ -6947,7 +7055,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa const ptr = try f.resolveInst(bin_op.lhs); const element = try f.resolveInst(bin_op.rhs); - const writer = f.object.writer(); + const w = &f.object.code.writer; const element_mat = try Materialize.start(f, inst, ty, element); try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); @@ -6956,31 +7064,32 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa else ty; - try writer.writeAll("zig_atomic_store((zig_atomic("); - try f.renderType(writer, ty); - try writer.writeByte(')'); - if (ptr_ty.isVolatilePtr(zcu)) try writer.writeAll(" volatile"); - try writer.writeAll(" *)"); - try f.writeCValue(writer, ptr, .Other); - try writer.writeAll(", "); - try element_mat.mat(f, writer); - try writer.print(", {s}, ", .{order}); - try f.object.dg.renderTypeForBuiltinFnName(writer, ty); - try writer.writeAll(", "); - try f.renderType(writer, repr_ty); - try writer.writeAll(");\n"); + try w.writeAll("zig_atomic_store((zig_atomic("); + try f.renderType(w, ty); + try w.writeByte(')'); + if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile"); + try w.writeAll(" *)"); + try f.writeCValue(w, ptr, .Other); + try w.writeAll(", "); + try element_mat.mat(f, w); + try w.print(", {s}, ", .{order}); + try f.object.dg.renderTypeForBuiltinFnName(w, ty); + try w.writeAll(", "); + try f.renderType(w, repr_ty); + try w.writeAll(");"); + try f.object.newline(); try element_mat.end(f, inst); return .none; } -fn writeSliceOrPtr(f: *Function, writer: anytype, ptr: CValue, ptr_ty: Type) !void { +fn writeSliceOrPtr(f: *Function, w: *Writer, ptr: CValue, ptr_ty: Type) !void { const pt = f.object.dg.pt; const zcu = pt.zcu; if (ptr_ty.isSlice(zcu)) { - try f.writeCValueMember(writer, ptr, .{ .identifier = "ptr" }); + try f.writeCValueMember(w, ptr, .{ .identifier = "ptr" }); } else { - try f.writeCValue(writer, ptr, .FunctionArgument); + try f.writeCValue(w, ptr, .FunctionArgument); } } @@ -6994,7 +7103,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { const elem_ty = f.typeOf(bin_op.rhs); const elem_abi_size = elem_ty.abiSize(zcu); const val_is_undef = if (try f.air.value(bin_op.rhs, pt)) |val| val.isUndefDeep(zcu) else false; - const writer = f.object.writer(); + const w = &f.object.code.writer; if (val_is_undef) { if (!safety) { @@ -7002,24 +7111,25 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { return .none; } - try writer.writeAll("memset("); + try w.writeAll("memset("); switch (dest_ty.ptrSize(zcu)) { .slice => { - try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" }); - try writer.writeAll(", 0xaa, "); - try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" }); + try f.writeCValueMember(w, dest_slice, .{ .identifier = "ptr" }); + try w.writeAll(", 0xaa, "); + try f.writeCValueMember(w, dest_slice, .{ .identifier = "len" }); if (elem_abi_size > 1) { - try writer.print(" * {d});\n", .{elem_abi_size}); - } else { - try writer.writeAll(");\n"); + try w.print(" * {d}", .{elem_abi_size}); } + try w.writeAll(");"); + try f.object.newline(); }, .one => { const array_ty = dest_ty.childType(zcu); const len = array_ty.arrayLen(zcu) * elem_abi_size; - try f.writeCValue(writer, dest_slice, .FunctionArgument); - try writer.print(", 0xaa, {d});\n", .{len}); + try f.writeCValue(w, dest_slice, .FunctionArgument); + try w.print(", 0xaa, {d});", .{len}); + try f.object.newline(); }, .many, .c => unreachable, } @@ -7040,38 +7150,38 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { const index = try f.allocLocal(inst, .usize); - try writer.writeAll("for ("); - try f.writeCValue(writer, index, .Other); - try writer.writeAll(" = "); - try f.object.dg.renderValue(writer, .zero_usize, .Other); - try writer.writeAll("; "); - try f.writeCValue(writer, index, .Other); - try writer.writeAll(" != "); + try w.writeAll("for ("); + try f.writeCValue(w, index, .Other); + try w.writeAll(" = "); + try f.object.dg.renderValue(w, .zero_usize, .Other); + try w.writeAll("; "); + try f.writeCValue(w, index, .Other); + try w.writeAll(" != "); switch (dest_ty.ptrSize(zcu)) { .slice => { - try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" }); + try f.writeCValueMember(w, dest_slice, .{ .identifier = "len" }); }, .one => { const array_ty = dest_ty.childType(zcu); - try writer.print("{d}", .{array_ty.arrayLen(zcu)}); + try w.print("{d}", .{array_ty.arrayLen(zcu)}); }, .many, .c => unreachable, } - try writer.writeAll("; ++"); - try f.writeCValue(writer, index, .Other); - try writer.writeAll(") "); - - const a = try Assignment.start(f, writer, try f.ctypeFromType(elem_ty, .complete)); - try writer.writeAll("(("); - try f.renderType(writer, elem_ptr_ty); - try writer.writeByte(')'); - try writeSliceOrPtr(f, writer, dest_slice, dest_ty); - try writer.writeAll(")["); - try f.writeCValue(writer, index, .Other); - try writer.writeByte(']'); - try a.assign(f, writer); - try f.writeCValue(writer, value, .Other); - try a.end(f, writer); + try w.writeAll("; ++"); + try f.writeCValue(w, index, .Other); + try w.writeAll(") "); + + const a = try Assignment.start(f, w, try f.ctypeFromType(elem_ty, .complete)); + try w.writeAll("(("); + try f.renderType(w, elem_ptr_ty); + try w.writeByte(')'); + try writeSliceOrPtr(f, w, dest_slice, dest_ty); + try w.writeAll(")["); + try f.writeCValue(w, index, .Other); + try w.writeByte(']'); + try a.assign(f, w); + try f.writeCValue(w, value, .Other); + try a.end(f, w); try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); try freeLocal(f, inst, index.new_local, null); @@ -7081,24 +7191,26 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { const bitcasted = try bitcast(f, .u8, value, elem_ty); - try writer.writeAll("memset("); + try w.writeAll("memset("); switch (dest_ty.ptrSize(zcu)) { .slice => { - try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" }); - try writer.writeAll(", "); - try f.writeCValue(writer, bitcasted, .FunctionArgument); - try writer.writeAll(", "); - try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" }); - try writer.writeAll(");\n"); + try f.writeCValueMember(w, dest_slice, .{ .identifier = "ptr" }); + try w.writeAll(", "); + try f.writeCValue(w, bitcasted, .FunctionArgument); + try w.writeAll(", "); + try f.writeCValueMember(w, dest_slice, .{ .identifier = "len" }); + try w.writeAll(");"); + try f.object.newline(); }, .one => { const array_ty = dest_ty.childType(zcu); const len = array_ty.arrayLen(zcu) * elem_abi_size; - try f.writeCValue(writer, dest_slice, .FunctionArgument); - try writer.writeAll(", "); - try f.writeCValue(writer, bitcasted, .FunctionArgument); - try writer.print(", {d});\n", .{len}); + try f.writeCValue(w, dest_slice, .FunctionArgument); + try w.writeAll(", "); + try f.writeCValue(w, bitcasted, .FunctionArgument); + try w.print(", {d});", .{len}); + try f.object.newline(); }, .many, .c => unreachable, } @@ -7115,36 +7227,38 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index, function_paren: []const u8) !CV const src_ptr = try f.resolveInst(bin_op.rhs); const dest_ty = f.typeOf(bin_op.lhs); const src_ty = f.typeOf(bin_op.rhs); - const writer = f.object.writer(); + const w = &f.object.code.writer; if (dest_ty.ptrSize(zcu) != .one) { - try writer.writeAll("if ("); - try writeArrayLen(f, writer, dest_ptr, dest_ty); - try writer.writeAll(" != 0) "); - } - try writer.writeAll(function_paren); - try writeSliceOrPtr(f, writer, dest_ptr, dest_ty); - try writer.writeAll(", "); - try writeSliceOrPtr(f, writer, src_ptr, src_ty); - try writer.writeAll(", "); - try writeArrayLen(f, writer, dest_ptr, dest_ty); - try writer.writeAll(" * sizeof("); - try f.renderType(writer, dest_ty.elemType2(zcu)); - try writer.writeAll("));\n"); + try w.writeAll("if ("); + try writeArrayLen(f, dest_ptr, dest_ty); + try w.writeAll(" != 0) "); + } + try w.writeAll(function_paren); + try writeSliceOrPtr(f, w, dest_ptr, dest_ty); + try w.writeAll(", "); + try writeSliceOrPtr(f, w, src_ptr, src_ty); + try w.writeAll(", "); + try writeArrayLen(f, dest_ptr, dest_ty); + try w.writeAll(" * sizeof("); + try f.renderType(w, dest_ty.elemType2(zcu)); + try w.writeAll("));"); + try f.object.newline(); try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); return .none; } -fn writeArrayLen(f: *Function, writer: ArrayListWriter, dest_ptr: CValue, dest_ty: Type) !void { +fn writeArrayLen(f: *Function, dest_ptr: CValue, dest_ty: Type) !void { const pt = f.object.dg.pt; const zcu = pt.zcu; + const w = &f.object.code.writer; switch (dest_ty.ptrSize(zcu)) { - .one => try writer.print("{}", .{ - try f.fmtIntLiteral(try pt.intValue(.usize, dest_ty.childType(zcu).arrayLen(zcu))), + .one => try w.print("{f}", .{ + try f.fmtIntLiteralDec(try pt.intValue(.usize, dest_ty.childType(zcu).arrayLen(zcu))), }), .many, .c => unreachable, - .slice => try f.writeCValueMember(writer, dest_ptr, .{ .identifier = "len" }), + .slice => try f.writeCValueMember(w, dest_ptr, .{ .identifier = "len" }), } } @@ -7161,12 +7275,12 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { if (layout.tag_size == 0) return .none; const tag_ty = union_ty.unionTagTypeSafety(zcu).?; - const writer = f.object.writer(); - const a = try Assignment.start(f, writer, try f.ctypeFromType(tag_ty, .complete)); - try f.writeCValueDerefMember(writer, union_ptr, .{ .identifier = "tag" }); - try a.assign(f, writer); - try f.writeCValue(writer, new_tag, .Other); - try a.end(f, writer); + const w = &f.object.code.writer; + const a = try Assignment.start(f, w, try f.ctypeFromType(tag_ty, .complete)); + try f.writeCValueDerefMember(w, union_ptr, .{ .identifier = "tag" }); + try a.assign(f, w); + try f.writeCValue(w, new_tag, .Other); + try a.end(f, w); return .none; } @@ -7183,13 +7297,13 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { if (layout.tag_size == 0) return .none; const inst_ty = f.typeOfIndex(inst); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try a.assign(f, writer); - try f.writeCValueMember(writer, operand, .{ .identifier = "tag" }); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete)); + try f.writeCValue(w, local, .Other); + try a.assign(f, w); + try f.writeCValueMember(w, operand, .{ .identifier = "tag" }); + try a.end(f, w); return local; } @@ -7201,14 +7315,15 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { const operand = try f.resolveInst(un_op); try reap(f, inst, &.{un_op}); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - try f.writeCValue(writer, local, .Other); - try writer.print(" = {s}(", .{ + try f.writeCValue(w, local, .Other); + try w.print(" = {s}(", .{ try f.getLazyFnName(.{ .tag_name = enum_ty.toIntern() }), }); - try f.writeCValue(writer, operand, .Other); - try writer.writeAll(");\n"); + try f.writeCValue(w, operand, .Other); + try w.writeAll(");"); + try f.object.newline(); return local; } @@ -7216,16 +7331,17 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue { const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const writer = f.object.writer(); + const w = &f.object.code.writer; const inst_ty = f.typeOfIndex(inst); const operand = try f.resolveInst(un_op); try reap(f, inst, &.{un_op}); const local = try f.allocLocal(inst, inst_ty); - try f.writeCValue(writer, local, .Other); + try f.writeCValue(w, local, .Other); - try writer.writeAll(" = zig_errorName["); - try f.writeCValue(writer, operand, .Other); - try writer.writeAll(" - 1];\n"); + try w.writeAll(" = zig_errorName["); + try f.writeCValue(w, operand, .Other); + try w.writeAll(" - 1];"); + try f.object.newline(); return local; } @@ -7240,16 +7356,16 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue { const inst_ty = f.typeOfIndex(inst); const inst_scalar_ty = inst_ty.scalarType(zcu); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, writer, inst_ty); - const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_scalar_ty, .complete)); - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try a.assign(f, writer); - try f.writeCValue(writer, operand, .Other); - try a.end(f, writer); - try v.end(f, inst, writer); + const v = try Vectorize.start(f, inst, w, inst_ty); + const a = try Assignment.start(f, w, try f.ctypeFromType(inst_scalar_ty, .complete)); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try a.assign(f, w); + try f.writeCValue(w, operand, .Other); + try a.end(f, w); + try v.end(f, inst, w); return local; } @@ -7265,22 +7381,23 @@ fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue { const inst_ty = f.typeOfIndex(inst); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, writer, inst_ty); - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try writer.writeAll(" = "); - try f.writeCValue(writer, pred, .Other); - try v.elem(f, writer); - try writer.writeAll(" ? "); - try f.writeCValue(writer, lhs, .Other); - try v.elem(f, writer); - try writer.writeAll(" : "); - try f.writeCValue(writer, rhs, .Other); - try v.elem(f, writer); - try writer.writeAll(";\n"); - try v.end(f, inst, writer); + const v = try Vectorize.start(f, inst, w, inst_ty); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try w.writeAll(" = "); + try f.writeCValue(w, pred, .Other); + try v.elem(f, w); + try w.writeAll(" ? "); + try f.writeCValue(w, lhs, .Other); + try v.elem(f, w); + try w.writeAll(" : "); + try f.writeCValue(w, rhs, .Other); + try v.elem(f, w); + try w.writeByte(';'); + try f.object.newline(); + try v.end(f, inst, w); return local; } @@ -7294,24 +7411,24 @@ fn airShuffleOne(f: *Function, inst: Air.Inst.Index) !CValue { const operand = try f.resolveInst(unwrapped.operand); const inst_ty = unwrapped.result_ty; - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); try reap(f, inst, &.{unwrapped.operand}); // local cannot alias operand for (mask, 0..) |mask_elem, out_idx| { - try f.writeCValue(writer, local, .Other); - try writer.writeByte('['); - try f.object.dg.renderValue(writer, try pt.intValue(.usize, out_idx), .Other); - try writer.writeAll("] = "); + try f.writeCValue(w, local, .Other); + try w.writeByte('['); + try f.object.dg.renderValue(w, try pt.intValue(.usize, out_idx), .Other); + try w.writeAll("] = "); switch (mask_elem.unwrap()) { .elem => |src_idx| { - try f.writeCValue(writer, operand, .Other); - try writer.writeByte('['); - try f.object.dg.renderValue(writer, try pt.intValue(.usize, src_idx), .Other); - try writer.writeByte(']'); + try f.writeCValue(w, operand, .Other); + try w.writeByte('['); + try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other); + try w.writeByte(']'); }, - .value => |val| try f.object.dg.renderValue(writer, .fromInterned(val), .Other), + .value => |val| try f.object.dg.renderValue(w, .fromInterned(val), .Other), } - try writer.writeAll(";\n"); + try w.writeAll(";\n"); } return local; @@ -7328,30 +7445,31 @@ fn airShuffleTwo(f: *Function, inst: Air.Inst.Index) !CValue { const inst_ty = unwrapped.result_ty; const elem_ty = inst_ty.childType(zcu); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); try reap(f, inst, &.{ unwrapped.operand_a, unwrapped.operand_b }); // local cannot alias operands for (mask, 0..) |mask_elem, out_idx| { - try f.writeCValue(writer, local, .Other); - try writer.writeByte('['); - try f.object.dg.renderValue(writer, try pt.intValue(.usize, out_idx), .Other); - try writer.writeAll("] = "); + try f.writeCValue(w, local, .Other); + try w.writeByte('['); + try f.object.dg.renderValue(w, try pt.intValue(.usize, out_idx), .Other); + try w.writeAll("] = "); switch (mask_elem.unwrap()) { .a_elem => |src_idx| { - try f.writeCValue(writer, operand_a, .Other); - try writer.writeByte('['); - try f.object.dg.renderValue(writer, try pt.intValue(.usize, src_idx), .Other); - try writer.writeByte(']'); + try f.writeCValue(w, operand_a, .Other); + try w.writeByte('['); + try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other); + try w.writeByte(']'); }, .b_elem => |src_idx| { - try f.writeCValue(writer, operand_b, .Other); - try writer.writeByte('['); - try f.object.dg.renderValue(writer, try pt.intValue(.usize, src_idx), .Other); - try writer.writeByte(']'); + try f.writeCValue(w, operand_b, .Other); + try w.writeByte('['); + try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other); + try w.writeByte(']'); }, - .undef => try f.object.dg.renderUndefValue(writer, elem_ty, .Other), + .undef => try f.object.dg.renderUndefValue(w, elem_ty, .Other), } - try writer.writeAll(";\n"); + try w.writeByte(';'); + try f.object.newline(); } return local; @@ -7366,7 +7484,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { const operand = try f.resolveInst(reduce.operand); try reap(f, inst, &.{reduce.operand}); const operand_ty = f.typeOf(reduce.operand); - const writer = f.object.writer(); + const w = &f.object.code.writer; const use_operator = scalar_ty.bitSize(zcu) <= 64; const op: union(enum) { @@ -7413,10 +7531,10 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { // } const accum = try f.allocLocal(inst, scalar_ty); - try f.writeCValue(writer, accum, .Other); - try writer.writeAll(" = "); + try f.writeCValue(w, accum, .Other); + try w.writeAll(" = "); - try f.object.dg.renderValue(writer, switch (reduce.operation) { + try f.object.dg.renderValue(w, switch (reduce.operation) { .Or, .Xor => switch (scalar_ty.zigTypeTag(zcu)) { .bool => Value.false, .int => try pt.intValue(scalar_ty, 0), @@ -7453,42 +7571,44 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { else => unreachable, }, }, .Other); - try writer.writeAll(";\n"); + try w.writeByte(';'); + try f.object.newline(); - const v = try Vectorize.start(f, inst, writer, operand_ty); - try f.writeCValue(writer, accum, .Other); + const v = try Vectorize.start(f, inst, w, operand_ty); + try f.writeCValue(w, accum, .Other); switch (op) { .builtin => |func| { - try writer.print(" = zig_{s}_", .{func.operation}); - try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); - try writer.writeByte('('); - try f.writeCValue(writer, accum, .FunctionArgument); - try writer.writeAll(", "); - try f.writeCValue(writer, operand, .Other); - try v.elem(f, writer); - try f.object.dg.renderBuiltinInfo(writer, scalar_ty, func.info); - try writer.writeByte(')'); + try w.print(" = zig_{s}_", .{func.operation}); + try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty); + try w.writeByte('('); + try f.writeCValue(w, accum, .FunctionArgument); + try w.writeAll(", "); + try f.writeCValue(w, operand, .Other); + try v.elem(f, w); + try f.object.dg.renderBuiltinInfo(w, scalar_ty, func.info); + try w.writeByte(')'); }, .infix => |ass| { - try writer.writeAll(ass); - try f.writeCValue(writer, operand, .Other); - try v.elem(f, writer); + try w.writeAll(ass); + try f.writeCValue(w, operand, .Other); + try v.elem(f, w); }, .ternary => |cmp| { - try writer.writeAll(" = "); - try f.writeCValue(writer, accum, .Other); - try writer.writeAll(cmp); - try f.writeCValue(writer, operand, .Other); - try v.elem(f, writer); - try writer.writeAll(" ? "); - try f.writeCValue(writer, accum, .Other); - try writer.writeAll(" : "); - try f.writeCValue(writer, operand, .Other); - try v.elem(f, writer); + try w.writeAll(" = "); + try f.writeCValue(w, accum, .Other); + try w.writeAll(cmp); + try f.writeCValue(w, operand, .Other); + try v.elem(f, w); + try w.writeAll(" ? "); + try f.writeCValue(w, accum, .Other); + try w.writeAll(" : "); + try f.writeCValue(w, operand, .Other); + try v.elem(f, w); }, } - try writer.writeAll(";\n"); - try v.end(f, inst, writer); + try w.writeByte(';'); + try f.object.newline(); + try v.end(f, inst, w); return accum; } @@ -7514,7 +7634,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { } } - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); switch (ip.indexToKey(inst_ty.toIntern())) { inline .array_type, .vector_type => |info, tag| { @@ -7522,20 +7642,20 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { .ctype = try f.ctypeFromType(.fromInterned(info.child), .complete), }; for (resolved_elements, 0..) |element, i| { - try a.restart(f, writer); - try f.writeCValue(writer, local, .Other); - try writer.print("[{d}]", .{i}); - try a.assign(f, writer); - try f.writeCValue(writer, element, .Other); - try a.end(f, writer); + try a.restart(f, w); + try f.writeCValue(w, local, .Other); + try w.print("[{d}]", .{i}); + try a.assign(f, w); + try f.writeCValue(w, element, .Other); + try a.end(f, w); } if (tag == .array_type and info.sentinel != .none) { - try a.restart(f, writer); - try f.writeCValue(writer, local, .Other); - try writer.print("[{d}]", .{info.len}); - try a.assign(f, writer); - try f.object.dg.renderValue(writer, Value.fromInterned(info.sentinel), .Other); - try a.end(f, writer); + try a.restart(f, w); + try f.writeCValue(w, local, .Other); + try w.print("[{d}]", .{info.len}); + try a.assign(f, w); + try f.object.dg.renderValue(w, Value.fromInterned(info.sentinel), .Other); + try a.end(f, w); } }, .struct_type => { @@ -7547,19 +7667,19 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; - const a = try Assignment.start(f, writer, try f.ctypeFromType(field_ty, .complete)); - try f.writeCValueMember(writer, local, if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| + const a = try Assignment.start(f, w, try f.ctypeFromType(field_ty, .complete)); + try f.writeCValueMember(w, local, if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| .{ .identifier = field_name.toSlice(ip) } else .{ .field = field_index }); - try a.assign(f, writer); - try f.writeCValue(writer, resolved_elements[field_index], .Other); - try a.end(f, writer); + try a.assign(f, w); + try f.writeCValue(w, resolved_elements[field_index], .Other); + try a.end(f, w); } }, .@"packed" => { - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = "); + try f.writeCValue(w, local, .Other); + try w.writeAll(" = "); const backing_int_ty: Type = .fromInterned(loaded_struct.backingIntTypeUnordered(ip)); const int_info = backing_int_ty.intInfo(zcu); @@ -7575,9 +7695,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; if (!empty) { - try writer.writeAll("zig_or_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); - try writer.writeByte('('); + try w.writeAll("zig_or_"); + try f.object.dg.renderTypeForBuiltinFnName(w, inst_ty); + try w.writeByte('('); } empty = false; } @@ -7587,57 +7707,58 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { const field_ty = inst_ty.fieldType(field_index, zcu); if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; - if (!empty) try writer.writeAll(", "); + if (!empty) try w.writeAll(", "); // TODO: Skip this entire shift if val is 0? - try writer.writeAll("zig_shlw_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); - try writer.writeByte('('); + try w.writeAll("zig_shlw_"); + try f.object.dg.renderTypeForBuiltinFnName(w, inst_ty); + try w.writeByte('('); if (field_ty.isAbiInt(zcu)) { - try writer.writeAll("zig_and_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); - try writer.writeByte('('); + try w.writeAll("zig_and_"); + try f.object.dg.renderTypeForBuiltinFnName(w, inst_ty); + try w.writeByte('('); } if (inst_ty.isAbiInt(zcu) and (field_ty.isAbiInt(zcu) or field_ty.isPtrAtRuntime(zcu))) { - try f.renderIntCast(writer, inst_ty, element, .{}, field_ty, .FunctionArgument); + try f.renderIntCast(w, inst_ty, element, .{}, field_ty, .FunctionArgument); } else { - try writer.writeByte('('); - try f.renderType(writer, inst_ty); - try writer.writeByte(')'); + try w.writeByte('('); + try f.renderType(w, inst_ty); + try w.writeByte(')'); if (field_ty.isPtrAtRuntime(zcu)) { - try writer.writeByte('('); - try f.renderType(writer, switch (int_info.signedness) { + try w.writeByte('('); + try f.renderType(w, switch (int_info.signedness) { .unsigned => .usize, .signed => .isize, }); - try writer.writeByte(')'); + try w.writeByte(')'); } - try f.writeCValue(writer, element, .Other); + try f.writeCValue(w, element, .Other); } if (field_ty.isAbiInt(zcu)) { - try writer.writeAll(", "); + try w.writeAll(", "); const field_int_info = field_ty.intInfo(zcu); const field_mask = if (int_info.signedness == .signed and int_info.bits == field_int_info.bits) try pt.intValue(backing_int_ty, -1) else try (try pt.intType(.unsigned, field_int_info.bits)).maxIntScalar(pt, backing_int_ty); - try f.object.dg.renderValue(writer, field_mask, .FunctionArgument); - try writer.writeByte(')'); + try f.object.dg.renderValue(w, field_mask, .FunctionArgument); + try w.writeByte(')'); } - try writer.print(", {}", .{ - try f.fmtIntLiteral(try pt.intValue(bit_offset_ty, bit_offset)), + try w.print(", {f}", .{ + try f.fmtIntLiteralDec(try pt.intValue(bit_offset_ty, bit_offset)), }); - try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits); - try writer.writeByte(')'); - if (!empty) try writer.writeByte(')'); + try f.object.dg.renderBuiltinInfo(w, inst_ty, .bits); + try w.writeByte(')'); + if (!empty) try w.writeByte(')'); bit_offset += field_ty.bitSize(zcu); empty = false; } - try writer.writeAll(";\n"); + try w.writeByte(';'); + try f.object.newline(); }, } }, @@ -7646,11 +7767,11 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { const field_ty: Type = .fromInterned(tuple_info.types.get(ip)[field_index]); if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; - const a = try Assignment.start(f, writer, try f.ctypeFromType(field_ty, .complete)); - try f.writeCValueMember(writer, local, .{ .field = field_index }); - try a.assign(f, writer); - try f.writeCValue(writer, resolved_elements[field_index], .Other); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(field_ty, .complete)); + try f.writeCValueMember(w, local, .{ .field = field_index }); + try a.assign(f, w); + try f.writeCValue(w, resolved_elements[field_index], .Other); + try a.end(f, w); }, else => unreachable, } @@ -7672,7 +7793,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { const payload = try f.resolveInst(extra.init); try reap(f, inst, &.{extra.init}); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, union_ty); if (loaded_union.flagsUnordered(ip).layout == .@"packed") return f.moveCValue(inst, union_ty, payload); @@ -7682,20 +7803,20 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { const field_index = tag_ty.enumFieldIndex(field_name, zcu).?; const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index); - const a = try Assignment.start(f, writer, try f.ctypeFromType(tag_ty, .complete)); - try f.writeCValueMember(writer, local, .{ .identifier = "tag" }); - try a.assign(f, writer); - try writer.print("{}", .{try f.fmtIntLiteral(try tag_val.intFromEnum(tag_ty, pt))}); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(tag_ty, .complete)); + try f.writeCValueMember(w, local, .{ .identifier = "tag" }); + try a.assign(f, w); + try w.print("{f}", .{try f.fmtIntLiteralDec(try tag_val.intFromEnum(tag_ty, pt))}); + try a.end(f, w); } break :field .{ .payload_identifier = field_name.toSlice(ip) }; } else .{ .identifier = field_name.toSlice(ip) }; - const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete)); - try f.writeCValueMember(writer, local, field); - try a.assign(f, writer); - try f.writeCValue(writer, payload, .Other); - try a.end(f, writer); + const a = try Assignment.start(f, w, try f.ctypeFromType(payload_ty, .complete)); + try f.writeCValueMember(w, local, field); + try a.assign(f, w); + try f.writeCValue(w, payload, .Other); + try a.end(f, w); return local; } @@ -7708,15 +7829,16 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue { const ptr = try f.resolveInst(prefetch.ptr); try reap(f, inst, &.{prefetch.ptr}); - const writer = f.object.writer(); + const w = &f.object.code.writer; switch (prefetch.cache) { .data => { - try writer.writeAll("zig_prefetch("); + try w.writeAll("zig_prefetch("); if (ptr_ty.isSlice(zcu)) - try f.writeCValueMember(writer, ptr, .{ .identifier = "ptr" }) + try f.writeCValueMember(w, ptr, .{ .identifier = "ptr" }) else - try f.writeCValue(writer, ptr, .FunctionArgument); - try writer.print(", {d}, {d});\n", .{ @intFromEnum(prefetch.rw), prefetch.locality }); + try f.writeCValue(w, ptr, .FunctionArgument); + try w.print(", {d}, {d});", .{ @intFromEnum(prefetch.rw), prefetch.locality }); + try f.object.newline(); }, // The available prefetch intrinsics do not accept a cache argument; only // address, rw, and locality. @@ -7729,13 +7851,14 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue { fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue { const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; - const writer = f.object.writer(); + const w = &f.object.code.writer; const inst_ty = f.typeOfIndex(inst); const local = try f.allocLocal(inst, inst_ty); - try f.writeCValue(writer, local, .Other); + try f.writeCValue(w, local, .Other); - try writer.writeAll(" = "); - try writer.print("zig_wasm_memory_size({d});\n", .{pl_op.payload}); + try w.writeAll(" = "); + try w.print("zig_wasm_memory_size({d});", .{pl_op.payload}); + try f.object.newline(); return local; } @@ -7743,17 +7866,18 @@ fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue { fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue { const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; - const writer = f.object.writer(); + const w = &f.object.code.writer; const inst_ty = f.typeOfIndex(inst); const operand = try f.resolveInst(pl_op.operand); try reap(f, inst, &.{pl_op.operand}); const local = try f.allocLocal(inst, inst_ty); - try f.writeCValue(writer, local, .Other); + try f.writeCValue(w, local, .Other); - try writer.writeAll(" = "); - try writer.print("zig_wasm_memory_grow({d}, ", .{pl_op.payload}); - try f.writeCValue(writer, operand, .FunctionArgument); - try writer.writeAll(");\n"); + try w.writeAll(" = "); + try w.print("zig_wasm_memory_grow({d}, ", .{pl_op.payload}); + try f.writeCValue(w, operand, .FunctionArgument); + try w.writeAll(");"); + try f.object.newline(); return local; } @@ -7771,36 +7895,38 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { const inst_ty = f.typeOfIndex(inst); const inst_scalar_ty = inst_ty.scalarType(zcu); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, writer, inst_ty); - try f.writeCValue(writer, local, .Other); - try v.elem(f, writer); - try writer.writeAll(" = zig_fma_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, inst_scalar_ty); - try writer.writeByte('('); - try f.writeCValue(writer, mulend1, .FunctionArgument); - try v.elem(f, writer); - try writer.writeAll(", "); - try f.writeCValue(writer, mulend2, .FunctionArgument); - try v.elem(f, writer); - try writer.writeAll(", "); - try f.writeCValue(writer, addend, .FunctionArgument); - try v.elem(f, writer); - try writer.writeAll(");\n"); - try v.end(f, inst, writer); + const v = try Vectorize.start(f, inst, w, inst_ty); + try f.writeCValue(w, local, .Other); + try v.elem(f, w); + try w.writeAll(" = zig_fma_"); + try f.object.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty); + try w.writeByte('('); + try f.writeCValue(w, mulend1, .FunctionArgument); + try v.elem(f, w); + try w.writeAll(", "); + try f.writeCValue(w, mulend2, .FunctionArgument); + try v.elem(f, w); + try w.writeAll(", "); + try f.writeCValue(w, addend, .FunctionArgument); + try v.elem(f, w); + try w.writeAll(");"); + try f.object.newline(); + try v.end(f, inst, w); return local; } fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue { const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav; - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty)); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = "); - try f.object.dg.renderNav(writer, ty_nav.nav, .Other); - try writer.writeAll(";\n"); + try f.writeCValue(w, local, .Other); + try w.writeAll(" = "); + try f.object.dg.renderNav(w, ty_nav.nav, .Other); + try w.writeByte(';'); + try f.object.newline(); return local; } @@ -7812,15 +7938,16 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue { const function_info = (try f.ctypeFromType(function_ty, .complete)).info(&f.object.dg.ctype_pool).function; assert(function_info.varargs); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - try writer.writeAll("va_start(*(va_list *)&"); - try f.writeCValue(writer, local, .Other); + try w.writeAll("va_start(*(va_list *)&"); + try f.writeCValue(w, local, .Other); if (function_info.param_ctypes.len > 0) { - try writer.writeAll(", "); - try f.writeCValue(writer, .{ .arg = function_info.param_ctypes.len - 1 }, .FunctionArgument); + try w.writeAll(", "); + try f.writeCValue(w, .{ .arg = function_info.param_ctypes.len - 1 }, .FunctionArgument); } - try writer.writeAll(");\n"); + try w.writeAll(");"); + try f.object.newline(); return local; } @@ -7831,14 +7958,15 @@ fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue { const va_list = try f.resolveInst(ty_op.operand); try reap(f, inst, &.{ty_op.operand}); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = va_arg(*(va_list *)"); - try f.writeCValue(writer, va_list, .Other); - try writer.writeAll(", "); - try f.renderType(writer, ty_op.ty.toType()); - try writer.writeAll(");\n"); + try f.writeCValue(w, local, .Other); + try w.writeAll(" = va_arg(*(va_list *)"); + try f.writeCValue(w, va_list, .Other); + try w.writeAll(", "); + try f.renderType(w, ty_op.ty.toType()); + try w.writeAll(");"); + try f.object.newline(); return local; } @@ -7848,10 +7976,11 @@ fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue { const va_list = try f.resolveInst(un_op); try reap(f, inst, &.{un_op}); - const writer = f.object.writer(); - try writer.writeAll("va_end(*(va_list *)"); - try f.writeCValue(writer, va_list, .Other); - try writer.writeAll(");\n"); + const w = &f.object.code.writer; + try w.writeAll("va_end(*(va_list *)"); + try f.writeCValue(w, va_list, .Other); + try w.writeAll(");"); + try f.object.newline(); return .none; } @@ -7862,13 +7991,14 @@ fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue { const va_list = try f.resolveInst(ty_op.operand); try reap(f, inst, &.{ty_op.operand}); - const writer = f.object.writer(); + const w = &f.object.code.writer; const local = try f.allocLocal(inst, inst_ty); - try writer.writeAll("va_copy(*(va_list *)&"); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(", *(va_list *)"); - try f.writeCValue(writer, va_list, .Other); - try writer.writeAll(");\n"); + try w.writeAll("va_copy(*(va_list *)&"); + try f.writeCValue(w, local, .Other); + try w.writeAll(", *(va_list *)"); + try f.writeCValue(w, va_list, .Other); + try w.writeAll(");"); + try f.object.newline(); return local; } @@ -7883,7 +8013,7 @@ fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 { }; } -fn writeMemoryOrder(w: anytype, order: std.builtin.AtomicOrder) !void { +fn writeMemoryOrder(w: *Writer, order: std.builtin.AtomicOrder) !void { return w.writeAll(toMemoryOrder(order)); } @@ -7970,93 +8100,6 @@ fn toAtomicRmwSuffix(order: std.builtin.AtomicRmwOp) []const u8 { }; } -const ArrayListWriter = ErrorOnlyGenericWriter(std.ArrayList(u8).Writer.Error); - -fn arrayListWriter(list: *std.ArrayList(u8)) ArrayListWriter { - return .{ .context = .{ - .context = list, - .writeFn = struct { - fn write(context: *const anyopaque, bytes: []const u8) anyerror!usize { - const l: *std.ArrayList(u8) = @alignCast(@constCast(@ptrCast(context))); - return l.writer().write(bytes); - } - }.write, - } }; -} - -fn IndentWriter(comptime UnderlyingWriter: type) type { - return struct { - const Self = @This(); - pub const Error = UnderlyingWriter.Error; - pub const Writer = ErrorOnlyGenericWriter(Error); - - pub const indent_delta = 1; - - underlying_writer: UnderlyingWriter, - indent_count: usize = 0, - current_line_empty: bool = true, - - pub fn writer(self: *Self) Writer { - return .{ .context = .{ - .context = self, - .writeFn = writeAny, - } }; - } - - pub fn write(self: *Self, bytes: []const u8) Error!usize { - if (bytes.len == 0) return 0; - - const current_indent = self.indent_count * Self.indent_delta; - if (self.current_line_empty and current_indent > 0) { - try self.underlying_writer.writeByteNTimes(' ', current_indent); - } - self.current_line_empty = false; - - return self.writeNoIndent(bytes); - } - - fn writeAny(context: *const anyopaque, bytes: []const u8) anyerror!usize { - const self: *Self = @alignCast(@constCast(@ptrCast(context))); - return self.write(bytes); - } - - pub fn insertNewline(self: *Self) Error!void { - _ = try self.writeNoIndent("\n"); - } - - pub fn pushIndent(self: *Self) void { - self.indent_count += 1; - } - - pub fn popIndent(self: *Self) void { - assert(self.indent_count != 0); - self.indent_count -= 1; - } - - fn writeNoIndent(self: *Self, bytes: []const u8) Error!usize { - if (bytes.len == 0) return 0; - - try self.underlying_writer.writeAll(bytes); - if (bytes[bytes.len - 1] == '\n') { - self.current_line_empty = true; - } - return bytes.len; - } - }; -} - -/// A wrapper around `std.io.AnyWriter` that maintains a generic error set while -/// erasing the rest of the implementation. This is intended to avoid duplicate -/// generic instantiations for writer types which share the same error set, while -/// maintaining ease of error handling. -fn ErrorOnlyGenericWriter(comptime Error: type) type { - return std.io.GenericWriter(std.io.AnyWriter, Error, struct { - fn write(context: std.io.AnyWriter, bytes: []const u8) Error!usize { - return @errorCast(context.write(bytes)); - } - }.write); -} - fn toCIntBits(zig_bits: u32) ?u32 { for (&[_]u8{ 8, 16, 32, 64, 128 }) |c_bits| { if (zig_bits <= c_bits) { @@ -8111,7 +8154,12 @@ fn compareOperatorC(operator: std.math.CompareOperator) []const u8 { }; } -fn StringLiteral(comptime WriterType: type) type { +const StringLiteral = struct { + len: usize, + cur_len: usize, + w: *Writer, + first: bool, + // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal, // regardless of the length of the string literal initializing it. Array initializer syntax is // used instead. @@ -8123,99 +8171,116 @@ fn StringLiteral(comptime WriterType: type) type { const max_char_len = 4; const max_literal_len = @min(16380 - max_char_len, 4095); - return struct { - len: u64, - cur_len: u64 = 0, - counting_writer: std.io.CountingWriter(WriterType), - - pub const Error = WriterType.Error; - - const Self = @This(); + fn init(w: *Writer, len: usize) StringLiteral { + return .{ + .cur_len = 0, + .len = len, + .w = w, + .first = true, + }; + } - pub fn start(self: *Self) Error!void { - const writer = self.counting_writer.writer(); - if (self.len <= max_string_initializer_len) { - try writer.writeByte('\"'); - } else { - try writer.writeByte('{'); - } + pub fn start(sl: *StringLiteral) Writer.Error!void { + if (sl.len <= max_string_initializer_len) { + try sl.w.writeByte('\"'); + } else { + try sl.w.writeByte('{'); } + } - pub fn end(self: *Self) Error!void { - const writer = self.counting_writer.writer(); - if (self.len <= max_string_initializer_len) { - try writer.writeByte('\"'); - } else { - try writer.writeByte('}'); - } + pub fn end(sl: *StringLiteral) Writer.Error!void { + if (sl.len <= max_string_initializer_len) { + try sl.w.writeByte('\"'); + } else { + try sl.w.writeByte('}'); } + } - fn writeStringLiteralChar(writer: anytype, c: u8) !void { - switch (c) { - 7 => try writer.writeAll("\\a"), - 8 => try writer.writeAll("\\b"), - '\t' => try writer.writeAll("\\t"), - '\n' => try writer.writeAll("\\n"), - 11 => try writer.writeAll("\\v"), - 12 => try writer.writeAll("\\f"), - '\r' => try writer.writeAll("\\r"), - '"', '\'', '?', '\\' => try writer.print("\\{c}", .{c}), - else => switch (c) { - ' '...'~' => try writer.writeByte(c), - else => try writer.print("\\{o:0>3}", .{c}), - }, - } + fn writeStringLiteralChar(sl: *StringLiteral, c: u8) Writer.Error!usize { + const w = sl.w; + switch (c) { + 7 => { + try w.writeAll("\\a"); + return 2; + }, + 8 => { + try w.writeAll("\\b"); + return 2; + }, + '\t' => { + try w.writeAll("\\t"); + return 2; + }, + '\n' => { + try w.writeAll("\\n"); + return 2; + }, + 11 => { + try w.writeAll("\\v"); + return 2; + }, + 12 => { + try w.writeAll("\\f"); + return 2; + }, + '\r' => { + try w.writeAll("\\r"); + return 2; + }, + '"', '\'', '?', '\\' => { + try w.print("\\{c}", .{c}); + return 2; + }, + ' '...'!', '#'...'&', '('...'>', '@'...'[', ']'...'~' => { + try w.writeByte(c); + return 1; + }, + else => { + var buf: [4]u8 = undefined; + const printed = std.fmt.bufPrint(&buf, "\\{o:0>3}", .{c}) catch unreachable; + try w.writeAll(printed); + return printed.len; + }, } + } - pub fn writeChar(self: *Self, c: u8) Error!void { - const writer = self.counting_writer.writer(); - if (self.len <= max_string_initializer_len) { - if (self.cur_len == 0 and self.counting_writer.bytes_written > 1) - try writer.writeAll("\"\""); - - const len = self.counting_writer.bytes_written; - try writeStringLiteralChar(writer, c); + pub fn writeChar(sl: *StringLiteral, c: u8) Writer.Error!void { + if (sl.len <= max_string_initializer_len) { + if (sl.cur_len == 0 and !sl.first) try sl.w.writeAll("\"\""); - const char_length = self.counting_writer.bytes_written - len; - assert(char_length <= max_char_len); - self.cur_len += char_length; + const char_len = try sl.writeStringLiteralChar(c); + assert(char_len <= max_char_len); + sl.cur_len += char_len; - if (self.cur_len >= max_literal_len) self.cur_len = 0; - } else { - if (self.counting_writer.bytes_written > 1) try writer.writeByte(','); - try writer.print("'\\x{x}'", .{c}); + if (sl.cur_len >= max_literal_len) { + sl.cur_len = 0; + sl.first = false; } + } else { + if (!sl.first) try sl.w.writeByte(','); + var buf: [6]u8 = undefined; + const printed = std.fmt.bufPrint(&buf, "'\\x{x}'", .{c}) catch unreachable; + try sl.w.writeAll(printed); + sl.cur_len += printed.len; + sl.first = false; } - }; -} - -fn stringLiteral( - child_stream: anytype, - len: u64, -) StringLiteral(@TypeOf(child_stream)) { - return .{ - .len = len, - .counting_writer = std.io.countingWriter(child_stream), - }; -} + } +}; -const FormatStringContext = struct { str: []const u8, sentinel: ?u8 }; -fn formatStringLiteral( - data: FormatStringContext, - comptime fmt: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { - if (fmt.len != 1 or fmt[0] != 's') @compileError("Invalid fmt: " ++ fmt); +const FormatStringContext = struct { + str: []const u8, + sentinel: ?u8, +}; - var literal = stringLiteral(writer, data.str.len + @intFromBool(data.sentinel != null)); +fn formatStringLiteral(data: FormatStringContext, w: *std.io.Writer) std.io.Writer.Error!void { + var literal: StringLiteral = .init(w, data.str.len + @intFromBool(data.sentinel != null)); try literal.start(); for (data.str) |c| try literal.writeChar(c); if (data.sentinel) |sentinel| if (sentinel != 0) try literal.writeChar(sentinel); try literal.end(); } -fn fmtStringLiteral(str: []const u8, sentinel: ?u8) std.fmt.Formatter(formatStringLiteral) { +fn fmtStringLiteral(str: []const u8, sentinel: ?u8) std.fmt.Formatter(FormatStringContext, formatStringLiteral) { return .{ .data = .{ .str = str, .sentinel = sentinel } }; } @@ -8231,13 +8296,10 @@ const FormatIntLiteralContext = struct { kind: CType.Kind, ctype: CType, val: Value, + base: u8, + case: std.fmt.Case, }; -fn formatIntLiteral( - data: FormatIntLiteralContext, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { +fn formatIntLiteral(data: FormatIntLiteralContext, w: *std.io.Writer) std.io.Writer.Error!void { const pt = data.dg.pt; const zcu = pt.zcu; const target = &data.dg.mod.resolved_target.result; @@ -8262,7 +8324,7 @@ fn formatIntLiteral( var int_buf: Value.BigIntSpace = undefined; const int = if (data.val.isUndefDeep(zcu)) blk: { - undef_limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(data.int_info.bits)); + undef_limbs = allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(data.int_info.bits)) catch return error.WriteFailed; @memset(undef_limbs, undefPattern(BigIntLimb)); var undef_int = BigInt.Mutable{ @@ -8280,7 +8342,7 @@ fn formatIntLiteral( const one = BigInt.Mutable.init(&one_limbs, 1).toConst(); var wrap = BigInt.Mutable{ - .limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(c_bits)), + .limbs = allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(c_bits)) catch return error.WriteFailed, .len = undefined, .positive = undefined, }; @@ -8317,46 +8379,29 @@ fn formatIntLiteral( if (c_limb_info.count == 1) { if (wrap.addWrap(int, one, data.int_info.signedness, c_bits) or data.int_info.signedness == .signed and wrap.subWrap(int, one, data.int_info.signedness, c_bits)) - return writer.print("{s}_{s}", .{ - data.ctype.getStandardDefineAbbrev() orelse return writer.print("zig_{s}Int_{c}{d}", .{ + return w.print("{s}_{s}", .{ + data.ctype.getStandardDefineAbbrev() orelse return w.print("zig_{s}Int_{c}{d}", .{ if (int.positive) "max" else "min", signAbbrev(data.int_info.signedness), c_bits, }), if (int.positive) "MAX" else "MIN", }); - if (!int.positive) try writer.writeByte('-'); - try data.ctype.renderLiteralPrefix(writer, data.kind, ctype_pool); + if (!int.positive) try w.writeByte('-'); + try data.ctype.renderLiteralPrefix(w, data.kind, ctype_pool); - const style: struct { base: u8, case: std.fmt.Case = undefined } = switch (fmt.len) { - 0 => .{ .base = 10 }, - 1 => switch (fmt[0]) { - 'b' => style: { - try writer.writeAll("0b"); - break :style .{ .base = 2 }; - }, - 'o' => style: { - try writer.writeByte('0'); - break :style .{ .base = 8 }; - }, - 'd' => .{ .base = 10 }, - 'x', 'X' => |base| style: { - try writer.writeAll("0x"); - break :style .{ .base = 16, .case = switch (base) { - 'x' => .lower, - 'X' => .upper, - else => unreachable, - } }; - }, - else => @compileError("Invalid fmt: " ++ fmt), - }, - else => @compileError("Invalid fmt: " ++ fmt), - }; - - const string = try int.abs().toStringAlloc(allocator, style.base, style.case); + switch (data.base) { + 2 => try w.writeAll("0b"), + 8 => try w.writeByte('0'), + 10 => {}, + 16 => try w.writeAll("0x"), + else => unreachable, + } + const string = int.abs().toStringAlloc(allocator, data.base, data.case) catch + return error.WriteFailed; defer allocator.free(string); - try writer.writeAll(string); + try w.writeAll(string); } else { - try data.ctype.renderLiteralPrefix(writer, data.kind, ctype_pool); + try data.ctype.renderLiteralPrefix(w, data.kind, ctype_pool); wrap.truncate(int, .unsigned, c_bits); @memset(wrap.limbs[wrap.len..], 0); wrap.len = wrap.limbs.len; @@ -8399,17 +8444,20 @@ fn formatIntLiteral( c_limb_ctype = c_limb_info.ctype; } - if (limb_offset > 0) try writer.writeAll(", "); + if (limb_offset > 0) try w.writeAll(", "); try formatIntLiteral(.{ .dg = data.dg, .int_info = c_limb_int_info, .kind = data.kind, .ctype = c_limb_ctype, - .val = try pt.intValue_big(.comptime_int, c_limb_mut.toConst()), - }, fmt, options, writer); + .val = pt.intValue_big(.comptime_int, c_limb_mut.toConst()) catch + return error.WriteFailed, + .base = data.base, + .case = data.case, + }, w); } } - try data.ctype.renderLiteralSuffix(writer, ctype_pool); + try data.ctype.renderLiteralSuffix(w, ctype_pool); } const Materialize = struct { @@ -8423,8 +8471,8 @@ const Materialize = struct { } }; } - pub fn mat(self: Materialize, f: *Function, writer: anytype) !void { - try f.writeCValue(writer, self.local, .Other); + pub fn mat(self: Materialize, f: *Function, w: *Writer) !void { + try f.writeCValue(w, self.local, .Other); } pub fn end(self: Materialize, f: *Function, inst: Air.Inst.Index) !void { @@ -8435,36 +8483,37 @@ const Materialize = struct { const Assignment = struct { ctype: CType, - pub fn start(f: *Function, writer: anytype, ctype: CType) !Assignment { + pub fn start(f: *Function, w: *Writer, ctype: CType) !Assignment { const self: Assignment = .{ .ctype = ctype }; - try self.restart(f, writer); + try self.restart(f, w); return self; } - pub fn restart(self: Assignment, f: *Function, writer: anytype) !void { + pub fn restart(self: Assignment, f: *Function, w: *Writer) !void { switch (self.strategy(f)) { .assign => {}, - .memcpy => try writer.writeAll("memcpy("), + .memcpy => try w.writeAll("memcpy("), } } - pub fn assign(self: Assignment, f: *Function, writer: anytype) !void { + pub fn assign(self: Assignment, f: *Function, w: *Writer) !void { switch (self.strategy(f)) { - .assign => try writer.writeAll(" = "), - .memcpy => try writer.writeAll(", "), + .assign => try w.writeAll(" = "), + .memcpy => try w.writeAll(", "), } } - pub fn end(self: Assignment, f: *Function, writer: anytype) !void { + pub fn end(self: Assignment, f: *Function, w: *Writer) !void { switch (self.strategy(f)) { .assign => {}, .memcpy => { - try writer.writeAll(", sizeof("); - try f.renderCType(writer, self.ctype); - try writer.writeAll("))"); + try w.writeAll(", sizeof("); + try f.renderCType(w, self.ctype); + try w.writeAll("))"); }, } - try writer.writeAll(";\n"); + try w.writeByte(';'); + try f.object.newline(); } fn strategy(self: Assignment, f: *Function) enum { assign, memcpy } { @@ -8478,37 +8527,39 @@ const Assignment = struct { const Vectorize = struct { index: CValue = .none, - pub fn start(f: *Function, inst: Air.Inst.Index, writer: anytype, ty: Type) !Vectorize { + pub fn start(f: *Function, inst: Air.Inst.Index, w: *Writer, ty: Type) !Vectorize { const pt = f.object.dg.pt; const zcu = pt.zcu; return if (ty.zigTypeTag(zcu) == .vector) index: { const local = try f.allocLocal(inst, .usize); - try writer.writeAll("for ("); - try f.writeCValue(writer, local, .Other); - try writer.print(" = {d}; ", .{try f.fmtIntLiteral(.zero_usize)}); - try f.writeCValue(writer, local, .Other); - try writer.print(" < {d}; ", .{try f.fmtIntLiteral(try pt.intValue(.usize, ty.vectorLen(zcu)))}); - try f.writeCValue(writer, local, .Other); - try writer.print(" += {d}) {{\n", .{try f.fmtIntLiteral(.one_usize)}); - f.object.indent_writer.pushIndent(); + try w.writeAll("for ("); + try f.writeCValue(w, local, .Other); + try w.print(" = {f}; ", .{try f.fmtIntLiteralDec(.zero_usize)}); + try f.writeCValue(w, local, .Other); + try w.print(" < {f}; ", .{try f.fmtIntLiteralDec(try pt.intValue(.usize, ty.vectorLen(zcu)))}); + try f.writeCValue(w, local, .Other); + try w.print(" += {f}) {{\n", .{try f.fmtIntLiteralDec(.one_usize)}); + f.object.indent(); + try f.object.newline(); break :index .{ .index = local }; } else .{}; } - pub fn elem(self: Vectorize, f: *Function, writer: anytype) !void { + pub fn elem(self: Vectorize, f: *Function, w: *Writer) !void { if (self.index != .none) { - try writer.writeByte('['); - try f.writeCValue(writer, self.index, .Other); - try writer.writeByte(']'); + try w.writeByte('['); + try f.writeCValue(w, self.index, .Other); + try w.writeByte(']'); } } - pub fn end(self: Vectorize, f: *Function, inst: Air.Inst.Index, writer: anytype) !void { + pub fn end(self: Vectorize, f: *Function, inst: Air.Inst.Index, w: *Writer) !void { if (self.index != .none) { - f.object.indent_writer.popIndent(); - try writer.writeAll("}\n"); + try f.object.outdent(); + try w.writeByte('}'); + try f.object.newline(); try freeLocal(f, inst, self.index.new_local, null); } } diff --git a/src/codegen/c/Type.zig b/src/codegen/c/Type.zig index 044d947702..77555d773c 100644 --- a/src/codegen/c/Type.zig +++ b/src/codegen/c/Type.zig @@ -209,7 +209,7 @@ pub fn getStandardDefineAbbrev(ctype: CType) ?[]const u8 { }; } -pub fn renderLiteralPrefix(ctype: CType, writer: anytype, kind: Kind, pool: *const Pool) @TypeOf(writer).Error!void { +pub fn renderLiteralPrefix(ctype: CType, w: *Writer, kind: Kind, pool: *const Pool) Writer.Error!void { switch (ctype.info(pool)) { .basic => |basic_info| switch (basic_info) { .void => unreachable, @@ -224,7 +224,7 @@ pub fn renderLiteralPrefix(ctype: CType, writer: anytype, kind: Kind, pool: *con .uintptr_t, .intptr_t, => switch (kind) { - else => try writer.print("({s})", .{@tagName(basic_info)}), + else => try w.print("({s})", .{@tagName(basic_info)}), .global => {}, }, .int, @@ -246,7 +246,7 @@ pub fn renderLiteralPrefix(ctype: CType, writer: anytype, kind: Kind, pool: *con .int32_t, .uint64_t, .int64_t, - => try writer.print("{s}_C(", .{ctype.getStandardDefineAbbrev().?}), + => try w.print("{s}_C(", .{ctype.getStandardDefineAbbrev().?}), .zig_u128, .zig_i128, .zig_f16, @@ -255,7 +255,7 @@ pub fn renderLiteralPrefix(ctype: CType, writer: anytype, kind: Kind, pool: *con .zig_f80, .zig_f128, .zig_c_longdouble, - => try writer.print("zig_{s}_{s}(", .{ + => try w.print("zig_{s}_{s}(", .{ switch (kind) { else => "make", .global => "init", @@ -265,12 +265,12 @@ pub fn renderLiteralPrefix(ctype: CType, writer: anytype, kind: Kind, pool: *con .va_list => unreachable, _ => unreachable, }, - .array, .vector => try writer.writeByte('{'), + .array, .vector => try w.writeByte('{'), else => unreachable, } } -pub fn renderLiteralSuffix(ctype: CType, writer: anytype, pool: *const Pool) @TypeOf(writer).Error!void { +pub fn renderLiteralSuffix(ctype: CType, w: *Writer, pool: *const Pool) Writer.Error!void { switch (ctype.info(pool)) { .basic => |basic_info| switch (basic_info) { .void => unreachable, @@ -280,20 +280,20 @@ pub fn renderLiteralSuffix(ctype: CType, writer: anytype, pool: *const Pool) @Ty .short, .int, => {}, - .long => try writer.writeByte('l'), - .@"long long" => try writer.writeAll("ll"), + .long => try w.writeByte('l'), + .@"long long" => try w.writeAll("ll"), .@"unsigned char", .@"unsigned short", .@"unsigned int", - => try writer.writeByte('u'), + => try w.writeByte('u'), .@"unsigned long", .size_t, .uintptr_t, - => try writer.writeAll("ul"), - .@"unsigned long long" => try writer.writeAll("ull"), - .float => try writer.writeByte('f'), + => try w.writeAll("ul"), + .@"unsigned long long" => try w.writeAll("ull"), + .float => try w.writeByte('f'), .double => {}, - .@"long double" => try writer.writeByte('l'), + .@"long double" => try w.writeByte('l'), .bool, .ptrdiff_t, .intptr_t, @@ -314,11 +314,11 @@ pub fn renderLiteralSuffix(ctype: CType, writer: anytype, pool: *const Pool) @Ty .zig_f80, .zig_f128, .zig_c_longdouble, - => try writer.writeByte(')'), + => try w.writeByte(')'), .va_list => unreachable, _ => unreachable, }, - .array, .vector => try writer.writeByte('}'), + .array, .vector => try w.writeByte('}'), else => unreachable, } } @@ -938,19 +938,13 @@ pub const Pool = struct { index: String.Index, const FormatData = struct { string: String, pool: *const Pool }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (fmt_str.len > 0) @compileError("invalid format string '" ++ fmt_str ++ "'"); + fn format(data: FormatData, writer: *Writer) Writer.Error!void { if (data.string.toSlice(data.pool)) |slice| try writer.writeAll(slice) else try writer.print("f{d}", .{@intFromEnum(data.string.index)}); } - pub fn fmt(str: String, pool: *const Pool) std.fmt.Formatter(format) { + pub fn fmt(str: String, pool: *const Pool) std.fmt.Formatter(FormatData, format) { return .{ .data = .{ .string = str, .pool = pool } }; } @@ -2890,7 +2884,7 @@ pub const Pool = struct { comptime fmt_str: []const u8, fmt_args: anytype, ) !String { - try pool.string_bytes.writer(allocator).print(fmt_str, fmt_args); + try pool.string_bytes.print(allocator, fmt_str, fmt_args); return pool.trailingString(allocator); } @@ -3281,10 +3275,12 @@ pub const AlignAs = packed struct { } }; +const std = @import("std"); const assert = std.debug.assert; +const Writer = std.io.Writer; + const CType = @This(); const InternPool = @import("../../InternPool.zig"); const Module = @import("../../Package/Module.zig"); -const std = @import("std"); const Type = @import("../../Type.zig"); const Zcu = @import("../../Zcu.zig"); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 5135095f69..3d670dce83 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -239,12 +239,12 @@ pub fn targetTriple(allocator: Allocator, target: *const std.Target) ![]const u8 .none, .windows, => {}, - .semver => |ver| try llvm_triple.writer().print("{d}.{d}.{d}", .{ + .semver => |ver| try llvm_triple.print("{d}.{d}.{d}", .{ ver.min.major, ver.min.minor, ver.min.patch, }), - inline .linux, .hurd => |ver| try llvm_triple.writer().print("{d}.{d}.{d}", .{ + inline .linux, .hurd => |ver| try llvm_triple.print("{d}.{d}.{d}", .{ ver.range.min.major, ver.range.min.minor, ver.range.min.patch, @@ -295,13 +295,13 @@ pub fn targetTriple(allocator: Allocator, target: *const std.Target) ![]const u8 .windows, => {}, inline .hurd, .linux => |ver| if (target.abi.isGnu()) { - try llvm_triple.writer().print("{d}.{d}.{d}", .{ + try llvm_triple.print("{d}.{d}.{d}", .{ ver.glibc.major, ver.glibc.minor, ver.glibc.patch, }); } else if (@TypeOf(ver) == std.Target.Os.LinuxVersionRange and target.abi.isAndroid()) { - try llvm_triple.writer().print("{d}", .{ver.android}); + try llvm_triple.print("{d}", .{ver.android}); }, } @@ -746,12 +746,18 @@ pub const Object = struct { try wip.finish(); } - fn genModuleLevelAssembly(object: *Object) !void { - const writer = object.builder.setModuleAsm(); + fn genModuleLevelAssembly(object: *Object) Allocator.Error!void { + const b = &object.builder; + const gpa = b.gpa; + b.module_asm.clearRetainingCapacity(); for (object.pt.zcu.global_assembly.values()) |assembly| { - try writer.print("{s}\n", .{assembly}); + try b.module_asm.ensureUnusedCapacity(gpa, assembly.len + 1); + b.module_asm.appendSliceAssumeCapacity(assembly); + b.module_asm.appendAssumeCapacity('\n'); + } + if (b.module_asm.getLastOrNull()) |last| { + if (last != '\n') try b.module_asm.append(gpa, '\n'); } - try object.builder.finishModuleAsm(); } pub const EmitOptions = struct { @@ -939,7 +945,9 @@ pub const Object = struct { if (std.mem.eql(u8, path, "-")) { o.builder.dump(); } else { - _ = try o.builder.printToFile(path); + o.builder.printToFilePath(std.fs.cwd(), path) catch |err| { + log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) }); + }; } } @@ -2486,7 +2494,7 @@ pub const Object = struct { var union_name_buf: ?[:0]const u8 = null; defer if (union_name_buf) |buf| gpa.free(buf); const union_name = if (layout.tag_size == 0) name else name: { - union_name_buf = try std.fmt.allocPrintZ(gpa, "{s}:Payload", .{name}); + union_name_buf = try std.fmt.allocPrintSentinel(gpa, "{s}:Payload", .{name}, 0); break :name union_name_buf.?; }; @@ -2680,10 +2688,12 @@ pub const Object = struct { } fn allocTypeName(o: *Object, ty: Type) Allocator.Error![:0]const u8 { - var buffer = std.ArrayList(u8).init(o.gpa); - errdefer buffer.deinit(); - try ty.print(buffer.writer(), o.pt); - return buffer.toOwnedSliceSentinel(0); + var aw: std.io.Writer.Allocating = .init(o.gpa); + defer aw.deinit(); + ty.print(&aw.writer, o.pt) catch |err| switch (err) { + error.WriteFailed => return error.OutOfMemory, + }; + return aw.toOwnedSliceSentinel(0); } /// If the llvm function does not exist, create it. @@ -4482,7 +4492,7 @@ pub const Object = struct { const target = &zcu.root_mod.resolved_target.result; const function_index = try o.builder.addFunction( try o.builder.fnType(ret_ty, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal), - try o.builder.strtabStringFmt("__zig_tag_name_{}", .{enum_type.name.fmt(ip)}), + try o.builder.strtabStringFmt("__zig_tag_name_{f}", .{enum_type.name.fmt(ip)}), toLlvmAddressSpace(.generic, target), ); @@ -4633,7 +4643,7 @@ pub const NavGen = struct { if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") { if (lib_name.toSlice(ip)) |lib_name_slice| { if (!std.mem.eql(u8, lib_name_slice, "c")) { - break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ nav.name.fmt(ip), lib_name_slice }); + break :decl_name try o.builder.strtabStringFmt("{f}|{s}", .{ nav.name.fmt(ip), lib_name_slice }); } } } @@ -7472,7 +7482,7 @@ pub const FuncGen = struct { llvm_param_types[llvm_param_i] = llvm_elem_ty; } - try llvm_constraints.writer(self.gpa).print(",{d}", .{output_index}); + try llvm_constraints.print(self.gpa, ",{d}", .{output_index}); // In the case of indirect inputs, LLVM requires the callsite to have // an elementtype(<ty>) attribute. @@ -7573,7 +7583,7 @@ pub const FuncGen = struct { // we should validate the assembly in Sema; by now it is too late return self.todo("unknown input or output name: '{s}'", .{name}); }; - try rendered_template.writer().print("{d}", .{index}); + try rendered_template.print("{d}", .{index}); if (byte == ':') { try rendered_template.append(':'); modifier_start = i + 1; @@ -10370,7 +10380,7 @@ pub const FuncGen = struct { const target = &zcu.root_mod.resolved_target.result; const function_index = try o.builder.addFunction( try o.builder.fnType(.i1, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal), - try o.builder.strtabStringFmt("__zig_is_named_enum_value_{}", .{enum_type.name.fmt(ip)}), + try o.builder.strtabStringFmt("__zig_is_named_enum_value_{f}", .{enum_type.name.fmt(ip)}), toLlvmAddressSpace(.generic, target), ); diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 8a782c54aa..f263e567e8 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -817,7 +817,7 @@ const NavGen = struct { const result_ty_id = try self.resolveType(ty, repr); const ip = &zcu.intern_pool; - log.debug("lowering constant: ty = {}, val = {}, key = {s}", .{ ty.fmt(pt), val.fmtValue(pt), @tagName(ip.indexToKey(val.toIntern())) }); + log.debug("lowering constant: ty = {f}, val = {f}, key = {s}", .{ ty.fmt(pt), val.fmtValue(pt), @tagName(ip.indexToKey(val.toIntern())) }); if (val.isUndefDeep(zcu)) { return self.spv.constUndef(result_ty_id); } @@ -1147,7 +1147,7 @@ const NavGen = struct { return result_ptr_id; } - return self.fail("cannot perform pointer cast: '{}' to '{}'", .{ + return self.fail("cannot perform pointer cast: '{f}' to '{f}'", .{ parent_ptr_ty.fmt(pt), oac.new_ptr_ty.fmt(pt), }); @@ -1260,10 +1260,12 @@ const NavGen = struct { // Turn a Zig type's name into a cache reference. fn resolveTypeName(self: *NavGen, ty: Type) ![]const u8 { - var name = std.ArrayList(u8).init(self.gpa); - defer name.deinit(); - try ty.print(name.writer(), self.pt); - return try name.toOwnedSlice(); + var aw: std.io.Writer.Allocating = .init(self.gpa); + defer aw.deinit(); + ty.print(&aw.writer, self.pt) catch |err| switch (err) { + error.WriteFailed => return error.OutOfMemory, + }; + return try aw.toOwnedSlice(); } /// Create an integer type suitable for storing at least 'bits' bits. @@ -1462,7 +1464,7 @@ const NavGen = struct { const pt = self.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; - log.debug("resolveType: ty = {}", .{ty.fmt(pt)}); + log.debug("resolveType: ty = {f}", .{ty.fmt(pt)}); const target = self.spv.target; const section = &self.spv.sections.types_globals_constants; @@ -3068,7 +3070,7 @@ const NavGen = struct { try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); try self.spv.addFunction(spv_decl_index, self.func); - try self.spv.debugNameFmt(initializer_id, "initializer of {}", .{nav.fqn.fmt(ip)}); + try self.spv.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)}); try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{ .id_result_type = ptr_ty_id, diff --git a/src/codegen/spirv/spec.zig b/src/codegen/spirv/spec.zig index 970f5bfe7f..82ec05ebba 100644 --- a/src/codegen/spirv/spec.zig +++ b/src/codegen/spirv/spec.zig @@ -1,6 +1,7 @@ //! This file is auto-generated by tools/gen_spirv_spec.zig. const std = @import("std"); +const assert = std.debug.assert; pub const Version = packed struct(Word) { padding: u8 = 0, @@ -18,15 +19,10 @@ pub const IdResult = enum(Word) { none, _, - pub fn format( - self: IdResult, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(self: IdResult, writer: *std.io.Writer) std.io.Writer.Error!void { switch (self) { .none => try writer.writeAll("(none)"), - else => try writer.print("%{}", .{@intFromEnum(self)}), + else => try writer.print("%{d}", .{@intFromEnum(self)}), } } }; |
