From 5913140b6bf96e168a0167906a78e2d4aac5bd9d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 21 Sep 2021 15:08:32 -0700 Subject: stage2: free Sema's arena after generating machine code Previously, linker backends or machine code backends were able to hold on to references to inside Sema's temporary arena. However there can be large objects stored there that we want to free after machine code is generated. The primary change in this commit is to use a temporary arena for Sema of function bodies that gets freed after machine code backend finishes handling `updateFunc` (at the same time that Air and Liveness get freed). The other changes in this commit are fixing issues that fell out from the primary change. * The C linker backend is rewritten to handle updateDecl and updateFunc separately. Also, all Decl updates get access to typedefs and fwd_decls, not only functions. * The C linker backend is updated to the new API that does not depend on allocateDeclIndexes and does not have to handle garbage collected decls. * The C linker backend uses an arena for Type/Value objects that `typedefs` references. These can be garbage collected every so often after flush(), however that garbage collection code is not implemented at this time. It will be pretty simple, just allocate a new arena, copy all the Type objects to it, update the keys of the hash map, free the old arena. * Sema: fix a handful of instances of not copying Type/Value objects from the temporary arena into the appropriate Decl arena. * Type: fix some function types not reporting hasCodeGenBits() correctly. --- src/codegen/c.zig | 1095 +++++++++++++++++++++++++++-------------------------- 1 file changed, 566 insertions(+), 529 deletions(-) (limited to 'src/codegen') diff --git a/src/codegen/c.zig b/src/codegen/c.zig index fb8211f6b8..c4e1d48062 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -91,55 +91,76 @@ pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) { return .{ .data = ident }; } -/// This data is available when outputting .c code for a Module. +/// This data is available when outputting .c code for a `*Module.Fn`. /// It is not available when generating .h file. -pub const Object = struct { - dg: DeclGen, +pub const Function = struct { air: Air, liveness: Liveness, - gpa: *mem.Allocator, - code: std.ArrayList(u8), value_map: CValueMap, blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{}, next_arg_index: usize = 0, next_local_index: usize = 0, next_block_index: usize = 0, - indent_writer: IndentWriter(std.ArrayList(u8).Writer), + object: Object, + func: *Module.Fn, - fn resolveInst(o: *Object, inst: Air.Inst.Ref) !CValue { - if (o.air.value(inst)) |_| { + fn resolveInst(f: *Function, inst: Air.Inst.Ref) !CValue { + if (f.air.value(inst)) |_| { return CValue{ .constant = inst }; } const index = Air.refToIndex(inst).?; - return o.value_map.get(index).?; // Assertion means instruction does not dominate usage. + return f.value_map.get(index).?; // Assertion means instruction does not dominate usage. } - fn allocLocalValue(o: *Object) CValue { - const result = o.next_local_index; - o.next_local_index += 1; + fn allocLocalValue(f: *Function) CValue { + const result = f.next_local_index; + f.next_local_index += 1; return .{ .local = result }; } - fn allocLocal(o: *Object, ty: Type, mutability: Mutability) !CValue { - const local_value = o.allocLocalValue(); - try o.renderTypeAndName(o.writer(), ty, local_value, mutability); + fn allocLocal(f: *Function, ty: Type, mutability: Mutability) !CValue { + const local_value = f.allocLocalValue(); + try f.object.renderTypeAndName(f.object.writer(), ty, local_value, mutability); return local_value; } + fn writeCValue(f: *Function, w: anytype, c_value: CValue) !void { + switch (c_value) { + .constant => |inst| { + const ty = f.air.typeOf(inst); + const val = f.air.value(inst).?; + return f.object.dg.renderValue(w, ty, val); + }, + else => return Object.writeCValue(w, c_value), + } + } + + fn fail(f: *Function, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { + return f.object.dg.fail(format, args); + } + + fn renderType(f: *Function, w: anytype, t: Type) !void { + return f.object.dg.renderType(w, t); + } +}; + +/// This data is available when outputting .c code for a `Module`. +/// It is not available when generating .h file. +pub const Object = struct { + dg: DeclGen, + code: std.ArrayList(u8), + indent_writer: IndentWriter(std.ArrayList(u8).Writer), + fn writer(o: *Object) IndentWriter(std.ArrayList(u8).Writer).Writer { return o.indent_writer.writer(); } - fn writeCValue(o: *Object, w: anytype, c_value: CValue) !void { + fn writeCValue(w: anytype, c_value: CValue) !void { switch (c_value) { .none => unreachable, .local => |i| return w.print("t{d}", .{i}), .local_ref => |i| return w.print("&t{d}", .{i}), - .constant => |inst| { - const ty = o.air.typeOf(inst); - const val = o.air.value(inst).?; - return o.dg.renderValue(w, ty, val); - }, + .constant => unreachable, .arg => |i| return w.print("a{d}", .{i}), .decl => |decl| return w.writeAll(mem.span(decl.name)), .decl_ref => |decl| return w.print("&{s}", .{decl.name}), @@ -153,7 +174,7 @@ pub const Object = struct { name: CValue, mutability: Mutability, ) error{ OutOfMemory, AnalysisFail }!void { - var suffix = std.ArrayList(u8).init(o.gpa); + var suffix = std.ArrayList(u8).init(o.dg.gpa); defer suffix.deinit(); var render_ty = ty; @@ -177,7 +198,7 @@ pub const Object = struct { .Const => try w.writeAll("const "), .Mut => {}, } - try o.writeCValue(w, name); + try writeCValue(w, name); try w.writeAll(")("); const param_len = render_ty.fnParamLen(); const is_var_args = render_ty.fnIsVarArgs(); @@ -205,7 +226,7 @@ pub const Object = struct { .Mut => "", }; try w.print(" {s}", .{const_prefix}); - try o.writeCValue(w, name); + try writeCValue(w, name); } try w.writeAll(suffix.items); } @@ -213,11 +234,14 @@ pub const Object = struct { /// This data is available both when outputting .c code and when outputting an .h file. pub const DeclGen = struct { + gpa: *std.mem.Allocator, module: *Module, decl: *Decl, fwd_decl: std.ArrayList(u8), error_msg: ?*Module.ErrorMsg, + /// The key of this map is Type which has references to typedefs_arena. typedefs: TypedefMap, + typedefs_arena: *std.mem.Allocator, fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { @setCold(true); @@ -545,7 +569,10 @@ pub const DeclGen = struct { try dg.typedefs.ensureUnusedCapacity(1); try w.writeAll(name); - dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered }); + dg.typedefs.putAssumeCapacityNoClobber( + try t.copy(dg.typedefs_arena), + .{ .name = name, .rendered = rendered }, + ); } else { try dg.renderType(w, t.elemType()); try w.writeAll(" *"); @@ -586,7 +613,10 @@ pub const DeclGen = struct { try dg.typedefs.ensureUnusedCapacity(1); try w.writeAll(name); - dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered }); + dg.typedefs.putAssumeCapacityNoClobber( + try t.copy(dg.typedefs_arena), + .{ .name = name, .rendered = rendered }, + ); }, .ErrorSet => { comptime std.debug.assert(Type.initTag(.anyerror).abiSize(std.Target.current) == 2); @@ -626,7 +656,10 @@ pub const DeclGen = struct { try dg.typedefs.ensureUnusedCapacity(1); try w.writeAll(name); - dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered }); + dg.typedefs.putAssumeCapacityNoClobber( + try t.copy(dg.typedefs_arena), + .{ .name = name, .rendered = rendered }, + ); }, .Struct => { if (dg.typedefs.get(t)) |some| { @@ -659,7 +692,10 @@ pub const DeclGen = struct { try dg.typedefs.ensureUnusedCapacity(1); try w.writeAll(name); - dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered }); + dg.typedefs.putAssumeCapacityNoClobber( + try t.copy(dg.typedefs_arena), + .{ .name = name, .rendered = rendered }, + ); }, .Enum => { // For enums, we simply use the integer tag type. @@ -724,6 +760,29 @@ pub const DeclGen = struct { } }; +pub fn genFunc(f: *Function) !void { + const tracy = trace(@src()); + defer tracy.end(); + + const o = &f.object; + const is_global = o.dg.module.decl_exports.contains(f.func.owner_decl); + const fwd_decl_writer = o.dg.fwd_decl.writer(); + if (is_global) { + try fwd_decl_writer.writeAll("ZIG_EXTERN_C "); + } + try o.dg.renderFunctionSignature(fwd_decl_writer, is_global); + try fwd_decl_writer.writeAll(";\n"); + + try o.indent_writer.insertNewline(); + try o.dg.renderFunctionSignature(o.writer(), is_global); + + try o.writer().writeByte(' '); + const main_body = f.air.getMainBody(); + try genBody(f, main_body); + + try o.indent_writer.insertNewline(); +} + pub fn genDecl(o: *Object) !void { const tracy = trace(@src()); defer tracy.end(); @@ -732,28 +791,6 @@ pub fn genDecl(o: *Object) !void { .ty = o.dg.decl.ty, .val = o.dg.decl.val, }; - if (tv.val.castTag(.function)) |func_payload| { - const func: *Module.Fn = func_payload.data; - if (func.owner_decl == o.dg.decl) { - const is_global = o.dg.declIsGlobal(tv); - const fwd_decl_writer = o.dg.fwd_decl.writer(); - if (is_global) { - try fwd_decl_writer.writeAll("ZIG_EXTERN_C "); - } - try o.dg.renderFunctionSignature(fwd_decl_writer, is_global); - try fwd_decl_writer.writeAll(";\n"); - - try o.indent_writer.insertNewline(); - try o.dg.renderFunctionSignature(o.writer(), is_global); - - try o.writer().writeByte(' '); - const main_body = o.air.getMainBody(); - try genBody(o, main_body); - - try o.indent_writer.insertNewline(); - return; - } - } if (tv.val.tag() == .extern_fn) { const writer = o.writer(); try writer.writeAll("ZIG_EXTERN_C "); @@ -821,250 +858,250 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { } } -fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void { - const writer = o.writer(); +fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void { + const writer = f.object.writer(); if (body.len == 0) { try writer.writeAll("{}"); return; } try writer.writeAll("{\n"); - o.indent_writer.pushIndent(); + f.object.indent_writer.pushIndent(); - const air_tags = o.air.instructions.items(.tag); + const air_tags = f.air.instructions.items(.tag); for (body) |inst| { const result_value = switch (air_tags[inst]) { // zig fmt: off .constant => unreachable, // excluded from function bodies .const_ty => unreachable, // excluded from function bodies - .arg => airArg(o), + .arg => airArg(f), - .breakpoint => try airBreakpoint(o), - .unreach => try airUnreach(o), - .fence => try airFence(o, inst), + .breakpoint => try airBreakpoint(f), + .unreach => try airUnreach(f), + .fence => try airFence(f, inst), // TODO use a different strategy for add that communicates to the optimizer // that wrapping is UB. - .add, .ptr_add => try airBinOp( o, inst, " + "), - .addwrap => try airWrapOp(o, inst, " + ", "addw_"), + .add, .ptr_add => try airBinOp( f, inst, " + "), + .addwrap => try airWrapOp(f, inst, " + ", "addw_"), // TODO use a different strategy for sub that communicates to the optimizer // that wrapping is UB. - .sub, .ptr_sub => try airBinOp( o, inst, " - "), - .subwrap => try airWrapOp(o, inst, " - ", "subw_"), + .sub, .ptr_sub => try airBinOp( f, inst, " - "), + .subwrap => try airWrapOp(f, inst, " - ", "subw_"), // TODO use a different strategy for mul that communicates to the optimizer // that wrapping is UB. - .mul => try airBinOp( o, inst, " * "), - .mulwrap => try airWrapOp(o, inst, " * ", "mulw_"), + .mul => try airBinOp( f, inst, " * "), + .mulwrap => try airWrapOp(f, inst, " * ", "mulw_"), // TODO use a different strategy for div that communicates to the optimizer // that wrapping is UB. - .div => try airBinOp( o, inst, " / "), - .rem => try airBinOp( o, inst, " % "), + .div => try airBinOp( f, inst, " / "), + .rem => try airBinOp( f, inst, " % "), - .cmp_eq => try airBinOp(o, inst, " == "), - .cmp_gt => try airBinOp(o, inst, " > "), - .cmp_gte => try airBinOp(o, inst, " >= "), - .cmp_lt => try airBinOp(o, inst, " < "), - .cmp_lte => try airBinOp(o, inst, " <= "), - .cmp_neq => try airBinOp(o, inst, " != "), + .cmp_eq => try airBinOp(f, inst, " == "), + .cmp_gt => try airBinOp(f, inst, " > "), + .cmp_gte => try airBinOp(f, inst, " >= "), + .cmp_lt => try airBinOp(f, inst, " < "), + .cmp_lte => try airBinOp(f, inst, " <= "), + .cmp_neq => try airBinOp(f, inst, " != "), // bool_and and bool_or are non-short-circuit operations - .bool_and => try airBinOp(o, inst, " & "), - .bool_or => try airBinOp(o, inst, " | "), - .bit_and => try airBinOp(o, inst, " & "), - .bit_or => try airBinOp(o, inst, " | "), - .xor => try airBinOp(o, inst, " ^ "), - - .shr => try airBinOp(o, inst, " >> "), - .shl => try airBinOp(o, inst, " << "), - - .not => try airNot( o, inst), - - .optional_payload => try airOptionalPayload(o, inst), - .optional_payload_ptr => try airOptionalPayload(o, inst), - - .is_err => try airIsErr(o, inst, "", ".", "!="), - .is_non_err => try airIsErr(o, inst, "", ".", "=="), - .is_err_ptr => try airIsErr(o, inst, "*", "->", "!="), - .is_non_err_ptr => try airIsErr(o, inst, "*", "->", "=="), - - .is_null => try airIsNull(o, inst, "==", ""), - .is_non_null => try airIsNull(o, inst, "!=", ""), - .is_null_ptr => try airIsNull(o, inst, "==", "[0]"), - .is_non_null_ptr => try airIsNull(o, inst, "!=", "[0]"), - - .alloc => try airAlloc(o, inst), - .assembly => try airAsm(o, inst), - .block => try airBlock(o, inst), - .bitcast => try airBitcast(o, inst), - .call => try airCall(o, inst), - .dbg_stmt => try airDbgStmt(o, inst), - .intcast => try airIntCast(o, inst), - .trunc => try airTrunc(o, inst), - .bool_to_int => try airBoolToInt(o, inst), - .load => try airLoad(o, inst), - .ret => try airRet(o, inst), - .store => try airStore(o, inst), - .loop => try airLoop(o, inst), - .cond_br => try airCondBr(o, inst), - .br => try airBr(o, inst), - .switch_br => try airSwitchBr(o, inst), - .wrap_optional => try airWrapOptional(o, inst), - .struct_field_ptr => try airStructFieldPtr(o, inst), - .array_to_slice => try airArrayToSlice(o, inst), - .cmpxchg_weak => try airCmpxchg(o, inst, "weak"), - .cmpxchg_strong => try airCmpxchg(o, inst, "strong"), - .atomic_rmw => try airAtomicRmw(o, inst), - .atomic_load => try airAtomicLoad(o, inst), - - .int_to_float, .float_to_int => try airSimpleCast(o, inst), - - .atomic_store_unordered => try airAtomicStore(o, inst, toMemoryOrder(.Unordered)), - .atomic_store_monotonic => try airAtomicStore(o, inst, toMemoryOrder(.Monotonic)), - .atomic_store_release => try airAtomicStore(o, inst, toMemoryOrder(.Release)), - .atomic_store_seq_cst => try airAtomicStore(o, inst, toMemoryOrder(.SeqCst)), - - .struct_field_ptr_index_0 => try airStructFieldPtrIndex(o, inst, 0), - .struct_field_ptr_index_1 => try airStructFieldPtrIndex(o, inst, 1), - .struct_field_ptr_index_2 => try airStructFieldPtrIndex(o, inst, 2), - .struct_field_ptr_index_3 => try airStructFieldPtrIndex(o, inst, 3), - - .struct_field_val => try airStructFieldVal(o, inst), - .slice_ptr => try airSliceField(o, inst, ".ptr;\n"), - .slice_len => try airSliceField(o, inst, ".len;\n"), - - .ptr_elem_val => try airPtrElemVal(o, inst, "["), - .ptr_ptr_elem_val => try airPtrElemVal(o, inst, "[0]["), - .ptr_elem_ptr => try airPtrElemPtr(o, inst), - .slice_elem_val => try airSliceElemVal(o, inst, "["), - .ptr_slice_elem_val => try airSliceElemVal(o, inst, "[0]["), - - .unwrap_errunion_payload => try airUnwrapErrUnionPay(o, inst), - .unwrap_errunion_err => try airUnwrapErrUnionErr(o, inst), - .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(o, inst), - .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(o, inst), - .wrap_errunion_payload => try airWrapErrUnionPay(o, inst), - .wrap_errunion_err => try airWrapErrUnionErr(o, inst), - - .ptrtoint => return o.dg.fail("TODO: C backend: implement codegen for ptrtoint", .{}), - .floatcast => return o.dg.fail("TODO: C backend: implement codegen for floatcast", .{}), + .bool_and => try airBinOp(f, inst, " & "), + .bool_or => try airBinOp(f, inst, " | "), + .bit_and => try airBinOp(f, inst, " & "), + .bit_or => try airBinOp(f, inst, " | "), + .xor => try airBinOp(f, inst, " ^ "), + + .shr => try airBinOp(f, inst, " >> "), + .shl => try airBinOp(f, inst, " << "), + + .not => try airNot( f, inst), + + .optional_payload => try airOptionalPayload(f, inst), + .optional_payload_ptr => try airOptionalPayload(f, inst), + + .is_err => try airIsErr(f, inst, "", ".", "!="), + .is_non_err => try airIsErr(f, inst, "", ".", "=="), + .is_err_ptr => try airIsErr(f, inst, "*", "->", "!="), + .is_non_err_ptr => try airIsErr(f, inst, "*", "->", "=="), + + .is_null => try airIsNull(f, inst, "==", ""), + .is_non_null => try airIsNull(f, inst, "!=", ""), + .is_null_ptr => try airIsNull(f, inst, "==", "[0]"), + .is_non_null_ptr => try airIsNull(f, inst, "!=", "[0]"), + + .alloc => try airAlloc(f, inst), + .assembly => try airAsm(f, inst), + .block => try airBlock(f, inst), + .bitcast => try airBitcast(f, inst), + .call => try airCall(f, inst), + .dbg_stmt => try airDbgStmt(f, inst), + .intcast => try airIntCast(f, inst), + .trunc => try airTrunc(f, inst), + .bool_to_int => try airBoolToInt(f, inst), + .load => try airLoad(f, inst), + .ret => try airRet(f, inst), + .store => try airStore(f, inst), + .loop => try airLoop(f, inst), + .cond_br => try airCondBr(f, inst), + .br => try airBr(f, inst), + .switch_br => try airSwitchBr(f, inst), + .wrap_optional => try airWrapOptional(f, inst), + .struct_field_ptr => try airStructFieldPtr(f, inst), + .array_to_slice => try airArrayToSlice(f, inst), + .cmpxchg_weak => try airCmpxchg(f, inst, "weak"), + .cmpxchg_strong => try airCmpxchg(f, inst, "strong"), + .atomic_rmw => try airAtomicRmw(f, inst), + .atomic_load => try airAtomicLoad(f, inst), + + .int_to_float, .float_to_int => try airSimpleCast(f, inst), + + .atomic_store_unordered => try airAtomicStore(f, inst, toMemoryOrder(.Unordered)), + .atomic_store_monotonic => try airAtomicStore(f, inst, toMemoryOrder(.Monotonic)), + .atomic_store_release => try airAtomicStore(f, inst, toMemoryOrder(.Release)), + .atomic_store_seq_cst => try airAtomicStore(f, inst, toMemoryOrder(.SeqCst)), + + .struct_field_ptr_index_0 => try airStructFieldPtrIndex(f, inst, 0), + .struct_field_ptr_index_1 => try airStructFieldPtrIndex(f, inst, 1), + .struct_field_ptr_index_2 => try airStructFieldPtrIndex(f, inst, 2), + .struct_field_ptr_index_3 => try airStructFieldPtrIndex(f, inst, 3), + + .struct_field_val => try airStructFieldVal(f, inst), + .slice_ptr => try airSliceField(f, inst, ".ptr;\n"), + .slice_len => try airSliceField(f, inst, ".len;\n"), + + .ptr_elem_val => try airPtrElemVal(f, inst, "["), + .ptr_ptr_elem_val => try airPtrElemVal(f, inst, "[0]["), + .ptr_elem_ptr => try airPtrElemPtr(f, inst), + .slice_elem_val => try airSliceElemVal(f, inst, "["), + .ptr_slice_elem_val => try airSliceElemVal(f, inst, "[0]["), + + .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst), + .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst), + .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst), + .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst), + .wrap_errunion_payload => try airWrapErrUnionPay(f, inst), + .wrap_errunion_err => try airWrapErrUnionErr(f, inst), + + .ptrtoint => return f.fail("TODO: C backend: implement codegen for ptrtoint", .{}), + .floatcast => return f.fail("TODO: C backend: implement codegen for floatcast", .{}), // zig fmt: on }; switch (result_value) { .none => {}, - else => try o.value_map.putNoClobber(inst, result_value), + else => try f.value_map.putNoClobber(inst, result_value), } } - o.indent_writer.popIndent(); + f.object.indent_writer.popIndent(); try writer.writeAll("}"); } -fn airSliceField(o: *Object, inst: Air.Inst.Index, suffix: []const u8) !CValue { - if (o.liveness.isUnused(inst)) +fn airSliceField(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const operand = try o.resolveInst(ty_op.operand); - const writer = o.writer(); - const local = try o.allocLocal(Type.initTag(.usize), .Const); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const operand = try f.resolveInst(ty_op.operand); + const writer = f.object.writer(); + const local = try f.allocLocal(Type.initTag(.usize), .Const); try writer.writeAll(" = "); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll(suffix); return local; } -fn airPtrElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue { +fn airPtrElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue { const is_volatile = false; // TODO - if (!is_volatile and o.liveness.isUnused(inst)) + if (!is_volatile and f.liveness.isUnused(inst)) return CValue.none; _ = prefix; - return o.dg.fail("TODO: C backend: airPtrElemVal", .{}); + return f.fail("TODO: C backend: airPtrElemVal", .{}); } -fn airPtrElemPtr(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - return o.dg.fail("TODO: C backend: airPtrElemPtr", .{}); + return f.fail("TODO: C backend: airPtrElemPtr", .{}); } -fn airSliceElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue { +fn airSliceElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue { const is_volatile = false; // TODO - if (!is_volatile and o.liveness.isUnused(inst)) + if (!is_volatile and f.liveness.isUnused(inst)) return CValue.none; - const bin_op = o.air.instructions.items(.data)[inst].bin_op; - const slice = try o.resolveInst(bin_op.lhs); - const index = try o.resolveInst(bin_op.rhs); - const writer = o.writer(); - const local = try o.allocLocal(o.air.typeOfIndex(inst), .Const); + const bin_op = f.air.instructions.items(.data)[inst].bin_op; + const slice = try f.resolveInst(bin_op.lhs); + const index = try f.resolveInst(bin_op.rhs); + const writer = f.object.writer(); + const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); try writer.writeAll(" = "); - try o.writeCValue(writer, slice); + try f.writeCValue(writer, slice); try writer.writeAll(prefix); - try o.writeCValue(writer, index); + try f.writeCValue(writer, index); try writer.writeAll("];\n"); return local; } -fn airAlloc(o: *Object, inst: Air.Inst.Index) !CValue { - const writer = o.writer(); - const inst_ty = o.air.typeOfIndex(inst); +fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { + const writer = f.object.writer(); + const inst_ty = f.air.typeOfIndex(inst); // First line: the variable used as data storage. const elem_type = inst_ty.elemType(); const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut; - const local = try o.allocLocal(elem_type, mutability); + const local = try f.allocLocal(elem_type, mutability); try writer.writeAll(";\n"); return CValue{ .local_ref = local.local }; } -fn airArg(o: *Object) CValue { - const i = o.next_arg_index; - o.next_arg_index += 1; +fn airArg(f: *Function) CValue { + const i = f.next_arg_index; + f.next_arg_index += 1; return .{ .arg = i }; } -fn airLoad(o: *Object, inst: Air.Inst.Index) !CValue { - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const is_volatile = o.air.typeOf(ty_op.operand).isVolatilePtr(); - if (!is_volatile and o.liveness.isUnused(inst)) +fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const is_volatile = f.air.typeOf(ty_op.operand).isVolatilePtr(); + if (!is_volatile and f.liveness.isUnused(inst)) return CValue.none; - const inst_ty = o.air.typeOfIndex(inst); - const operand = try o.resolveInst(ty_op.operand); - const writer = o.writer(); - const local = try o.allocLocal(inst_ty, .Const); + const inst_ty = f.air.typeOfIndex(inst); + const operand = try f.resolveInst(ty_op.operand); + const writer = f.object.writer(); + const local = try f.allocLocal(inst_ty, .Const); switch (operand) { .local_ref => |i| { const wrapped: CValue = .{ .local = i }; try writer.writeAll(" = "); - try o.writeCValue(writer, wrapped); + try f.writeCValue(writer, wrapped); try writer.writeAll(";\n"); }, .decl_ref => |decl| { const wrapped: CValue = .{ .decl = decl }; try writer.writeAll(" = "); - try o.writeCValue(writer, wrapped); + try f.writeCValue(writer, wrapped); try writer.writeAll(";\n"); }, else => { try writer.writeAll(" = *"); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll(";\n"); }, } return local; } -fn airRet(o: *Object, inst: Air.Inst.Index) !CValue { - const un_op = o.air.instructions.items(.data)[inst].un_op; - const writer = o.writer(); - if (o.air.typeOf(un_op).hasCodeGenBits()) { - const operand = try o.resolveInst(un_op); +fn airRet(f: *Function, inst: Air.Inst.Index) !CValue { + const un_op = f.air.instructions.items(.data)[inst].un_op; + const writer = f.object.writer(); + if (f.air.typeOf(un_op).hasCodeGenBits()) { + const operand = try f.resolveInst(un_op); try writer.writeAll("return "); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll(";\n"); } else { try writer.writeAll("return;\n"); @@ -1072,75 +1109,75 @@ fn airRet(o: *Object, inst: Air.Inst.Index) !CValue { return CValue.none; } -fn airIntCast(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const operand = try o.resolveInst(ty_op.operand); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const operand = try f.resolveInst(ty_op.operand); - const writer = o.writer(); - const inst_ty = o.air.typeOfIndex(inst); - const local = try o.allocLocal(inst_ty, .Const); + const writer = f.object.writer(); + const inst_ty = f.air.typeOfIndex(inst); + const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = ("); - try o.dg.renderType(writer, inst_ty); + try f.renderType(writer, inst_ty); try writer.writeAll(")"); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll(";\n"); return local; } -fn airTrunc(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const operand = try o.resolveInst(ty_op.operand); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const operand = try f.resolveInst(ty_op.operand); _ = operand; - return o.dg.fail("TODO: C backend: airTrunc", .{}); + return f.fail("TODO: C backend: airTrunc", .{}); } -fn airBoolToInt(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const un_op = o.air.instructions.items(.data)[inst].un_op; - const writer = o.writer(); - const inst_ty = o.air.typeOfIndex(inst); - const operand = try o.resolveInst(un_op); - const local = try o.allocLocal(inst_ty, .Const); + const un_op = f.air.instructions.items(.data)[inst].un_op; + const writer = f.object.writer(); + const inst_ty = f.air.typeOfIndex(inst); + const operand = try f.resolveInst(un_op); + const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = "); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll(";\n"); return local; } -fn airStore(o: *Object, inst: Air.Inst.Index) !CValue { +fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { // *a = b; - const bin_op = o.air.instructions.items(.data)[inst].bin_op; - const dest_ptr = try o.resolveInst(bin_op.lhs); - const src_val = try o.resolveInst(bin_op.rhs); + const bin_op = f.air.instructions.items(.data)[inst].bin_op; + const dest_ptr = try f.resolveInst(bin_op.lhs); + const src_val = try f.resolveInst(bin_op.rhs); - const writer = o.writer(); + const writer = f.object.writer(); switch (dest_ptr) { .local_ref => |i| { const dest: CValue = .{ .local = i }; - try o.writeCValue(writer, dest); + try f.writeCValue(writer, dest); try writer.writeAll(" = "); - try o.writeCValue(writer, src_val); + try f.writeCValue(writer, src_val); try writer.writeAll(";\n"); }, .decl_ref => |decl| { const dest: CValue = .{ .decl = decl }; - try o.writeCValue(writer, dest); + try f.writeCValue(writer, dest); try writer.writeAll(" = "); - try o.writeCValue(writer, src_val); + try f.writeCValue(writer, src_val); try writer.writeAll(";\n"); }, else => { try writer.writeAll("*"); - try o.writeCValue(writer, dest_ptr); + try f.writeCValue(writer, dest_ptr); try writer.writeAll(" = "); - try o.writeCValue(writer, src_val); + try f.writeCValue(writer, src_val); try writer.writeAll(";\n"); }, } @@ -1148,17 +1185,17 @@ fn airStore(o: *Object, inst: Air.Inst.Index) !CValue { } fn airWrapOp( - o: *Object, + f: *Function, inst: Air.Inst.Index, str_op: [*:0]const u8, fn_op: [*:0]const u8, ) !CValue { - if (o.liveness.isUnused(inst)) + if (f.liveness.isUnused(inst)) return CValue.none; - const bin_op = o.air.instructions.items(.data)[inst].bin_op; - const inst_ty = o.air.typeOfIndex(inst); - const int_info = inst_ty.intInfo(o.dg.module.getTarget()); + const bin_op = f.air.instructions.items(.data)[inst].bin_op; + const inst_ty = f.air.typeOfIndex(inst); + const int_info = inst_ty.intInfo(f.object.dg.module.getTarget()); const bits = int_info.bits; // if it's an unsigned int with non-arbitrary bit size then we can just add @@ -1168,12 +1205,12 @@ fn airWrapOp( else => false, }; if (ok_bits or inst_ty.tag() != .int_unsigned) { - return try airBinOp(o, inst, str_op); + return try airBinOp(f, inst, str_op); } } if (bits > 64) { - return o.dg.fail("TODO: C backend: airWrapOp for large integers", .{}); + return f.fail("TODO: C backend: airWrapOp for large integers", .{}); } var min_buf: [80]u8 = undefined; @@ -1220,11 +1257,11 @@ fn airWrapOp( }, }; - const lhs = try o.resolveInst(bin_op.lhs); - const rhs = try o.resolveInst(bin_op.rhs); - const w = o.writer(); + const lhs = try f.resolveInst(bin_op.lhs); + const rhs = try f.resolveInst(bin_op.rhs); + const w = f.object.writer(); - const ret = try o.allocLocal(inst_ty, .Mut); + const ret = try f.allocLocal(inst_ty, .Mut); try w.print(" = zig_{s}", .{fn_op}); switch (inst_ty.tag()) { @@ -1250,71 +1287,71 @@ fn airWrapOp( } try w.writeByte('('); - try o.writeCValue(w, lhs); + try f.writeCValue(w, lhs); try w.writeAll(", "); - try o.writeCValue(w, rhs); + try f.writeCValue(w, rhs); if (int_info.signedness == .signed) { try w.print(", {s}", .{min}); } try w.print(", {s});", .{max}); - try o.indent_writer.insertNewline(); + try f.object.indent_writer.insertNewline(); return ret; } -fn airNot(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const op = try o.resolveInst(ty_op.operand); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const op = try f.resolveInst(ty_op.operand); - const writer = o.writer(); - const inst_ty = o.air.typeOfIndex(inst); - const local = try o.allocLocal(inst_ty, .Const); + const writer = f.object.writer(); + const inst_ty = f.air.typeOfIndex(inst); + const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = "); if (inst_ty.zigTypeTag() == .Bool) try writer.writeAll("!") else try writer.writeAll("~"); - try o.writeCValue(writer, op); + try f.writeCValue(writer, op); try writer.writeAll(";\n"); return local; } -fn airBinOp(o: *Object, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue { - if (o.liveness.isUnused(inst)) +fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const bin_op = o.air.instructions.items(.data)[inst].bin_op; - const lhs = try o.resolveInst(bin_op.lhs); - const rhs = try o.resolveInst(bin_op.rhs); + const bin_op = f.air.instructions.items(.data)[inst].bin_op; + const lhs = try f.resolveInst(bin_op.lhs); + const rhs = try f.resolveInst(bin_op.rhs); - const writer = o.writer(); - const inst_ty = o.air.typeOfIndex(inst); - const local = try o.allocLocal(inst_ty, .Const); + const writer = f.object.writer(); + const inst_ty = f.air.typeOfIndex(inst); + const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = "); - try o.writeCValue(writer, lhs); + try f.writeCValue(writer, lhs); try writer.print("{s}", .{operator}); - try o.writeCValue(writer, rhs); + try f.writeCValue(writer, rhs); try writer.writeAll(";\n"); return local; } -fn airCall(o: *Object, inst: Air.Inst.Index) !CValue { - const pl_op = o.air.instructions.items(.data)[inst].pl_op; - const extra = o.air.extraData(Air.Call, pl_op.payload); - const args = @bitCast([]const Air.Inst.Ref, o.air.extra[extra.end..][0..extra.data.args_len]); - const fn_ty = o.air.typeOf(pl_op.operand); +fn airCall(f: *Function, inst: Air.Inst.Index) !CValue { + const pl_op = f.air.instructions.items(.data)[inst].pl_op; + const extra = f.air.extraData(Air.Call, pl_op.payload); + const args = @bitCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]); + const fn_ty = f.air.typeOf(pl_op.operand); const ret_ty = fn_ty.fnReturnType(); - const unused_result = o.liveness.isUnused(inst); - const writer = o.writer(); + const unused_result = f.liveness.isUnused(inst); + const writer = f.object.writer(); var result_local: CValue = .none; if (unused_result) { @@ -1322,11 +1359,11 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue { try writer.print("(void)", .{}); } } else { - result_local = try o.allocLocal(ret_ty, .Const); + result_local = try f.allocLocal(ret_ty, .Const); try writer.writeAll(" = "); } - if (o.air.value(pl_op.operand)) |func_val| { + if (f.air.value(pl_op.operand)) |func_val| { const fn_decl = if (func_val.castTag(.extern_fn)) |extern_fn| extern_fn.data else if (func_val.castTag(.function)) |func_payload| @@ -1336,8 +1373,8 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue { try writer.writeAll(mem.spanZ(fn_decl.name)); } else { - const callee = try o.resolveInst(pl_op.operand); - try o.writeCValue(writer, callee); + const callee = try f.resolveInst(pl_op.operand); + try f.writeCValue(writer, callee); } try writer.writeAll("("); @@ -1345,113 +1382,113 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue { if (i != 0) { try writer.writeAll(", "); } - if (o.air.value(arg)) |val| { - try o.dg.renderValue(writer, o.air.typeOf(arg), val); + if (f.air.value(arg)) |val| { + try f.object.dg.renderValue(writer, f.air.typeOf(arg), val); } else { - const val = try o.resolveInst(arg); - try o.writeCValue(writer, val); + const val = try f.resolveInst(arg); + try f.writeCValue(writer, val); } } try writer.writeAll(");\n"); return result_local; } -fn airDbgStmt(o: *Object, inst: Air.Inst.Index) !CValue { - const dbg_stmt = o.air.instructions.items(.data)[inst].dbg_stmt; - const writer = o.writer(); +fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { + const dbg_stmt = f.air.instructions.items(.data)[inst].dbg_stmt; + const writer = f.object.writer(); try writer.print("#line {d}\n", .{dbg_stmt.line + 1}); return CValue.none; } -fn airBlock(o: *Object, inst: Air.Inst.Index) !CValue { - const ty_pl = o.air.instructions.items(.data)[inst].ty_pl; - const extra = o.air.extraData(Air.Block, ty_pl.payload); - const body = o.air.extra[extra.end..][0..extra.data.body_len]; +fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue { + const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; + const extra = f.air.extraData(Air.Block, ty_pl.payload); + const body = f.air.extra[extra.end..][0..extra.data.body_len]; - const block_id: usize = o.next_block_index; - o.next_block_index += 1; - const writer = o.writer(); + const block_id: usize = f.next_block_index; + f.next_block_index += 1; + const writer = f.object.writer(); - const inst_ty = o.air.typeOfIndex(inst); - const result = if (inst_ty.tag() != .void and !o.liveness.isUnused(inst)) blk: { + const inst_ty = f.air.typeOfIndex(inst); + const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst)) blk: { // allocate a location for the result - const local = try o.allocLocal(inst_ty, .Mut); + const local = try f.allocLocal(inst_ty, .Mut); try writer.writeAll(";\n"); break :blk local; } else CValue{ .none = {} }; - try o.blocks.putNoClobber(o.gpa, inst, .{ + try f.blocks.putNoClobber(f.object.dg.gpa, inst, .{ .block_id = block_id, .result = result, }); - try genBody(o, body); - try o.indent_writer.insertNewline(); + try genBody(f, body); + try f.object.indent_writer.insertNewline(); // label must be followed by an expression, add an empty one. try writer.print("zig_block_{d}:;\n", .{block_id}); return result; } -fn airBr(o: *Object, inst: Air.Inst.Index) !CValue { - const branch = o.air.instructions.items(.data)[inst].br; - const block = o.blocks.get(branch.block_inst).?; +fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { + const branch = f.air.instructions.items(.data)[inst].br; + const block = f.blocks.get(branch.block_inst).?; const result = block.result; - const writer = o.writer(); + const writer = f.object.writer(); // If result is .none then the value of the block is unused. if (result != .none) { - const operand = try o.resolveInst(branch.operand); - try o.writeCValue(writer, result); + const operand = try f.resolveInst(branch.operand); + try f.writeCValue(writer, result); try writer.writeAll(" = "); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll(";\n"); } - try o.writer().print("goto zig_block_{d};\n", .{block.block_id}); + try f.object.writer().print("goto zig_block_{d};\n", .{block.block_id}); return CValue.none; } -fn airBitcast(o: *Object, inst: Air.Inst.Index) !CValue { - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const operand = try o.resolveInst(ty_op.operand); +fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const operand = try f.resolveInst(ty_op.operand); - const writer = o.writer(); - const inst_ty = o.air.typeOfIndex(inst); + const writer = f.object.writer(); + const inst_ty = f.air.typeOfIndex(inst); if (inst_ty.zigTypeTag() == .Pointer and - o.air.typeOf(ty_op.operand).zigTypeTag() == .Pointer) + f.air.typeOf(ty_op.operand).zigTypeTag() == .Pointer) { - const local = try o.allocLocal(inst_ty, .Const); + const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = ("); - try o.dg.renderType(writer, inst_ty); + try f.renderType(writer, inst_ty); try writer.writeAll(")"); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll(";\n"); return local; } - const local = try o.allocLocal(inst_ty, .Mut); + const local = try f.allocLocal(inst_ty, .Mut); try writer.writeAll(";\n"); try writer.writeAll("memcpy(&"); - try o.writeCValue(writer, local); + try f.writeCValue(writer, local); try writer.writeAll(", &"); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll(", sizeof "); - try o.writeCValue(writer, local); + try f.writeCValue(writer, local); try writer.writeAll(");\n"); return local; } -fn airBreakpoint(o: *Object) !CValue { - try o.writer().writeAll("zig_breakpoint();\n"); +fn airBreakpoint(f: *Function) !CValue { + try f.object.writer().writeAll("zig_breakpoint();\n"); return CValue.none; } -fn airFence(o: *Object, inst: Air.Inst.Index) !CValue { - const atomic_order = o.air.instructions.items(.data)[inst].fence; - const writer = o.writer(); +fn airFence(f: *Function, inst: Air.Inst.Index) !CValue { + const atomic_order = f.air.instructions.items(.data)[inst].fence; + const writer = f.object.writer(); try writer.writeAll("zig_fence("); try writeMemoryOrder(writer, atomic_order); @@ -1460,85 +1497,85 @@ fn airFence(o: *Object, inst: Air.Inst.Index) !CValue { return CValue.none; } -fn airUnreach(o: *Object) !CValue { - try o.writer().writeAll("zig_unreachable();\n"); +fn airUnreach(f: *Function) !CValue { + try f.object.writer().writeAll("zig_unreachable();\n"); return CValue.none; } -fn airLoop(o: *Object, inst: Air.Inst.Index) !CValue { - const ty_pl = o.air.instructions.items(.data)[inst].ty_pl; - const loop = o.air.extraData(Air.Block, ty_pl.payload); - const body = o.air.extra[loop.end..][0..loop.data.body_len]; - try o.writer().writeAll("while (true) "); - try genBody(o, body); - try o.indent_writer.insertNewline(); +fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue { + const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; + const loop = f.air.extraData(Air.Block, ty_pl.payload); + const body = f.air.extra[loop.end..][0..loop.data.body_len]; + try f.object.writer().writeAll("while (true) "); + try genBody(f, body); + try f.object.indent_writer.insertNewline(); return CValue.none; } -fn airCondBr(o: *Object, inst: Air.Inst.Index) !CValue { - const pl_op = o.air.instructions.items(.data)[inst].pl_op; - const cond = try o.resolveInst(pl_op.operand); - const extra = o.air.extraData(Air.CondBr, pl_op.payload); - const then_body = o.air.extra[extra.end..][0..extra.data.then_body_len]; - const else_body = o.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; - const writer = o.writer(); +fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { + const pl_op = f.air.instructions.items(.data)[inst].pl_op; + const cond = try f.resolveInst(pl_op.operand); + const extra = f.air.extraData(Air.CondBr, pl_op.payload); + const then_body = f.air.extra[extra.end..][0..extra.data.then_body_len]; + const else_body = f.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; + const writer = f.object.writer(); try writer.writeAll("if ("); - try o.writeCValue(writer, cond); + try f.writeCValue(writer, cond); try writer.writeAll(") "); - try genBody(o, then_body); + try genBody(f, then_body); try writer.writeAll(" else "); - try genBody(o, else_body); - try o.indent_writer.insertNewline(); + try genBody(f, else_body); + try f.object.indent_writer.insertNewline(); return CValue.none; } -fn airSwitchBr(o: *Object, inst: Air.Inst.Index) !CValue { - const pl_op = o.air.instructions.items(.data)[inst].pl_op; - const condition = try o.resolveInst(pl_op.operand); - const condition_ty = o.air.typeOf(pl_op.operand); - const switch_br = o.air.extraData(Air.SwitchBr, pl_op.payload); - const writer = o.writer(); +fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { + const pl_op = f.air.instructions.items(.data)[inst].pl_op; + const condition = try f.resolveInst(pl_op.operand); + const condition_ty = f.air.typeOf(pl_op.operand); + const switch_br = f.air.extraData(Air.SwitchBr, pl_op.payload); + const writer = f.object.writer(); try writer.writeAll("switch ("); - try o.writeCValue(writer, condition); + try f.writeCValue(writer, condition); try writer.writeAll(") {"); - o.indent_writer.pushIndent(); + f.object.indent_writer.pushIndent(); var extra_index: usize = switch_br.end; var case_i: u32 = 0; while (case_i < switch_br.data.cases_len) : (case_i += 1) { - const case = o.air.extraData(Air.SwitchBr.Case, extra_index); - const items = @bitCast([]const Air.Inst.Ref, o.air.extra[case.end..][0..case.data.items_len]); - const case_body = o.air.extra[case.end + items.len ..][0..case.data.body_len]; + const case = f.air.extraData(Air.SwitchBr.Case, extra_index); + const items = @bitCast([]const Air.Inst.Ref, f.air.extra[case.end..][0..case.data.items_len]); + const case_body = f.air.extra[case.end + items.len ..][0..case.data.body_len]; extra_index = case.end + case.data.items_len + case_body.len; for (items) |item| { - try o.indent_writer.insertNewline(); + try f.object.indent_writer.insertNewline(); try writer.writeAll("case "); - try o.dg.renderValue(writer, condition_ty, o.air.value(item).?); + try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?); try writer.writeAll(": "); } // The case body must be noreturn so we don't need to insert a break. - try genBody(o, case_body); + try genBody(f, case_body); } - const else_body = o.air.extra[extra_index..][0..switch_br.data.else_body_len]; - try o.indent_writer.insertNewline(); + const else_body = f.air.extra[extra_index..][0..switch_br.data.else_body_len]; + try f.object.indent_writer.insertNewline(); try writer.writeAll("default: "); - try genBody(o, else_body); - try o.indent_writer.insertNewline(); + try genBody(f, else_body); + try f.object.indent_writer.insertNewline(); - o.indent_writer.popIndent(); + f.object.indent_writer.popIndent(); try writer.writeAll("}\n"); return CValue.none; } -fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue { - const air_datas = o.air.instructions.items(.data); - const air_extra = o.air.extraData(Air.Asm, air_datas[inst].ty_pl.payload); - const zir = o.dg.decl.namespace.file_scope.zir; +fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { + const air_datas = f.air.instructions.items(.data); + const air_extra = f.air.extraData(Air.Asm, air_datas[inst].ty_pl.payload); + const zir = f.object.dg.decl.namespace.file_scope.zir; const extended = zir.instructions.items(.data)[air_extra.data.zir_index].extended; const zir_extra = zir.extraData(Zir.Inst.Asm, extended.operand); const asm_source = zir.nullTerminatedString(zir_extra.data.asm_source); @@ -1547,14 +1584,14 @@ fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue { const clobbers_len = @truncate(u5, extended.small >> 10); _ = clobbers_len; // TODO honor these const is_volatile = @truncate(u1, extended.small >> 15) != 0; - const outputs = @bitCast([]const Air.Inst.Ref, o.air.extra[air_extra.end..][0..outputs_len]); - const args = @bitCast([]const Air.Inst.Ref, o.air.extra[air_extra.end + outputs.len ..][0..args_len]); + const outputs = @bitCast([]const Air.Inst.Ref, f.air.extra[air_extra.end..][0..outputs_len]); + const args = @bitCast([]const Air.Inst.Ref, f.air.extra[air_extra.end + outputs.len ..][0..args_len]); if (outputs_len > 1) { - return o.dg.fail("TODO implement codegen for asm with more than 1 output", .{}); + return f.fail("TODO implement codegen for asm with more than 1 output", .{}); } - if (o.liveness.isUnused(inst) and !is_volatile) + if (f.liveness.isUnused(inst) and !is_volatile) return CValue.none; var extra_i: usize = zir_extra.end; @@ -1569,28 +1606,28 @@ fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue { }; const args_extra_begin = extra_i; - const writer = o.writer(); + const writer = f.object.writer(); for (args) |arg| { const input = zir.extraData(Zir.Inst.Asm.Input, extra_i); extra_i = input.end; const constraint = zir.nullTerminatedString(input.data.constraint); if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') { const reg = constraint[1 .. constraint.len - 1]; - const arg_c_value = try o.resolveInst(arg); + const arg_c_value = try f.resolveInst(arg); try writer.writeAll("register "); - try o.dg.renderType(writer, o.air.typeOf(arg)); + try f.renderType(writer, f.air.typeOf(arg)); try writer.print(" {s}_constant __asm__(\"{s}\") = ", .{ reg, reg }); - try o.writeCValue(writer, arg_c_value); + try f.writeCValue(writer, arg_c_value); try writer.writeAll(";\n"); } else { - return o.dg.fail("TODO non-explicit inline asm regs", .{}); + return f.fail("TODO non-explicit inline asm regs", .{}); } } const volatile_string: []const u8 = if (is_volatile) "volatile " else ""; try writer.print("__asm {s}(\"{s}\"", .{ volatile_string, asm_source }); if (output_constraint) |_| { - return o.dg.fail("TODO: CBE inline asm output", .{}); + return f.fail("TODO: CBE inline asm output", .{}); } if (args.len > 0) { if (output_constraint == null) { @@ -1616,30 +1653,30 @@ fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue { } try writer.writeAll(");\n"); - if (o.liveness.isUnused(inst)) + if (f.liveness.isUnused(inst)) return CValue.none; - return o.dg.fail("TODO: C backend: inline asm expression result used", .{}); + return f.fail("TODO: C backend: inline asm expression result used", .{}); } fn airIsNull( - o: *Object, + f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8, deref_suffix: [*:0]const u8, ) !CValue { - if (o.liveness.isUnused(inst)) + if (f.liveness.isUnused(inst)) return CValue.none; - const un_op = o.air.instructions.items(.data)[inst].un_op; - const writer = o.writer(); - const operand = try o.resolveInst(un_op); + const un_op = f.air.instructions.items(.data)[inst].un_op; + const writer = f.object.writer(); + const operand = try f.resolveInst(un_op); - const local = try o.allocLocal(Type.initTag(.bool), .Const); + const local = try f.allocLocal(Type.initTag(.bool), .Const); try writer.writeAll(" = ("); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); - if (o.air.typeOf(un_op).isPtrLikeOptional()) { + if (f.air.typeOf(un_op).isPtrLikeOptional()) { // operand is a regular pointer, test `operand !=/== NULL` try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator }); } else { @@ -1648,14 +1685,14 @@ fn airIsNull( return local; } -fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const writer = o.writer(); - const operand = try o.resolveInst(ty_op.operand); - const operand_ty = o.air.typeOf(ty_op.operand); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const writer = f.object.writer(); + const operand = try f.resolveInst(ty_op.operand); + const operand_ty = f.air.typeOf(ty_op.operand); const opt_ty = if (operand_ty.zigTypeTag() == .Pointer) operand_ty.elemType() @@ -1668,98 +1705,98 @@ fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue { return operand; } - const inst_ty = o.air.typeOfIndex(inst); + const inst_ty = f.air.typeOfIndex(inst); const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else "."; const maybe_addrof = if (inst_ty.zigTypeTag() == .Pointer) "&" else ""; - const local = try o.allocLocal(inst_ty, .Const); + const local = try f.allocLocal(inst_ty, .Const); try writer.print(" = {s}(", .{maybe_addrof}); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.print("){s}payload;\n", .{maybe_deref}); return local; } -fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) // TODO this @as is needed because of a stage1 bug return @as(CValue, CValue.none); - const ty_pl = o.air.instructions.items(.data)[inst].ty_pl; - const extra = o.air.extraData(Air.StructField, ty_pl.payload).data; - const struct_ptr = try o.resolveInst(extra.struct_operand); - const struct_ptr_ty = o.air.typeOf(extra.struct_operand); - return structFieldPtr(o, inst, struct_ptr_ty, struct_ptr, extra.field_index); + const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; + const extra = f.air.extraData(Air.StructField, ty_pl.payload).data; + const struct_ptr = try f.resolveInst(extra.struct_operand); + const struct_ptr_ty = f.air.typeOf(extra.struct_operand); + return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, extra.field_index); } -fn airStructFieldPtrIndex(o: *Object, inst: Air.Inst.Index, index: u8) !CValue { - if (o.liveness.isUnused(inst)) +fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue { + if (f.liveness.isUnused(inst)) // TODO this @as is needed because of a stage1 bug return @as(CValue, CValue.none); - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const struct_ptr = try o.resolveInst(ty_op.operand); - const struct_ptr_ty = o.air.typeOf(ty_op.operand); - return structFieldPtr(o, inst, struct_ptr_ty, struct_ptr, index); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const struct_ptr = try f.resolveInst(ty_op.operand); + const struct_ptr_ty = f.air.typeOf(ty_op.operand); + return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, index); } -fn structFieldPtr(o: *Object, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue { - const writer = o.writer(); +fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue { + const writer = f.object.writer(); const struct_obj = struct_ptr_ty.elemType().castTag(.@"struct").?.data; const field_name = struct_obj.fields.keys()[index]; - const inst_ty = o.air.typeOfIndex(inst); - const local = try o.allocLocal(inst_ty, .Const); + const inst_ty = f.air.typeOfIndex(inst); + const local = try f.allocLocal(inst_ty, .Const); switch (struct_ptr) { .local_ref => |i| { try writer.print(" = &t{d}.{};\n", .{ i, fmtIdent(field_name) }); }, else => { try writer.writeAll(" = &"); - try o.writeCValue(writer, struct_ptr); + try f.writeCValue(writer, struct_ptr); try writer.print("->{};\n", .{fmtIdent(field_name)}); }, } return local; } -fn airStructFieldVal(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const ty_pl = o.air.instructions.items(.data)[inst].ty_pl; - const extra = o.air.extraData(Air.StructField, ty_pl.payload).data; - const writer = o.writer(); - const struct_byval = try o.resolveInst(extra.struct_operand); - const struct_ty = o.air.typeOf(extra.struct_operand); + const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; + const extra = f.air.extraData(Air.StructField, ty_pl.payload).data; + const writer = f.object.writer(); + const struct_byval = try f.resolveInst(extra.struct_operand); + const struct_ty = f.air.typeOf(extra.struct_operand); const struct_obj = struct_ty.castTag(.@"struct").?.data; const field_name = struct_obj.fields.keys()[extra.field_index]; - const inst_ty = o.air.typeOfIndex(inst); - const local = try o.allocLocal(inst_ty, .Const); + const inst_ty = f.air.typeOfIndex(inst); + const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = "); - try o.writeCValue(writer, struct_byval); + try f.writeCValue(writer, struct_byval); try writer.print(".{};\n", .{fmtIdent(field_name)}); return local; } // *(E!T) -> E NOT *E -fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const inst_ty = o.air.typeOfIndex(inst); - const writer = o.writer(); - const operand = try o.resolveInst(ty_op.operand); - const operand_ty = o.air.typeOf(ty_op.operand); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const inst_ty = f.air.typeOfIndex(inst); + const writer = f.object.writer(); + const operand = try f.resolveInst(ty_op.operand); + const operand_ty = f.air.typeOf(ty_op.operand); const payload_ty = operand_ty.errorUnionPayload(); if (!payload_ty.hasCodeGenBits()) { if (operand_ty.zigTypeTag() == .Pointer) { - const local = try o.allocLocal(inst_ty, .Const); + const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = *"); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll(";\n"); return local; } else { @@ -1769,172 +1806,172 @@ fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue { const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else "."; - const local = try o.allocLocal(inst_ty, .Const); + const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = ("); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.print("){s}error;\n", .{maybe_deref}); return local; } -fn airUnwrapErrUnionPay(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const writer = o.writer(); - const operand = try o.resolveInst(ty_op.operand); - const operand_ty = o.air.typeOf(ty_op.operand); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const writer = f.object.writer(); + const operand = try f.resolveInst(ty_op.operand); + const operand_ty = f.air.typeOf(ty_op.operand); const payload_ty = operand_ty.errorUnionPayload(); if (!payload_ty.hasCodeGenBits()) { return CValue.none; } - const inst_ty = o.air.typeOfIndex(inst); + const inst_ty = f.air.typeOfIndex(inst); const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else "."; const maybe_addrof = if (inst_ty.zigTypeTag() == .Pointer) "&" else ""; - const local = try o.allocLocal(inst_ty, .Const); + const local = try f.allocLocal(inst_ty, .Const); try writer.print(" = {s}(", .{maybe_addrof}); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.print("){s}payload;\n", .{maybe_deref}); return local; } -fn airWrapOptional(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const writer = o.writer(); - const operand = try o.resolveInst(ty_op.operand); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const writer = f.object.writer(); + const operand = try f.resolveInst(ty_op.operand); - const inst_ty = o.air.typeOfIndex(inst); + const inst_ty = f.air.typeOfIndex(inst); if (inst_ty.isPtrLikeOptional()) { // the operand is just a regular pointer, no need to do anything special. return operand; } // .wrap_optional is used to convert non-optionals into optionals so it can never be null. - const local = try o.allocLocal(inst_ty, .Const); + const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = { .is_null = false, .payload ="); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll("};\n"); return local; } -fn airWrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const writer = o.writer(); - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const operand = try o.resolveInst(ty_op.operand); + const writer = f.object.writer(); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const operand = try f.resolveInst(ty_op.operand); - const inst_ty = o.air.typeOfIndex(inst); - const local = try o.allocLocal(inst_ty, .Const); + const inst_ty = f.air.typeOfIndex(inst); + const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = { .error = "); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll(" };\n"); return local; } -fn airWrapErrUnionPay(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const writer = o.writer(); - const operand = try o.resolveInst(ty_op.operand); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const writer = f.object.writer(); + const operand = try f.resolveInst(ty_op.operand); - const inst_ty = o.air.typeOfIndex(inst); - const local = try o.allocLocal(inst_ty, .Const); + const inst_ty = f.air.typeOfIndex(inst); + const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = { .error = 0, .payload = "); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll(" };\n"); return local; } fn airIsErr( - o: *Object, + f: *Function, inst: Air.Inst.Index, deref_prefix: [*:0]const u8, deref_suffix: [*:0]const u8, op_str: [*:0]const u8, ) !CValue { - if (o.liveness.isUnused(inst)) + if (f.liveness.isUnused(inst)) return CValue.none; - const un_op = o.air.instructions.items(.data)[inst].un_op; - const writer = o.writer(); - const operand = try o.resolveInst(un_op); - const operand_ty = o.air.typeOf(un_op); - const local = try o.allocLocal(Type.initTag(.bool), .Const); + const un_op = f.air.instructions.items(.data)[inst].un_op; + const writer = f.object.writer(); + const operand = try f.resolveInst(un_op); + const operand_ty = f.air.typeOf(un_op); + const local = try f.allocLocal(Type.initTag(.bool), .Const); const payload_ty = operand_ty.errorUnionPayload(); if (!payload_ty.hasCodeGenBits()) { try writer.print(" = {s}", .{deref_prefix}); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.print(" {s} 0;\n", .{op_str}); } else { try writer.writeAll(" = "); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.print("{s}error {s} 0;\n", .{ deref_suffix, op_str }); } return local; } -fn airArrayToSlice(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const inst_ty = o.air.typeOfIndex(inst); - const local = try o.allocLocal(inst_ty, .Const); - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const writer = o.writer(); - const operand = try o.resolveInst(ty_op.operand); - const array_len = o.air.typeOf(ty_op.operand).elemType().arrayLen(); + const inst_ty = f.air.typeOfIndex(inst); + const local = try f.allocLocal(inst_ty, .Const); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const writer = f.object.writer(); + const operand = try f.resolveInst(ty_op.operand); + const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen(); try writer.writeAll(" = { .ptr = "); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.print(", .len = {d} }};\n", .{array_len}); return local; } /// Emits a local variable with the result type and initializes it /// with the operand. -fn airSimpleCast(o: *Object, inst: Air.Inst.Index) !CValue { - if (o.liveness.isUnused(inst)) +fn airSimpleCast(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - const inst_ty = o.air.typeOfIndex(inst); - const local = try o.allocLocal(inst_ty, .Const); - const ty_op = o.air.instructions.items(.data)[inst].ty_op; - const writer = o.writer(); - const operand = try o.resolveInst(ty_op.operand); + const inst_ty = f.air.typeOfIndex(inst); + const local = try f.allocLocal(inst_ty, .Const); + const ty_op = f.air.instructions.items(.data)[inst].ty_op; + const writer = f.object.writer(); + const operand = try f.resolveInst(ty_op.operand); try writer.writeAll(" = "); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll(";\n"); return local; } -fn airCmpxchg(o: *Object, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue { - const ty_pl = o.air.instructions.items(.data)[inst].ty_pl; - const extra = o.air.extraData(Air.Cmpxchg, ty_pl.payload).data; - const inst_ty = o.air.typeOfIndex(inst); - const ptr = try o.resolveInst(extra.ptr); - const expected_value = try o.resolveInst(extra.expected_value); - const new_value = try o.resolveInst(extra.new_value); - const local = try o.allocLocal(inst_ty, .Const); - const writer = o.writer(); +fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue { + const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; + const extra = f.air.extraData(Air.Cmpxchg, ty_pl.payload).data; + const inst_ty = f.air.typeOfIndex(inst); + const ptr = try f.resolveInst(extra.ptr); + const expected_value = try f.resolveInst(extra.expected_value); + const new_value = try f.resolveInst(extra.new_value); + const local = try f.allocLocal(inst_ty, .Const); + const writer = f.object.writer(); try writer.print(" = zig_cmpxchg_{s}(", .{flavor}); - try o.writeCValue(writer, ptr); + try f.writeCValue(writer, ptr); try writer.writeAll(", "); - try o.writeCValue(writer, expected_value); + try f.writeCValue(writer, expected_value); try writer.writeAll(", "); - try o.writeCValue(writer, new_value); + try f.writeCValue(writer, new_value); try writer.writeAll(", "); try writeMemoryOrder(writer, extra.successOrder()); try writer.writeAll(", "); @@ -1944,19 +1981,19 @@ fn airCmpxchg(o: *Object, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue { return local; } -fn airAtomicRmw(o: *Object, inst: Air.Inst.Index) !CValue { - const pl_op = o.air.instructions.items(.data)[inst].pl_op; - const extra = o.air.extraData(Air.AtomicRmw, pl_op.payload).data; - const inst_ty = o.air.typeOfIndex(inst); - const ptr = try o.resolveInst(pl_op.operand); - const operand = try o.resolveInst(extra.operand); - const local = try o.allocLocal(inst_ty, .Const); - const writer = o.writer(); +fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { + const pl_op = f.air.instructions.items(.data)[inst].pl_op; + const extra = f.air.extraData(Air.AtomicRmw, pl_op.payload).data; + const inst_ty = f.air.typeOfIndex(inst); + const ptr = try f.resolveInst(pl_op.operand); + const operand = try f.resolveInst(extra.operand); + const local = try f.allocLocal(inst_ty, .Const); + const writer = f.object.writer(); try writer.print(" = zig_atomicrmw_{s}(", .{toAtomicRmwSuffix(extra.op())}); - try o.writeCValue(writer, ptr); + try f.writeCValue(writer, ptr); try writer.writeAll(", "); - try o.writeCValue(writer, operand); + try f.writeCValue(writer, operand); try writer.writeAll(", "); try writeMemoryOrder(writer, extra.ordering()); try writer.writeAll(");\n"); @@ -1964,15 +2001,15 @@ fn airAtomicRmw(o: *Object, inst: Air.Inst.Index) !CValue { return local; } -fn airAtomicLoad(o: *Object, inst: Air.Inst.Index) !CValue { - const atomic_load = o.air.instructions.items(.data)[inst].atomic_load; - const inst_ty = o.air.typeOfIndex(inst); - const ptr = try o.resolveInst(atomic_load.ptr); - const local = try o.allocLocal(inst_ty, .Const); - const writer = o.writer(); +fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { + const atomic_load = f.air.instructions.items(.data)[inst].atomic_load; + const inst_ty = f.air.typeOfIndex(inst); + const ptr = try f.resolveInst(atomic_load.ptr); + const local = try f.allocLocal(inst_ty, .Const); + const writer = f.object.writer(); try writer.writeAll(" = zig_atomic_load("); - try o.writeCValue(writer, ptr); + try f.writeCValue(writer, ptr); try writer.writeAll(", "); try writeMemoryOrder(writer, atomic_load.order); try writer.writeAll(");\n"); @@ -1980,18 +2017,18 @@ fn airAtomicLoad(o: *Object, inst: Air.Inst.Index) !CValue { return local; } -fn airAtomicStore(o: *Object, inst: Air.Inst.Index, order: [*:0]const u8) !CValue { - const bin_op = o.air.instructions.items(.data)[inst].bin_op; - const ptr = try o.resolveInst(bin_op.lhs); - const element = try o.resolveInst(bin_op.rhs); - const inst_ty = o.air.typeOfIndex(inst); - const local = try o.allocLocal(inst_ty, .Const); - const writer = o.writer(); +fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CValue { + const bin_op = f.air.instructions.items(.data)[inst].bin_op; + const ptr = try f.resolveInst(bin_op.lhs); + const element = try f.resolveInst(bin_op.rhs); + const inst_ty = f.air.typeOfIndex(inst); + const local = try f.allocLocal(inst_ty, .Const); + const writer = f.object.writer(); try writer.writeAll(" = zig_atomic_store("); - try o.writeCValue(writer, ptr); + try f.writeCValue(writer, ptr); try writer.writeAll(", "); - try o.writeCValue(writer, element); + try f.writeCValue(writer, element); try writer.print(", {s});\n", .{order}); return local; -- cgit v1.2.3