diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-12-01 18:14:54 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-12-04 15:57:40 -0700 |
| commit | 2a0efbee56b03d9deafaa7918433ea10b46305c9 (patch) | |
| tree | 29f2dd885e12a2acafacd821cbfdd0b2bb9f384b /src/codegen/c.zig | |
| parent | 46f4a97d051e630dfae75e3856c81ffd1c7811e3 (diff) | |
| download | zig-2a0efbee56b03d9deafaa7918433ea10b46305c9.tar.gz zig-2a0efbee56b03d9deafaa7918433ea10b46305c9.zip | |
Revert "cbe: reduce amount of temporary locals"
This reverts commit 15cc83e27ae8a1740d9b7e2ec14044903979a832.
Diffstat (limited to 'src/codegen/c.zig')
| -rw-r--r-- | src/codegen/c.zig | 291 |
1 files changed, 128 insertions, 163 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 6f48117af7..4737e3eefa 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -50,8 +50,6 @@ pub const CValue = union(enum) { /// Render these bytes literally. /// TODO make this a [*:0]const u8 to save memory bytes: []const u8, - /// Index of an instruction that should later be rendered inline. - inline_index: Air.Inst.Index, }; const BlockData = struct { @@ -81,7 +79,6 @@ const ValueRenderLocation = enum { FunctionArgument, Initializer, Other, - condition, }; const BuiltinInfo = enum { @@ -281,19 +278,6 @@ pub const Function = struct { return result; } - fn resolveInstNoInline(f: *Function, inst: Air.Inst.Ref) !CValue { - const operand = try f.resolveInst(inst); - if (operand != .inline_index) return operand; - - const inst_ty = f.air.typeOf(inst); - const writer = f.object.writer(); - const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = "); - try f.writeCValueInline(operand.inline_index); - try writer.writeAll(";\n"); - return local; - } - fn wantSafety(f: *Function) bool { return switch (f.object.dg.module.optimizeMode()) { .Debug, .ReleaseSafe => true, @@ -329,74 +313,10 @@ pub const Function = struct { .constant => |inst| { const ty = f.air.typeOf(inst); const val = f.air.value(inst).?; - try f.object.dg.renderValue(w, ty, val, location); - }, - .undef => |ty| try f.object.dg.renderValue(w, ty, Value.undef, location), - .inline_index => |node| { - if (location != .condition) try w.writeByte('('); - try f.writeCValueInline(node); - if (location != .condition) try w.writeByte(')'); - }, - else => try f.object.dg.writeCValue(w, c_value), - } - } - - const E = error{ OutOfMemory, AnalysisFail }; - - fn writeCValueInline(f: *Function, inst: Air.Inst.Index) E!void { - switch (f.air.instructions.items(.tag)[inst]) { - // zig fmt: off - // TODO use a different strategy for add, sub, mul, div - // that communicates to the optimizer that wrapping is UB. - .add => try airBinOp(f, inst, "+", "add", .None), - .sub => try airBinOp(f, inst, "-", "sub", .None), - .mul => try airBinOp(f, inst, "*", "mul", .None), - - .div_float => try airBinBuiltinCall(f, inst, "div", .None), - - .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None), - .rem => { - const bin_op = f.air.instructions.items(.data)[inst].bin_op; - const lhs_ty = f.air.typeOf(bin_op.lhs); - // For binary operations @TypeOf(lhs)==@TypeOf(rhs), - // so we only check one. - if (lhs_ty.isInt()) - try airBinOp(f, inst, "%", "rem", .None) - else - try airBinFloatOp(f, inst, "fmod"); + return f.object.dg.renderValue(w, ty, val, location); }, - .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None), - .mod => try airBinBuiltinCall(f, inst, "mod", .None), - - .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits), - .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits), - .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits), - - .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits), - .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits), - .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits), - .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits), - - .min => try airMinMax(f, inst, '<', "fmin"), - .max => try airMinMax(f, inst, '>', "fmax"), - - .cmp_gt => try airCmpOp(f, inst, ">", "gt"), - .cmp_gte => try airCmpOp(f, inst, ">=", "ge"), - .cmp_lt => try airCmpOp(f, inst, "<", "lt"), - .cmp_lte => try airCmpOp(f, inst, "<=", "le"), - - .cmp_eq => try airEquality(f, inst, "((", "==", "eq"), - .cmp_neq => try airEquality(f, inst, "!((", "!=", "ne"), - - .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None), - .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None), - .xor => try airBinOp(f, inst, "^", "xor", .None), - .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None), - .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits), - .shl_exact => try airBinOp(f, inst, "<<", "shl", .None), - .not => try airNot (f, inst), - else => unreachable, - // zig fmt: on + .undef => |ty| return f.object.dg.renderValue(w, ty, Value.undef, location), + else => return f.object.dg.writeCValue(w, c_value), } } @@ -2245,7 +2165,7 @@ pub const DeclGen = struct { fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void { switch (c_value) { - .none, .inline_index => unreachable, + .none => unreachable, .local => |i| return w.print("t{d}", .{i}), .local_ref => |i| return w.print("&t{d}", .{i}), .constant => unreachable, @@ -2264,7 +2184,7 @@ pub const DeclGen = struct { fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void { switch (c_value) { - .none, .inline_index => unreachable, + .none => unreachable, .local => |i| return w.print("(*t{d})", .{i}), .local_ref => |i| return w.print("t{d}", .{i}), .constant => unreachable, @@ -2294,7 +2214,7 @@ pub const DeclGen = struct { fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { switch (c_value) { - .none, .constant, .field, .undef, .inline_index => unreachable, + .none, .constant, .field, .undef => unreachable, .local, .arg, .decl, .identifier, .bytes => { try dg.writeCValue(writer, c_value); try writer.writeAll("->"); @@ -2633,26 +2553,37 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, .ptr_add => try airPtrAddSub(f, inst, '+'), .ptr_sub => try airPtrAddSub(f, inst, '-'), - .add => CValue{ .inline_index = inst }, - .sub => CValue{ .inline_index = inst }, - .mul => CValue{ .inline_index = inst }, + // TODO use a different strategy for add, sub, mul, div + // that communicates to the optimizer that wrapping is UB. + .add => try airBinOp(f, inst, "+", "add", .None), + .sub => try airBinOp(f, inst, "-", "sub", .None), + .mul => try airBinOp(f, inst, "*", "mul", .None), .neg => try airFloatNeg(f, inst), - .div_float => CValue{ .inline_index = inst }, + .div_float => try airBinBuiltinCall(f, inst, "div", .None), - .div_trunc, .div_exact => CValue{ .inline_index = inst }, - .rem => CValue{ .inline_index = inst }, - .div_floor => CValue{ .inline_index = inst }, - .mod => CValue{ .inline_index = inst }, + .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None), + .rem => blk: { + const bin_op = f.air.instructions.items(.data)[inst].bin_op; + const lhs_ty = f.air.typeOf(bin_op.lhs); + // For binary operations @TypeOf(lhs)==@TypeOf(rhs), + // so we only check one. + break :blk if (lhs_ty.isInt()) + try airBinOp(f, inst, "%", "rem", .None) + else + try airBinFloatOp(f, inst, "fmod"); + }, + .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None), + .mod => try airBinBuiltinCall(f, inst, "mod", .None), - .addwrap => CValue{ .inline_index = inst }, - .subwrap => CValue{ .inline_index = inst }, - .mulwrap => CValue{ .inline_index = inst }, + .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits), + .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits), + .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits), - .add_sat => CValue{ .inline_index = inst }, - .sub_sat => CValue{ .inline_index = inst }, - .mul_sat => CValue{ .inline_index = inst }, - .shl_sat => CValue{ .inline_index = inst }, + .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits), + .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits), + .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits), + .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits), .sqrt, .sin, @@ -2677,30 +2608,30 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, .mul_with_overflow => try airOverflow(f, inst, "mul", .Bits), .shl_with_overflow => try airOverflow(f, inst, "shl", .Bits), - .min => CValue{ .inline_index = inst }, - .max => CValue{ .inline_index = inst }, + .min => try airMinMax(f, inst, '<', "fmin"), + .max => try airMinMax(f, inst, '>', "fmax"), .slice => try airSlice(f, inst), - .cmp_gt => CValue{ .inline_index = inst }, - .cmp_gte => CValue{ .inline_index = inst }, - .cmp_lt => CValue{ .inline_index = inst }, - .cmp_lte => CValue{ .inline_index = inst }, + .cmp_gt => try airCmpOp(f, inst, ">", "gt"), + .cmp_gte => try airCmpOp(f, inst, ">=", "ge"), + .cmp_lt => try airCmpOp(f, inst, "<", "lt"), + .cmp_lte => try airCmpOp(f, inst, "<=", "le"), - .cmp_eq => CValue{ .inline_index = inst }, - .cmp_neq => CValue{ .inline_index = inst }, + .cmp_eq => try airEquality(f, inst, "((", "==", "eq"), + .cmp_neq => try airEquality(f, inst, "!((", "!=", "ne"), .cmp_vector => return f.fail("TODO: C backend: implement cmp_vector", .{}), .cmp_lt_errors_len => try airCmpLtErrorsLen(f, inst), // bool_and and bool_or are non-short-circuit operations - .bool_and, .bit_and => CValue{ .inline_index = inst }, - .bool_or, .bit_or => CValue{ .inline_index = inst }, - .xor => CValue{ .inline_index = inst }, - .shr, .shr_exact => CValue{ .inline_index = inst }, - .shl, => CValue{ .inline_index = inst }, - .shl_exact => CValue{ .inline_index = inst }, - .not => CValue{ .inline_index = inst }, + .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None), + .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None), + .xor => try airBinOp(f, inst, "^", "xor", .None), + .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None), + .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits), + .shl_exact => try airBinOp(f, inst, "<<", "shl", .None), + .not => try airNot (f, inst), .optional_payload => try airOptionalPayload(f, inst), .optional_payload_ptr => try airOptionalPayloadPtr(f, inst), @@ -3449,21 +3380,22 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: return local; } -fn airNot(f: *Function, inst: Air.Inst.Index) !void { +fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; + const ty_op = f.air.instructions.items(.data)[inst].ty_op; const op = try f.resolveInst(ty_op.operand); const writer = f.object.writer(); const inst_ty = f.air.typeOfIndex(inst); + const local = try f.allocLocal(inst_ty, .Const); - const target = f.object.dg.module.getTarget(); - if (inst_ty.bitSize(target) > 64) {} - - try writer.writeByte('('); - try f.renderTypecast(writer, inst_ty); - try writer.writeByte(')'); + try writer.writeAll(" = "); try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~'); try f.writeCValue(writer, op, .Other); + try writer.writeAll(";\n"); + + return local; } fn airBinOp( @@ -3472,54 +3404,62 @@ fn airBinOp( operator: []const u8, operation: []const u8, info: BuiltinInfo, -) !void { +) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; + const bin_op = f.air.instructions.items(.data)[inst].bin_op; const operand_ty = f.air.typeOf(bin_op.lhs); const target = f.object.dg.module.getTarget(); if ((operand_ty.isInt() and operand_ty.bitSize(target) > 64) or operand_ty.isRuntimeFloat()) - return airBinBuiltinCall(f, inst, operation, info); + return try airBinBuiltinCall(f, inst, operation, info); const inst_ty = f.air.typeOfIndex(inst); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); const writer = f.object.writer(); - try writer.writeByte('('); - try f.renderTypecast(writer, inst_ty); - try writer.writeAll(")("); + const local = try f.allocLocal(inst_ty, .Const); + + try writer.writeAll(" = "); try f.writeCValue(writer, lhs, .Other); try writer.writeByte(' '); try writer.writeAll(operator); try writer.writeByte(' '); try f.writeCValue(writer, rhs, .Other); - try writer.writeByte(')'); + try writer.writeAll(";\n"); + + return local; } -fn airCmpOp( - f: *Function, - inst: Air.Inst.Index, - operator: []const u8, - operation: []const u8, -) !void { +fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: []const u8) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; + const bin_op = f.air.instructions.items(.data)[inst].bin_op; const operand_ty = f.air.typeOf(bin_op.lhs); const target = f.object.dg.module.getTarget(); if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) - return airCmpBuiltinCall(f, inst, operator, "cmp"); + return try airCmpBuiltinCall(f, inst, operator, "cmp"); if (operand_ty.isRuntimeFloat()) - return airCmpBuiltinCall(f, inst, operator, operation); + return try airCmpBuiltinCall(f, inst, operator, operation); + const inst_ty = f.air.typeOfIndex(inst); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); const writer = f.object.writer(); + const local = try f.allocLocal(inst_ty, .Const); + + try writer.writeAll(" = "); try f.writeCValue(writer, lhs, .Other); try writer.writeByte(' '); try writer.writeAll(operator); try writer.writeByte(' '); try f.writeCValue(writer, rhs, .Other); + try writer.writeAll(";\n"); + + return local; } fn airEquality( @@ -3528,20 +3468,27 @@ fn airEquality( negate_prefix: []const u8, operator: []const u8, operation: []const u8, -) !void { +) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; + const bin_op = f.air.instructions.items(.data)[inst].bin_op; const operand_ty = f.air.typeOf(bin_op.lhs); const target = f.object.dg.module.getTarget(); if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) - return airCmpBuiltinCall(f, inst, operator, "cmp"); + return try airCmpBuiltinCall(f, inst, operator, "cmp"); if (operand_ty.isRuntimeFloat()) - return airCmpBuiltinCall(f, inst, operator, operation); + return try airCmpBuiltinCall(f, inst, operator, operation); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); const writer = f.object.writer(); + const inst_ty = f.air.typeOfIndex(inst); + const local = try f.allocLocal(inst_ty, .Const); + + try writer.writeAll(" = "); + if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) { // (A && B) || (C && (A == B)) // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload @@ -3558,8 +3505,9 @@ fn airEquality( try f.writeCValue(writer, lhs, .Other); try writer.writeAll(".is_null == "); try f.writeCValue(writer, rhs, .Other); - try writer.writeAll(".is_null))"); - return; + try writer.writeAll(".is_null));\n"); + + return local; } try f.writeCValue(writer, lhs, .Other); @@ -3567,6 +3515,9 @@ fn airEquality( try writer.writeAll(operator); try writer.writeByte(' '); try f.writeCValue(writer, rhs, .Other); + try writer.writeAll(";\n"); + + return local; } fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { @@ -3620,23 +3571,26 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { return local; } -fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !void { +fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; + const bin_op = f.air.instructions.items(.data)[inst].bin_op; const inst_ty = f.air.typeOfIndex(inst); const target = f.object.dg.module.getTarget(); if (inst_ty.isInt() and inst_ty.bitSize(target) > 64) - return airBinBuiltinCall(f, inst, operation[1..], .None); + return try airBinBuiltinCall(f, inst, operation[1..], .None); if (inst_ty.isRuntimeFloat()) - return airBinFloatOp(f, inst, operation); + return try airBinFloatOp(f, inst, operation); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); const writer = f.object.writer(); + const local = try f.allocLocal(inst_ty, .Const); // (lhs <> rhs) ? lhs : rhs - try writer.writeAll("("); + try writer.writeAll(" = ("); try f.writeCValue(writer, lhs, .Other); try writer.writeByte(' '); try writer.writeByte(operator); @@ -3646,6 +3600,9 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons try f.writeCValue(writer, lhs, .Other); try writer.writeAll(" : "); try f.writeCValue(writer, rhs, .Other); + try writer.writeAll(";\n"); + + return local; } fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { @@ -3961,7 +3918,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst) or !src_ty.hasRuntimeBits()) return CValue.none; const ty_op = f.air.instructions.items(.data)[inst].ty_op; - const operand = try f.resolveInstNoInline(ty_op.operand); + const operand = try f.resolveInst(ty_op.operand); const dest_ty = f.air.typeOf(ty_op.operand); const target = f.object.dg.module.getTarget(); @@ -4067,7 +4024,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue { const body = f.air.extra[loop.end..][0..loop.data.body_len]; const writer = f.object.writer(); try writer.writeAll("while ("); - try f.object.dg.renderValue(writer, Type.bool, Value.true, .condition); + try f.object.dg.renderValue(writer, Type.bool, Value.true, .Other); try writer.writeAll(") "); try genBody(f, body); try writer.writeByte('\n'); @@ -4083,7 +4040,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); try writer.writeAll("if ("); - try f.writeCValue(writer, cond, .condition); + try f.writeCValue(writer, cond, .Other); try writer.writeAll(") "); try genBody(f, then_body); try writer.writeAll(" else "); @@ -5174,12 +5131,16 @@ fn airBinBuiltinCall( inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo, -) !void { +) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; + + const inst_ty = f.air.typeOfIndex(inst); const bin_op = f.air.instructions.items(.data)[inst].bin_op; const operand_ty = f.air.typeOf(bin_op.lhs); + const local = try f.allocLocal(inst_ty, .Const); const writer = f.object.writer(); - try writer.writeAll("zig_"); + try writer.writeAll(" = zig_"); try writer.writeAll(operation); try writer.writeByte('_'); try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); @@ -5188,7 +5149,8 @@ fn airBinBuiltinCall( try writer.writeAll(", "); try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); try f.object.dg.renderBuiltinInfo(writer, operand_ty, info); - try writer.writeAll(")"); + try writer.writeAll(");\n"); + return local; } fn airCmpBuiltinCall( @@ -5196,12 +5158,16 @@ fn airCmpBuiltinCall( inst: Air.Inst.Index, operator: []const u8, operation: []const u8, -) !void { +) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; + + const inst_ty = f.air.typeOfIndex(inst); const bin_op = f.air.instructions.items(.data)[inst].bin_op; const operand_ty = f.air.typeOf(bin_op.lhs); + const local = try f.allocLocal(inst_ty, .Const); const writer = f.object.writer(); - try writer.writeAll("zig_"); + try writer.writeAll(" = zig_"); try writer.writeAll(operation); try writer.writeByte('_'); try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); @@ -5209,7 +5175,8 @@ fn airCmpBuiltinCall( try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument); try writer.writeAll(", "); try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); - try writer.print(") {s} {}", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) }); + try writer.print(") {s} {};\n", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) }); + return local; } fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue { @@ -5946,18 +5913,15 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal return local; } -fn airBinFloatOp( - f: *Function, - inst: Air.Inst.Index, - operation: []const u8, -) !void { +fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; const bin_op = f.air.instructions.items(.data)[inst].bin_op; const writer = f.object.writer(); const inst_ty = f.air.typeOfIndex(inst); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); - - try writer.writeAll("zig_libc_name_"); + const local = try f.allocLocal(inst_ty, .Const); + try writer.writeAll(" = zig_libc_name_"); try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); try writer.writeByte('('); try writer.writeAll(operation); @@ -5965,7 +5929,8 @@ fn airBinFloatOp( try f.writeCValue(writer, lhs, .FunctionArgument); try writer.writeAll(", "); try f.writeCValue(writer, rhs, .FunctionArgument); - try writer.writeAll(")"); + try writer.writeAll(");\n"); + return local; } fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |
