Commit 4fdac5f1c9

Jacob Young <jacobly0@users.noreply.github.com>
2022-10-20 05:18:46
cbe: fix C syntax when rendering initializers
1 parent 4765294
Changed files (1)
src
codegen
src/codegen/c.zig
@@ -63,6 +63,7 @@ const FormatTypeAsCIdentContext = struct {
 
 const ValueRenderLocation = enum {
     FunctionArgument,
+    Initializer,
     Other,
 };
 
@@ -256,7 +257,7 @@ pub const Function = struct {
                     0,
                 );
                 try writer.writeAll(" = ");
-                try f.object.dg.renderValue(writer, ty, val, .Other);
+                try f.object.dg.renderValue(writer, ty, val, .Initializer);
                 try writer.writeAll(";\n ");
                 return decl_c_value;
             },
@@ -297,13 +298,14 @@ pub const Function = struct {
         return local_value;
     }
 
-    fn writeCValue(f: *Function, w: anytype, c_value: CValue) !void {
+    fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !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, .Other);
+                return f.object.dg.renderValue(w, ty, val, location);
             },
+            .undef => |ty| return f.object.dg.renderValue(w, ty, Value.undef, location),
             else => return f.object.dg.writeCValue(w, c_value),
         }
     }
@@ -425,13 +427,17 @@ pub const DeclGen = struct {
         if (ty.isSlice()) {
             try writer.writeByte('(');
             try dg.renderTypecast(writer, ty);
-            try writer.writeAll("){");
+            try writer.writeAll("){ .ptr = ");
+
             var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-            try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Other);
-            try writer.writeAll(", ");
-            try writer.print("{d}", .{val.sliceLen(dg.module)});
-            try writer.writeByte('}');
-            return;
+            try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Initializer);
+
+            var len_pl: Value.Payload.U64 = .{
+                .base = .{ .tag = .int_u64 },
+                .data = val.sliceLen(dg.module),
+            };
+            const len_val = Value.initPayload(&len_pl.base);
+            return writer.print(", .len = {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)});
         }
 
         // We shouldn't cast C function pointers as this is UB (when you call
@@ -567,9 +573,13 @@ pub const DeclGen = struct {
                 },
                 .Pointer => switch (ty.ptrSize()) {
                     .Slice => {
-                        try writer.writeByte('(');
-                        try dg.renderTypecast(writer, ty);
-                        try writer.writeAll("){(");
+                        if (location != .Initializer) {
+                            try writer.writeByte('(');
+                            try dg.renderTypecast(writer, ty);
+                            try writer.writeByte(')');
+                        }
+
+                        try writer.writeAll("{(");
                         var buf: Type.SlicePtrFieldTypeBuffer = undefined;
                         const ptr_ty = ty.slicePtrFieldType(&buf);
                         try dg.renderTypecast(writer, ptr_ty);
@@ -593,69 +603,86 @@ pub const DeclGen = struct {
                         return dg.renderValue(writer, payload_ty, val, location);
                     }
 
-                    try writer.writeByte('(');
-                    try dg.renderTypecast(writer, ty);
-                    try writer.writeAll("){ .payload = ");
-                    try dg.renderValue(writer, payload_ty, val, location);
+                    if (location != .Initializer) {
+                        try writer.writeByte('(');
+                        try dg.renderTypecast(writer, ty);
+                        try writer.writeByte(')');
+                    }
+
+                    try writer.writeAll("{ .payload = ");
+                    try dg.renderValue(writer, payload_ty, val, .Initializer);
                     try writer.writeAll(", .is_null = ");
-                    try dg.renderValue(writer, Type.bool, val, location);
+                    try dg.renderValue(writer, Type.bool, val, .Initializer);
                     return writer.writeAll(" }");
                 },
                 .Struct => {
-                    try writer.writeByte('(');
-                    try dg.renderTypecast(writer, ty);
-                    try writer.writeAll("){");
+                    if (location != .Initializer) {
+                        try writer.writeByte('(');
+                        try dg.renderTypecast(writer, ty);
+                        try writer.writeByte(')');
+                    }
 
+                    try writer.writeByte('{');
                     var empty = true;
                     for (ty.structFields().values()) |field| {
                         if (!field.ty.hasRuntimeBits()) continue;
 
                         if (!empty) try writer.writeByte(',');
-                        try dg.renderValue(writer, field.ty, val, location);
+                        try dg.renderValue(writer, field.ty, val, .Initializer);
 
                         empty = false;
                     }
                     if (empty) try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)});
-
                     return writer.writeByte('}');
                 },
                 .Union => {
-                    try writer.writeByte('(');
-                    try dg.renderTypecast(writer, ty);
-                    try writer.writeAll("){");
+                    if (location != .Initializer) {
+                        try writer.writeByte('(');
+                        try dg.renderTypecast(writer, ty);
+                        try writer.writeByte(')');
+                    }
 
+                    try writer.writeByte('{');
                     if (ty.unionTagTypeSafety()) |tag_ty| {
-                        try writer.writeAll(".tag = ");
-                        try dg.renderValue(writer, tag_ty, val, location);
+                        try writer.writeAll(" .tag = ");
+                        try dg.renderValue(writer, tag_ty, val, .Initializer);
                         try writer.writeAll(", .payload = {");
                     }
                     for (ty.unionFields().values()) |field| {
                         if (!field.ty.hasRuntimeBits()) continue;
-                        try dg.renderValue(writer, field.ty, val, location);
+                        try dg.renderValue(writer, field.ty, val, .Initializer);
                         break;
                     } else try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)});
                     if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');
                     return writer.writeByte('}');
                 },
                 .ErrorUnion => {
-                    try writer.writeByte('(');
-                    try dg.renderTypecast(writer, ty);
-                    try writer.writeAll("){ .payload = ");
-                    try dg.renderValue(writer, ty.errorUnionPayload(), val, location);
+                    if (location != .Initializer) {
+                        try writer.writeByte('(');
+                        try dg.renderTypecast(writer, ty);
+                        try writer.writeByte(')');
+                    }
+
+                    try writer.writeAll("{ .payload = ");
+                    try dg.renderValue(writer, ty.errorUnionPayload(), val, .Initializer);
                     return writer.print(", .error = {x} }}", .{
                         try dg.fmtIntLiteral(ty.errorUnionSet(), val),
                     });
                 },
                 .Array => {
-                    try writer.writeByte('{');
+                    if (location != .Initializer) {
+                        try writer.writeByte('(');
+                        try dg.renderTypecast(writer, ty);
+                        try writer.writeByte(')');
+                    }
 
+                    try writer.writeByte('{');
                     const c_len = ty.arrayLenIncludingSentinel();
                     var index: usize = 0;
                     while (index < c_len) : (index += 1) {
                         if (index > 0) try writer.writeAll(", ");
-                        try dg.renderValue(writer, ty.childType(), val, location);
+                        try dg.renderValue(writer, ty.childType(), val, .Initializer);
                     }
-
                     return writer.writeByte('}');
                 },
                 .ComptimeInt,
@@ -696,21 +723,21 @@ pub const DeclGen = struct {
                         // just generate a bit cast (exactly like we do in airBitcast)
                         switch (ty.tag()) {
                             .f32 => {
-                                var bitcast_val_pl = Value.Payload.U64{
+                                var bitcast_pl = Value.Payload.U64{
                                     .base = .{ .tag = .int_u64 },
                                     .data = @bitCast(u32, val.toFloat(f32)),
                                 };
-                                const bitcast_val = Value.initPayload(&bitcast_val_pl.base);
+                                const bitcast_val = Value.initPayload(&bitcast_pl.base);
                                 return writer.print("zig_bitcast_f32_u32({x})", .{
                                     try dg.fmtIntLiteral(Type.u32, bitcast_val),
                                 });
                             },
                             .f64 => {
-                                var bitcast_val_pl = Value.Payload.U64{
+                                var bitcast_pl = Value.Payload.U64{
                                     .base = .{ .tag = .int_u64 },
                                     .data = @bitCast(u64, val.toFloat(f64)),
                                 };
-                                const bitcast_val = Value.initPayload(&bitcast_val_pl.base);
+                                const bitcast_val = Value.initPayload(&bitcast_pl.base);
                                 return writer.print("zig_bitcast_f64_u64({x})", .{
                                     try dg.fmtIntLiteral(Type.u64, bitcast_val),
                                 });
@@ -737,12 +764,16 @@ pub const DeclGen = struct {
                     const slice = val.castTag(.slice).?.data;
                     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
 
-                    try writer.writeByte('(');
-                    try dg.renderTypecast(writer, ty);
-                    try writer.writeAll("){");
-                    try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, location);
+                    if (location != .Initializer) {
+                        try writer.writeByte('(');
+                        try dg.renderTypecast(writer, ty);
+                        try writer.writeByte(')');
+                    }
+
+                    try writer.writeByte('{');
+                    try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, .Initializer);
                     try writer.writeAll(", ");
-                    try dg.renderValue(writer, Type.usize, slice.len, location);
+                    try dg.renderValue(writer, Type.usize, slice.len, .Initializer);
                     try writer.writeByte('}');
                 },
                 .function => {
@@ -768,13 +799,19 @@ pub const DeclGen = struct {
                 else => unreachable,
             },
             .Array => {
+                if (location == .FunctionArgument) {
+                    try writer.writeByte('(');
+                    try dg.renderTypecast(writer, ty);
+                    try writer.writeByte(')');
+                }
+
                 // First try specific tag representations for more efficiency.
                 switch (val.tag()) {
                     .undef, .empty_struct_value, .empty_array => {
                         try writer.writeByte('{');
                         const ai = ty.arrayInfo();
                         if (ai.sentinel) |s| {
-                            try dg.renderValue(writer, ai.elem_type, s, location);
+                            try dg.renderValue(writer, ai.elem_type, s, .Initializer);
                         } else {
                             try writer.writeByte('0');
                         }
@@ -786,23 +823,17 @@ pub const DeclGen = struct {
                         defer arena.deinit();
                         const arena_allocator = arena.allocator();
 
-                        if (location == .FunctionArgument) {
-                            try writer.writeByte('(');
-                            try dg.renderTypecast(writer, ty);
-                            try writer.writeByte(')');
-                        }
-
                         try writer.writeByte('{');
                         const ai = ty.arrayInfo();
                         var index: usize = 0;
                         while (index < ai.len) : (index += 1) {
                             if (index != 0) try writer.writeByte(',');
                             const elem_val = try val.elemValue(dg.module, arena_allocator, index);
-                            try dg.renderValue(writer, ai.elem_type, elem_val, .Other);
+                            try dg.renderValue(writer, ai.elem_type, elem_val, .Initializer);
                         }
                         if (ai.sentinel) |s| {
                             if (index != 0) try writer.writeByte(',');
-                            try dg.renderValue(writer, ai.elem_type, s, .Other);
+                            try dg.renderValue(writer, ai.elem_type, s, .Initializer);
                         }
                         try writer.writeByte('}');
                     },
@@ -823,19 +854,17 @@ pub const DeclGen = struct {
                     return dg.renderValue(writer, payload_ty, payload_val, location);
                 }
 
-                try writer.writeByte('(');
-                try dg.renderTypecast(writer, ty);
-                try writer.writeAll("){");
-                if (val.castTag(.opt_payload)) |pl| {
-                    const payload_val = pl.data;
-                    try writer.writeAll(" .payload = ");
-                    try dg.renderValue(writer, payload_ty, payload_val, location);
-                    try writer.writeAll(", .is_null = false }");
-                } else {
-                    try writer.writeAll(" .payload = ");
-                    try dg.renderValue(writer, payload_ty, Value.undef, location);
-                    try writer.writeAll(", .is_null = true }");
+                if (location != .Initializer) {
+                    try writer.writeByte('(');
+                    try dg.renderTypecast(writer, ty);
+                    try writer.writeByte(')');
                 }
+
+                const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else Value.undef;
+
+                try writer.writeAll("{ .payload = ");
+                try dg.renderValue(writer, payload_ty, payload_val, .Initializer);
+                try writer.print(", .is_null = {} }}", .{val.tag() == .null_value});
             },
             .ErrorSet => {
                 switch (val.tag()) {
@@ -861,23 +890,20 @@ pub const DeclGen = struct {
                     return dg.renderValue(writer, error_ty, err_val, location);
                 }
 
-                try writer.writeByte('(');
-                try dg.renderTypecast(writer, ty);
-                try writer.writeAll("){");
-                if (val.castTag(.eu_payload)) |pl| {
-                    const payload_val = pl.data;
-                    try writer.writeAll(" .payload = ");
-                    try dg.renderValue(writer, payload_ty, payload_val, location);
-                    try writer.print(", .error = {} }}", .{
-                        try dg.fmtIntLiteral(error_ty, Value.zero),
-                    });
-                } else {
-                    try writer.writeAll(" .payload = ");
-                    try dg.renderValue(writer, payload_ty, Value.undef, location);
-                    try writer.writeAll(", .error = ");
-                    try dg.renderValue(writer, error_ty, val, location);
-                    try writer.writeAll(" }");
+                if (location != .Initializer) {
+                    try writer.writeByte('(');
+                    try dg.renderTypecast(writer, ty);
+                    try writer.writeByte(')');
                 }
+
+                const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.undef;
+                const error_val = if (val.tag() == .eu_payload) Value.zero else val;
+
+                try writer.writeAll("{ .payload = ");
+                try dg.renderValue(writer, payload_ty, payload_val, .Initializer);
+                try writer.writeAll(", .error = ");
+                try dg.renderValue(writer, error_ty, error_val, .Initializer);
+                try writer.writeAll(" }");
             },
             .Enum => {
                 switch (val.tag()) {
@@ -927,36 +953,41 @@ pub const DeclGen = struct {
             .Struct => {
                 const field_vals = val.castTag(.aggregate).?.data;
 
-                try writer.writeByte('(');
-                try dg.renderTypecast(writer, ty);
-                try writer.writeAll("){");
+                if (location != .Initializer) {
+                    try writer.writeByte('(');
+                    try dg.renderTypecast(writer, ty);
+                    try writer.writeByte(')');
+                }
 
+                try writer.writeByte('{');
                 var empty = true;
                 for (field_vals) |field_val, field_index| {
                     const field_ty = ty.structFieldType(field_index);
                     if (!field_ty.hasRuntimeBits()) continue;
 
                     if (!empty) try writer.writeByte(',');
-                    try dg.renderValue(writer, field_ty, field_val, location);
+                    try dg.renderValue(writer, field_ty, field_val, .Initializer);
 
                     empty = false;
                 }
                 if (empty) try writer.print("{}", .{try dg.fmtIntLiteral(Type.u8, Value.zero)});
-
                 try writer.writeByte('}');
             },
             .Union => {
                 const union_obj = val.castTag(.@"union").?.data;
                 const layout = ty.unionGetLayout(target);
 
-                try writer.writeByte('(');
-                try dg.renderTypecast(writer, ty);
-                try writer.writeAll("){");
+                if (location != .Initializer) {
+                    try writer.writeByte('(');
+                    try dg.renderTypecast(writer, ty);
+                    try writer.writeByte(')');
+                }
 
+                try writer.writeByte('{');
                 if (ty.unionTagTypeSafety()) |tag_ty| {
                     if (layout.tag_size != 0) {
                         try writer.writeAll(".tag = ");
-                        try dg.renderValue(writer, tag_ty, union_obj.tag, location);
+                        try dg.renderValue(writer, tag_ty, union_obj.tag, .Initializer);
                         try writer.writeAll(", ");
                     }
                     try writer.writeAll(".payload = {");
@@ -967,11 +998,9 @@ pub const DeclGen = struct {
                 const field_name = ty.unionFields().keys()[index];
                 if (field_ty.hasRuntimeBits()) {
                     try writer.print(".{ } = ", .{fmtIdent(field_name)});
-                    try dg.renderValue(writer, field_ty, union_obj.val, location);
+                    try dg.renderValue(writer, field_ty, union_obj.val, .Initializer);
                 } else try writer.writeByte('0');
-                if (ty.unionTagTypeSafety()) |_| {
-                    try writer.writeByte('}');
-                }
+                if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');
                 try writer.writeByte('}');
             },
 
@@ -1029,7 +1058,7 @@ pub const DeclGen = struct {
                 try w.writeAll(", ");
             }
             const name = CValue{ .arg = index };
-            try dg.renderTypeAndName(w, param_type, name, .Mut, 0);
+            try dg.renderTypeAndName(w, param_type, name, .Const, 0);
             index += 1;
         }
 
@@ -1737,28 +1766,28 @@ pub const DeclGen = struct {
             defer dg.typedefs.allocator.free(name_z);
             const name_bytes = name_z[0 .. name_z.len + 1];
 
-            var tag_val_pl: Value.Payload.U32 = .{
+            var tag_pl: Value.Payload.U32 = .{
                 .base = .{ .tag = .enum_field_index },
                 .data = @intCast(u32, index),
             };
-            const tag_val = Value.initPayload(&tag_val_pl.base);
+            const tag_val = Value.initPayload(&tag_pl.base);
 
-            var int_val_pl: Value.Payload.U64 = undefined;
-            const int_val = tag_val.enumToInt(enum_ty, &int_val_pl);
+            var int_pl: Value.Payload.U64 = undefined;
+            const int_val = tag_val.enumToInt(enum_ty, &int_pl);
 
             var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };
             const name_ty = Type.initPayload(&name_ty_pl.base);
 
-            var name_val_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_bytes };
-            const name_val = Value.initPayload(&name_val_pl.base);
+            var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_bytes };
+            const name_val = Value.initPayload(&name_pl.base);
 
-            var len_val_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
-            const len_val = Value.initPayload(&len_val_pl.base);
+            var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
+            const len_val = Value.initPayload(&len_pl.base);
 
             try bw.print("  case {}: {{\n   static ", .{try dg.fmtIntLiteral(enum_ty, int_val)});
             try dg.renderTypeAndName(bw, name_ty, .{ .identifier = "name" }, .Const, 0);
             try buffer.appendSlice(" = ");
-            try dg.renderValue(bw, name_ty, name_val, .Other);
+            try dg.renderValue(bw, name_ty, name_val, .Initializer);
             try buffer.appendSlice(";\n   return (");
             try dg.renderTypecast(bw, name_slice_ty);
             try bw.print("){{{}, {}}};\n", .{
@@ -1893,8 +1922,8 @@ pub fn genErrDecls(o: *Object) !void {
     var max_name_len: usize = 0;
     for (o.dg.module.error_name_list.items) |name, value| {
         max_name_len = std.math.max(name.len, max_name_len);
-        var err_val_pl = Value.Payload.Error{ .data = .{ .name = name } };
-        try o.dg.renderValue(writer, Type.anyerror, Value.initPayload(&err_val_pl.base), .Other);
+        var err_pl = Value.Payload.Error{ .data = .{ .name = name } };
+        try o.dg.renderValue(writer, Type.anyerror, Value.initPayload(&err_pl.base), .Other);
         try writer.print(" = {d}u,\n", .{value});
     }
     o.indent_writer.popIndent();
@@ -1915,13 +1944,13 @@ pub fn genErrDecls(o: *Object) !void {
         var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };
         const name_ty = Type.initPayload(&name_ty_pl.base);
 
-        var name_val_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_z };
-        const name_val = Value.initPayload(&name_val_pl.base);
+        var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_z };
+        const name_val = Value.initPayload(&name_pl.base);
 
         try writer.writeAll("static ");
         try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0);
         try writer.writeAll(" = ");
-        try o.dg.renderValue(writer, name_ty, name_val, .Other);
+        try o.dg.renderValue(writer, name_ty, name_val, .Initializer);
         try writer.writeAll(";\n");
     }
 
@@ -1937,8 +1966,8 @@ pub fn genErrDecls(o: *Object) !void {
     for (o.dg.module.error_name_list.items) |name, value| {
         if (value != 0) try writer.writeByte(',');
 
-        var len_val_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
-        const len_val = Value.initPayload(&len_val_pl.base);
+        var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
+        const len_val = Value.initPayload(&len_pl.base);
 
         try writer.print("{{" ++ name_prefix ++ "_{}, {}}}", .{
             fmtIdent(name),
@@ -2031,7 +2060,7 @@ pub fn genDecl(o: *Object) !void {
         try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align");
         try w.writeAll(" = ");
         if (variable.init.tag() != .unreachable_value) {
-            try o.dg.renderValue(w, tv.ty, variable.init, .Other);
+            try o.dg.renderValue(w, tv.ty, variable.init, .Initializer);
         }
         try w.writeByte(';');
         try o.indent_writer.insertNewline();
@@ -2046,7 +2075,7 @@ pub fn genDecl(o: *Object) !void {
         try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align");
 
         try writer.writeAll(" = ");
-        try o.dg.renderValue(writer, tv.ty, tv.val, .Other);
+        try o.dg.renderValue(writer, tv.ty, tv.val, .Initializer);
         try writer.writeAll(";\n");
     }
 }
@@ -2099,15 +2128,15 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
             .unreach    => try airUnreach(f),
             .fence      => try airFence(f, inst),
 
-            .ptr_add => try airPtrAddSub(f, inst, " + "),
-            .ptr_sub => try airPtrAddSub(f, inst, " - "),
+            .ptr_add => try airPtrAddSub(f, inst, '+'),
+            .ptr_sub => try airPtrAddSub(f, 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, " + "),
-            .sub                   => try airBinOp (f, inst, " - "),
-            .mul                   => try airBinOp (f, inst, " * "),
-            .div_float, .div_exact => try airBinOp( f, inst, " / "),
+            .add                   => try airBinOp(f, inst, "+"),
+            .sub                   => try airBinOp(f, inst, "-"),
+            .mul                   => try airBinOp(f, inst, "*"),
+            .div_float, .div_exact => try airBinOp(f, inst, "/"),
 
             .rem => blk: {
                 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
@@ -2115,7 +2144,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
                 // For binary operations @TypeOf(lhs)==@TypeOf(rhs),
                 // so we only check one.
                 break :blk if (lhs_ty.isInt())
-                    try airBinOp(f, inst, " % ")
+                    try airBinOp(f, inst, "%")
                 else
                     try airBinFloatOp(f, inst, "fmod"); // yes, @rem() => fmod()
             },
@@ -2125,21 +2154,21 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
                 // For binary operations @TypeOf(lhs)==@TypeOf(rhs),
                 // so we only check one.
                 break :blk if (lhs_ty.isInt())
-                    try airBinOp(f, inst, " / ")
+                    try airBinOp(f, inst, "/")
                 else
                     try airBinOpBuiltinCall(f, inst, "div_trunc");
             },
             .div_floor => try airBinOpBuiltinCall(f, inst, "div_floor"),
             .mod       => try airBinOpBuiltinCall(f, inst, "mod"),
 
-            .addwrap => try airWrapOp(f, inst, " + ", "addw_"),
-            .subwrap => try airWrapOp(f, inst, " - ", "subw_"),
-            .mulwrap => try airWrapOp(f, inst, " * ", "mulw_"),
+            .addwrap => try airWrapOp(f, inst, "+", "add"),
+            .subwrap => try airWrapOp(f, inst, "-", "sub"),
+            .mulwrap => try airWrapOp(f, inst, "*", "mul"),
 
-            .add_sat => try airSatOp(f, inst, "adds_"),
-            .sub_sat => try airSatOp(f, inst, "subs_"),
-            .mul_sat => try airSatOp(f, inst, "muls_"),
-            .shl_sat => try airSatOp(f, inst, "shls_"),
+            .add_sat => try airSatOp(f, inst, "add"),
+            .sub_sat => try airSatOp(f, inst, "sub"),
+            .mul_sat => try airSatOp(f, inst, "mul"),
+            .shl_sat => try airSatOp(f, inst, "shl"),
 
             .neg => try airNeg(f, inst),
 
@@ -2161,20 +2190,20 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
 
             .mul_add => try airMulAdd(f, inst),
 
-            .add_with_overflow => try airOverflow(f, inst, "addo_", .range),
-            .sub_with_overflow => try airOverflow(f, inst, "subo_", .range),
-            .mul_with_overflow => try airOverflow(f, inst, "mulo_", .range),
-            .shl_with_overflow => try airOverflow(f, inst, "shlo_", .bits),
+            .add_with_overflow => try airOverflow(f, inst, "add", .range),
+            .sub_with_overflow => try airOverflow(f, inst, "sub", .range),
+            .mul_with_overflow => try airOverflow(f, inst, "mul", .range),
+            .shl_with_overflow => try airOverflow(f, inst, "shl", .bits),
 
-            .min => try airMinMax(f, inst, "<"),
-            .max => try airMinMax(f, inst, ">"),
+            .min => try airMinMax(f, inst, '<'),
+            .max => try airMinMax(f, inst, '>'),
 
             .slice => try airSlice(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_gt  => try airBinOp(f, inst, ">"),
+            .cmp_gte => try airBinOp(f, inst, ">="),
+            .cmp_lt  => try airBinOp(f, inst, "<"),
+            .cmp_lte => try airBinOp(f, inst, "<="),
 
             .cmp_eq  => try airEquality(f, inst, "((", "=="),
             .cmp_neq => try airEquality(f, inst, "!((", "!="),
@@ -2183,13 +2212,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
             .cmp_lt_errors_len => return f.fail("TODO: C backend: implement cmp_lt_errors_len", .{}),
 
             // bool_and and bool_or are non-short-circuit operations
-            .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, .shr_exact => try airBinOp(f, inst, " >> "),
-            .shl, .shl_exact => try airBinOp(f, inst, " << "),
+            .bool_and, .bit_and => try airBinOp(f, inst, "&"),
+            .bool_or,  .bit_or  => try airBinOp(f, inst, "|"),
+            .xor             => try airBinOp(f, inst, "^"),
+            .shr, .shr_exact => try airBinOp(f, inst, ">>"),
+            .shl, .shl_exact => try airBinOp(f, inst, "<<"),
             .not             => try airNot  (f, inst),
 
             .optional_payload         => try airOptionalPayload(f, inst),
@@ -2202,10 +2229,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
             .is_err_ptr      => try airIsErr(f, inst, true, "!="),
             .is_non_err_ptr  => try airIsErr(f, inst, true, "=="),
 
-            .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]"),
+            .is_null         => try airIsNull(f, inst, "==", false),
+            .is_non_null     => try airIsNull(f, inst, "!=", false),
+            .is_null_ptr     => try airIsNull(f, inst, "==", true),
+            .is_non_null_ptr => try airIsNull(f, inst, "!=", true),
 
             .alloc            => try airAlloc(f, inst),
             .ret_ptr          => try airRetPtr(f, inst),
@@ -2291,11 +2318,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
             .field_parent_ptr => try airFieldParentPtr(f, inst),
 
             .struct_field_val => try airStructFieldVal(f, inst),
-            .slice_ptr        => try airSliceField(f, inst, " = ", ".ptr;\n"),
-            .slice_len        => try airSliceField(f, inst, " = ", ".len;\n"),
+            .slice_ptr        => try airSliceField(f, inst, false, "ptr"),
+            .slice_len        => try airSliceField(f, inst, false, "len"),
 
-            .ptr_slice_len_ptr => try airSliceField(f, inst, " = &", "->len;\n"),
-            .ptr_slice_ptr_ptr => try airSliceField(f, inst, " = &", "->ptr;\n"),
+            .ptr_slice_len_ptr => try airSliceField(f, inst, true, "len"),
+            .ptr_slice_ptr_ptr => try airSliceField(f, inst, true, "ptr"),
 
             .ptr_elem_val       => try airPtrElemVal(f, inst),
             .ptr_elem_ptr       => try airPtrElemPtr(f, inst),
@@ -2303,8 +2330,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
             .slice_elem_ptr     => try airSliceElemPtr(f, inst),
             .array_elem_val     => try airArrayElemVal(f, inst),
 
-            .unwrap_errunion_payload     => try airUnwrapErrUnionPay(f, inst, ""),
-            .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"),
+            .unwrap_errunion_payload     => try airUnwrapErrUnionPay(f, inst, false),
+            .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, true),
             .unwrap_errunion_err         => try airUnwrapErrUnionErr(f, inst),
             .unwrap_errunion_err_ptr     => try airUnwrapErrUnionErr(f, inst),
             .wrap_errunion_payload       => try airWrapErrUnionPay(f, inst),
@@ -2355,7 +2382,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
     try writer.writeByte('}');
 }
 
-fn airSliceField(f: *Function, inst: Air.Inst.Index, prefix: []const u8, suffix: []const u8) !CValue {
+fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: []const u8) !CValue {
     if (f.liveness.isUnused(inst)) return CValue.none;
 
     const inst_ty = f.air.typeOfIndex(inst);
@@ -2363,9 +2390,12 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, prefix: []const u8, suffix:
     const operand = try f.resolveInst(ty_op.operand);
     const writer = f.object.writer();
     const local = try f.allocLocal(inst_ty, .Const);
-    try writer.writeAll(prefix);
-    try f.writeCValue(writer, operand);
-    try writer.writeAll(suffix);
+    try writer.writeAll(" = ");
+    if (is_ptr) try writer.writeByte('&');
+    try f.writeCValue(writer, operand, .Other);
+    try if (is_ptr) writer.writeAll("->") else writer.writeByte('.');
+    try writer.writeAll(field_name);
+    try writer.writeAll(";\n");
     return local;
 }
 
@@ -2379,9 +2409,9 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
     const writer = f.object.writer();
     const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
     try writer.writeAll(" = ");
-    try f.writeCValue(writer, ptr);
+    try f.writeCValue(writer, ptr, .Other);
     try writer.writeByte('[');
-    try f.writeCValue(writer, index);
+    try f.writeCValue(writer, index, .Other);
     try writer.writeAll("];\n");
     return local;
 }
@@ -2403,10 +2433,10 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
         // It's a pointer to an array, so we need to de-reference.
         try f.writeCValueDeref(writer, ptr);
     } else {
-        try f.writeCValue(writer, ptr);
+        try f.writeCValue(writer, ptr, .Other);
     }
     try writer.writeAll(")[");
-    try f.writeCValue(writer, index);
+    try f.writeCValue(writer, index, .Other);
     try writer.writeAll("];\n");
     return local;
 }
@@ -2421,9 +2451,9 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
     const writer = f.object.writer();
     const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
     try writer.writeAll(" = ");
-    try f.writeCValue(writer, slice);
+    try f.writeCValue(writer, slice, .Other);
     try writer.writeAll(".ptr[");
-    try f.writeCValue(writer, index);
+    try f.writeCValue(writer, index, .Other);
     try writer.writeAll("];\n");
     return local;
 }
@@ -2439,9 +2469,9 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
     const writer = f.object.writer();
     const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
     try writer.writeAll(" = &");
-    try f.writeCValue(writer, slice);
+    try f.writeCValue(writer, slice, .Other);
     try writer.writeAll(".ptr[");
-    try f.writeCValue(writer, index);
+    try f.writeCValue(writer, index, .Other);
     try writer.writeAll("];\n");
     return local;
 }
@@ -2455,9 +2485,9 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
     const writer = f.object.writer();
     const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
     try writer.writeAll(" = ");
-    try f.writeCValue(writer, array);
+    try f.writeCValue(writer, array, .Other);
     try writer.writeByte('[');
-    try f.writeCValue(writer, index);
+    try f.writeCValue(writer, index, .Other);
     try writer.writeAll("];\n");
     return local;
 }
@@ -2523,11 +2553,11 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
         // and thus we only need to know size/type information from the local type/dest.
         try writer.writeAll(";\n");
         try writer.writeAll("memcpy(");
-        try f.writeCValue(writer, local);
+        try f.writeCValue(writer, local, .FunctionArgument);
         try writer.writeAll(", ");
-        try f.writeCValue(writer, operand);
+        try f.writeCValue(writer, operand, .FunctionArgument);
         try writer.writeAll(", sizeof(");
-        try f.writeCValue(writer, local);
+        try f.renderTypecast(writer, inst_ty);
         try writer.writeAll("));\n");
     } else {
         try writer.writeAll(" = ");
@@ -2544,7 +2574,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
     if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
         const operand = try f.resolveInst(un_op);
         try writer.writeAll("return ");
-        try f.writeCValue(writer, operand);
+        try f.writeCValue(writer, operand, .Other);
         try writer.writeAll(";\n");
     } else if (ret_ty.isError()) {
         try writer.writeAll("return 0;");
@@ -2563,7 +2593,7 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {
     if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
         const ptr = try f.resolveInst(un_op);
         try writer.writeAll("return *");
-        try f.writeCValue(writer, ptr);
+        try f.writeCValue(writer, ptr, .Other);
         try writer.writeAll(";\n");
     } else if (ret_ty.isError()) {
         try writer.writeAll("return 0;\n");
@@ -2586,7 +2616,7 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
     try writer.writeAll(" = (");
     try f.renderTypecast(writer, inst_ty);
     try writer.writeByte(')');
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .Other);
     try writer.writeAll(";\n");
     return local;
 }
@@ -2603,32 +2633,44 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
     const dest_int_info = inst_ty.intInfo(target);
     const dest_bits = dest_int_info.bits;
 
-    try writer.writeAll(" = ");
+    try writer.writeAll(" = (");
+    try f.renderTypecast(writer, inst_ty);
+    try writer.writeByte(')');
 
     if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) {
-        try f.writeCValue(writer, operand);
+        try f.writeCValue(writer, operand, .Other);
         try writer.writeAll(";\n");
-        return local;
-    }
-
-    switch (dest_int_info.signedness) {
+    } else switch (dest_int_info.signedness) {
         .unsigned => {
-            try f.writeCValue(writer, operand);
-            const mask = (@as(u65, 1) << @intCast(u7, dest_bits)) - 1;
-            try writer.print(" & {d}ULL;\n", .{mask});
-            return local;
+            var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa);
+            defer arena.deinit();
+
+            const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 };
+            var stack align(@alignOf(expected_contents)) =
+                std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator());
+
+            const mask_val = try inst_ty.maxInt(stack.get(), target);
+
+            try writer.writeByte('(');
+            try f.writeCValue(writer, operand, .Other);
+            try writer.print(" & {x});\n", .{try f.fmtIntLiteral(inst_ty, mask_val)});
         },
         .signed => {
             const operand_ty = f.air.typeOf(ty_op.operand);
             const c_bits = toCIntBits(operand_ty.intInfo(target).bits) orelse
                 return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
-            const shift_rhs = c_bits - dest_bits;
-            try writer.print("(int{d}_t)((uint{d}_t)", .{ c_bits, c_bits });
-            try f.writeCValue(writer, operand);
-            try writer.print(" << {d}) >> {d};\n", .{ shift_rhs, shift_rhs });
-            return local;
+            var shift_pl = Value.Payload.U64{
+                .base = .{ .tag = .int_u64 },
+                .data = c_bits - dest_bits,
+            };
+            const shift_val = Value.initPayload(&shift_pl.base);
+
+            try writer.print("((int{d}_t)((uint{0d}_t)", .{c_bits});
+            try f.writeCValue(writer, operand, .Other);
+            try writer.print(" << {}) >> {0});\n", .{try f.fmtIntLiteral(Type.u8, shift_val)});
         },
     }
+    return local;
 }
 
 fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {
@@ -2640,18 +2682,18 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {
     const operand = try f.resolveInst(un_op);
     const local = try f.allocLocal(inst_ty, .Const);
     try writer.writeAll(" = ");
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .Other);
     try writer.writeAll(";\n");
     return local;
 }
 
-fn airStoreUndefined(f: *Function, dest_ptr: CValue) !CValue {
+fn airStoreUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue {
     if (f.wantSafety()) {
         const writer = f.object.writer();
         try writer.writeAll("memset(");
-        try f.writeCValue(writer, dest_ptr);
+        try f.writeCValue(writer, dest_ptr, .FunctionArgument);
         try writer.print(", {x}, sizeof(", .{try f.fmtIntLiteral(Type.u8, Value.undef)});
-        try f.writeCValueDeref(writer, dest_ptr);
+        try f.renderTypecast(writer, lhs_child_ty);
         try writer.writeAll("));\n");
     }
     return CValue.none;
@@ -2660,8 +2702,8 @@ fn airStoreUndefined(f: *Function, dest_ptr: CValue) !CValue {
 fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
     // *a = b;
     const bin_op = f.air.instructions.items(.data)[inst].bin_op;
-    const lhs_child_type = f.air.typeOf(bin_op.lhs).childType();
-    if (!lhs_child_type.hasRuntimeBitsIgnoreComptime()) return CValue.none;
+    const lhs_child_ty = f.air.typeOf(bin_op.lhs).childType();
+    if (!lhs_child_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;
 
     const dest_ptr = try f.resolveInst(bin_op.lhs);
     const src_val = try f.resolveInst(bin_op.rhs);
@@ -2671,14 +2713,14 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
     const src_val_is_undefined =
         if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false;
     if (src_val_is_undefined)
-        return try airStoreUndefined(f, dest_ptr);
+        return try airStoreUndefined(f, lhs_child_ty, dest_ptr);
 
     const writer = f.object.writer();
-    if (lhs_child_type.zigTypeTag() == .Array) {
+    if (lhs_child_ty.zigTypeTag() == .Array) {
         // 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).
         const rhs_type = f.air.typeOf(bin_op.rhs);
-        assert(rhs_type.eql(lhs_child_type, f.object.dg.module));
+        assert(rhs_type.eql(lhs_child_ty, f.object.dg.module));
 
         // If the source is a constant, writeCValue will emit a brace initialization
         // so work around this by initializing into new local.
@@ -2686,37 +2728,30 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
         const array_src = if (src_val == .constant) blk: {
             const new_local = try f.allocLocal(rhs_type, .Const);
             try writer.writeAll(" = ");
-            try f.writeCValue(writer, src_val);
-            try writer.writeByte(';');
-            try f.object.indent_writer.insertNewline();
+            try f.writeCValue(writer, src_val, .Initializer);
+            try writer.writeAll(";\n");
 
             break :blk new_local;
         } else src_val;
 
         try writer.writeAll("memcpy(");
-        try f.writeCValue(writer, dest_ptr);
+        try f.writeCValue(writer, dest_ptr, .FunctionArgument);
         try writer.writeAll(", ");
-        try f.writeCValue(writer, array_src);
+        try f.writeCValue(writer, array_src, .FunctionArgument);
         try writer.writeAll(", sizeof(");
-        try f.writeCValue(writer, array_src);
+        try f.renderTypecast(writer, lhs_child_ty);
         try writer.writeAll("));\n");
     } else {
         try f.writeCValueDeref(writer, dest_ptr);
         try writer.writeAll(" = ");
-        try f.writeCValue(writer, src_val);
+        try f.writeCValue(writer, src_val, .Other);
         try writer.writeAll(";\n");
     }
     return CValue.none;
 }
 
-fn airWrapOp(
-    f: *Function,
-    inst: Air.Inst.Index,
-    str_op: [*:0]const u8,
-    fn_op: [*:0]const u8,
-) !CValue {
-    if (f.liveness.isUnused(inst))
-        return CValue.none;
+fn airWrapOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, fn_name: []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);
@@ -2725,26 +2760,18 @@ fn airWrapOp(
     const bits = int_info.bits;
 
     // if it's an unsigned int with non-arbitrary bit size then we can just add
-    if (int_info.signedness == .unsigned) {
-        const ok_bits = switch (bits) {
-            8, 16, 32, 64, 128 => true,
-            else => false,
-        };
-        if (ok_bits or inst_ty.tag() != .int_unsigned) {
-            return try airBinOp(f, inst, str_op);
-        }
+    if (int_info.signedness == .unsigned and bits == toCIntBits(bits)) {
+        return try airBinOp(f, inst, operator);
     }
 
-    if (bits > 64) {
-        return f.fail("TODO: C backend: airWrapOp for large integers", .{});
-    }
+    if (bits > 64) return f.fail("TODO: C backend: airWrapOp for large integers", .{});
 
     const lhs = try f.resolveInst(bin_op.lhs);
     const rhs = try f.resolveInst(bin_op.rhs);
     const w = f.object.writer();
 
-    const ret = try f.allocLocal(inst_ty, .Mut);
-    try w.print(" = zig_{s}", .{fn_op});
+    const local = try f.allocLocal(inst_ty, .Mut);
+    try w.print(" = zig_{s}w_", .{fn_name});
 
     switch (inst_ty.tag()) {
         .isize => try w.writeAll("isize"),
@@ -2766,9 +2793,9 @@ fn airWrapOp(
     }
 
     try w.writeByte('(');
-    try f.writeCValue(w, lhs);
+    try f.writeCValue(w, lhs, .FunctionArgument);
     try w.writeAll(", ");
-    try f.writeCValue(w, rhs);
+    try f.writeCValue(w, rhs, .FunctionArgument);
     {
         var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa);
         defer arena.deinit();
@@ -2787,12 +2814,11 @@ fn airWrapOp(
     }
     try f.object.indent_writer.insertNewline();
 
-    return ret;
+    return local;
 }
 
-fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {
-    if (f.liveness.isUnused(inst))
-        return CValue.none;
+fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_name: []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);
@@ -2800,22 +2826,14 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {
     const int_info = inst_ty.intInfo(target);
     const bits = int_info.bits;
 
-    switch (bits) {
-        8, 16, 32, 64, 128 => {},
-        else => return f.object.dg.fail("TODO: C backend: airSatOp for non power of 2 integers", .{}),
-    }
-
-    // if it's an unsigned int with non-arbitrary bit size then we can just add
-    if (bits > 64) {
-        return f.object.dg.fail("TODO: C backend: airSatOp for large integers", .{});
-    }
+    if (bits > 64) return f.object.dg.fail("TODO: C backend: airSatOp for large integers", .{});
 
     const lhs = try f.resolveInst(bin_op.lhs);
     const rhs = try f.resolveInst(bin_op.rhs);
     const w = f.object.writer();
 
-    const ret = try f.allocLocal(inst_ty, .Mut);
-    try w.print(" = zig_{s}", .{fn_op});
+    const local = try f.allocLocal(inst_ty, .Mut);
+    try w.print(" = zig_{s}s_", .{fn_name});
 
     switch (inst_ty.tag()) {
         .isize => try w.writeAll("isize"),
@@ -2837,9 +2855,9 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {
     }
 
     try w.writeByte('(');
-    try f.writeCValue(w, lhs);
+    try f.writeCValue(w, lhs, .FunctionArgument);
     try w.writeAll(", ");
-    try f.writeCValue(w, rhs);
+    try f.writeCValue(w, rhs, .FunctionArgument);
     {
         var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa);
         defer arena.deinit();
@@ -2858,10 +2876,10 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {
     }
     try f.object.indent_writer.insertNewline();
 
-    return ret;
+    return local;
 }
 
-fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8, kind: enum { range, bits }) !CValue {
+fn airOverflow(f: *Function, inst: Air.Inst.Index, fn_name: []const u8, kind: enum { range, bits }) !CValue {
     if (f.liveness.isUnused(inst))
         return CValue.none;
 
@@ -2879,19 +2897,18 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8, kin
     const c_bits = toCIntBits(int_info.bits) orelse
         return f.fail("TODO: C backend: implement integer arithmetic larger than 128 bits", .{});
 
-    const ret = try f.allocLocal(inst_ty, .Mut);
-    try w.writeByte(';');
-    try f.object.indent_writer.insertNewline();
-    try f.writeCValue(w, ret);
+    const local = try f.allocLocal(inst_ty, .Mut);
+    try w.writeAll(";\n");
 
-    try w.print(".field_1 = zig_{s}{c}{d}(", .{
-        op_abbrev, signAbbrev(int_info.signedness), c_bits,
+    try f.writeCValue(w, local, .Other);
+    try w.print(".field_1 = zig_{s}o_{c}{d}(", .{
+        fn_name, signAbbrev(int_info.signedness), c_bits,
     });
-    try f.writeCValue(w, lhs);
+    try f.writeCValue(w, lhs, .FunctionArgument);
     try w.writeAll(", ");
-    try f.writeCValue(w, rhs);
+    try f.writeCValue(w, rhs, .FunctionArgument);
     try w.writeAll(", &");
-    try f.writeCValue(w, ret);
+    try f.writeCValue(w, local, .Other);
     try w.writeAll(".field_0, ");
     switch (kind) {
         .range => {
@@ -2916,7 +2933,7 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8, kin
             try w.print("{x});\n", .{try f.fmtIntLiteral(Type.u8, bits_val)});
         },
     }
-    return ret;
+    return local;
 }
 
 fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
@@ -2932,13 +2949,13 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
 
     try writer.writeAll(" = ");
     try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~');
-    try f.writeCValue(writer, op);
+    try f.writeCValue(writer, op, .Other);
     try writer.writeAll(";\n");
 
     return local;
 }
 
-fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {
+fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: []const u8) !CValue {
     if (f.liveness.isUnused(inst))
         return CValue.none;
 
@@ -2951,9 +2968,11 @@ fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue
     const local = try f.allocLocal(inst_ty, .Const);
 
     try writer.writeAll(" = ");
-    try f.writeCValue(writer, lhs);
-    try writer.print("{s}", .{operator});
-    try f.writeCValue(writer, rhs);
+    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;
@@ -2983,31 +3002,31 @@ fn airEquality(
         // A = lhs.is_null  ;  B = rhs.is_null  ;  C = rhs.payload == lhs.payload
 
         try writer.writeAll(negate_prefix);
-        try f.writeCValue(writer, lhs);
+        try f.writeCValue(writer, lhs, .Other);
         try writer.writeAll(".is_null && ");
-        try f.writeCValue(writer, rhs);
+        try f.writeCValue(writer, rhs, .Other);
         try writer.writeAll(".is_null) || (");
-        try f.writeCValue(writer, lhs);
+        try f.writeCValue(writer, lhs, .Other);
         try writer.writeAll(".payload == ");
-        try f.writeCValue(writer, rhs);
+        try f.writeCValue(writer, rhs, .Other);
         try writer.writeAll(".payload && ");
-        try f.writeCValue(writer, lhs);
+        try f.writeCValue(writer, lhs, .Other);
         try writer.writeAll(".is_null == ");
-        try f.writeCValue(writer, rhs);
+        try f.writeCValue(writer, rhs, .Other);
         try writer.writeAll(".is_null));\n");
 
         return local;
     }
 
-    try f.writeCValue(writer, lhs);
+    try f.writeCValue(writer, lhs, .Other);
     try writer.writeAll(eq_op_str);
-    try f.writeCValue(writer, rhs);
+    try f.writeCValue(writer, rhs, .Other);
     try writer.writeAll(";\n");
 
     return local;
 }
 
-fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {
+fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
     if (f.liveness.isUnused(inst)) return CValue.none;
 
     const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
@@ -3031,17 +3050,19 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CV
     try writer.writeAll(" = (");
     try f.renderTypecast(writer, inst_ty);
     try writer.writeAll(")(((uintptr_t)");
-    try f.writeCValue(writer, lhs);
-    try writer.print("){s}(", .{operator});
-    try f.writeCValue(writer, rhs);
+    try f.writeCValue(writer, lhs, .Other);
+    try writer.writeAll(") ");
+    try writer.writeByte(operator);
+    try writer.writeAll(" (");
+    try f.writeCValue(writer, rhs, .Other);
     try writer.writeAll("*sizeof(");
     try f.renderTypecast(writer, elem_ty);
-    try writer.print(")));\n", .{});
+    try writer.writeAll(")));\n");
 
     return local;
 }
 
-fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {
+fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
     if (f.liveness.isUnused(inst)) return CValue.none;
 
     const bin_op = f.air.instructions.items(.data)[inst].bin_op;
@@ -3054,13 +3075,15 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValu
 
     // (lhs <> rhs) ? lhs : rhs
     try writer.writeAll(" = (");
-    try f.writeCValue(writer, lhs);
-    try writer.print("{s}", .{operator});
-    try f.writeCValue(writer, rhs);
+    try f.writeCValue(writer, lhs, .Other);
+    try writer.writeByte(' ');
+    try writer.writeByte(operator);
+    try writer.writeByte(' ');
+    try f.writeCValue(writer, rhs, .Other);
     try writer.writeAll(") ? ");
-    try f.writeCValue(writer, lhs);
+    try f.writeCValue(writer, lhs, .Other);
     try writer.writeAll(" : ");
-    try f.writeCValue(writer, rhs);
+    try f.writeCValue(writer, rhs, .Other);
     try writer.writeAll(";\n");
 
     return local;
@@ -3082,9 +3105,9 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
     var buf: Type.SlicePtrFieldTypeBuffer = undefined;
     try f.renderTypecast(writer, inst_ty.slicePtrFieldType(&buf));
     try writer.writeByte(')');
-    try f.writeCValue(writer, ptr);
+    try f.writeCValue(writer, ptr, .Other);
     try writer.writeAll(", ");
-    try f.writeCValue(writer, len);
+    try f.writeCValue(writer, len, .Initializer);
     try writer.writeAll("};\n");
 
     return local;
@@ -3151,7 +3174,7 @@ fn airCall(
         }
         // Fall back to function pointer call.
         const callee = try f.resolveInst(pl_op.operand);
-        try f.writeCValue(writer, callee);
+        try f.writeCValue(writer, callee, .Other);
     }
 
     try writer.writeByte('(');
@@ -3171,12 +3194,7 @@ fn airCall(
             if (ty.isVolatilePtr()) try writer.writeAll(" volatile");
             try writer.writeAll(" *)");
         }
-        if (f.air.value(arg)) |val| {
-            try f.object.dg.renderValue(writer, f.air.typeOf(arg), val, .FunctionArgument);
-        } else {
-            const val = try f.resolveInst(arg);
-            try f.writeCValue(writer, val);
-        }
+        try f.writeCValue(writer, try f.resolveInst(arg), .FunctionArgument);
         args_written += 1;
     }
     try writer.writeAll(");\n");
@@ -3286,18 +3304,18 @@ fn lowerTry(
                 } else {
                     try writer.writeAll("if(");
                 }
-                try f.writeCValue(writer, err_union);
+                try f.writeCValue(writer, err_union, .Other);
                 try writer.writeByte(')');
                 break :err;
             }
             if (operand_is_ptr or isByRef(err_union_ty)) {
                 try writer.writeAll("if(");
-                try f.writeCValue(writer, err_union);
+                try f.writeCValue(writer, err_union, .Other);
                 try writer.writeAll("->error)");
                 break :err;
             }
             try writer.writeAll("if(");
-            try f.writeCValue(writer, err_union);
+            try f.writeCValue(writer, err_union, .Other);
             try writer.writeAll(".error)");
         }
 
@@ -3318,20 +3336,20 @@ fn lowerTry(
     if (is_array) {
         try writer.writeAll(";\n");
         try writer.writeAll("memcpy(");
-        try f.writeCValue(writer, local);
+        try f.writeCValue(writer, local, .FunctionArgument);
         try writer.writeAll(", ");
-        try f.writeCValue(writer, err_union);
+        try f.writeCValue(writer, err_union, .Other);
         try writer.writeAll(".payload, sizeof(");
-        try f.writeCValue(writer, local);
+        try f.renderTypecast(writer, payload_ty);
         try writer.writeAll("));\n");
     } else {
         if (operand_is_ptr or isByRef(payload_ty)) {
             try writer.writeAll(" = &");
-            try f.writeCValue(writer, err_union);
+            try f.writeCValue(writer, err_union, .Other);
             try writer.writeAll("->payload;\n");
         } else {
             try writer.writeAll(" = ");
-            try f.writeCValue(writer, err_union);
+            try f.writeCValue(writer, err_union, .Other);
             try writer.writeAll(".payload;\n");
         }
     }
@@ -3347,9 +3365,9 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
     // If result is .none then the value of the block is unused.
     if (result != .none) {
         const operand = try f.resolveInst(branch.operand);
-        try f.writeCValue(writer, result);
+        try f.writeCValue(writer, result, .Other);
         try writer.writeAll(" = ");
-        try f.writeCValue(writer, operand);
+        try f.writeCValue(writer, operand, .Other);
         try writer.writeAll(";\n");
     }
 
@@ -3374,7 +3392,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
         try f.renderTypecast(writer, inst_ty);
 
         try writer.writeByte(')');
-        try f.writeCValue(writer, operand);
+        try f.writeCValue(writer, operand, .Other);
         try writer.writeAll(";\n");
         return local;
     }
@@ -3383,11 +3401,11 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
     try writer.writeAll(";\n");
 
     try writer.writeAll("memcpy(&");
-    try f.writeCValue(writer, local);
+    try f.writeCValue(writer, local, .Other);
     try writer.writeAll(", &");
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .Other);
     try writer.writeAll(", sizeof(");
-    try f.writeCValue(writer, local);
+    try f.renderTypecast(writer, inst_ty);
     try writer.writeAll("));\n");
 
     return local;
@@ -3456,7 +3474,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
     const writer = f.object.writer();
 
     try writer.writeAll("if (");
-    try f.writeCValue(writer, cond);
+    try f.writeCValue(writer, cond, .Other);
     try writer.writeAll(") ");
     try genBody(f, then_body);
     try writer.writeAll(" else ");
@@ -3475,7 +3493,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
 
     try writer.writeAll("switch (");
     if (condition_ty.tag() == .bool) try writer.writeAll("(int)");
-    try f.writeCValue(writer, condition);
+    try f.writeCValue(writer, condition, .Other);
     try writer.writeAll(") {");
     f.object.indent_writer.pushIndent();
 
@@ -3527,7 +3545,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
         const local = try f.allocLocal(inst_ty, .Mut);
         if (f.wantSafety()) {
             try writer.writeAll(" = ");
-            try f.writeCValue(writer, .{ .undef = inst_ty });
+            try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer);
         }
         try writer.writeAll(";\n");
         break :local local;
@@ -3555,7 +3573,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
             try writer.writeAll("\")");
             if (f.wantSafety()) {
                 try writer.writeAll(" = ");
-                try f.writeCValue(writer, .{ .undef = output_ty });
+                try f.writeCValue(writer, .{ .undef = output_ty }, .Initializer);
             }
             try writer.writeAll(";\n");
         } else if (constraint.len < 2 or constraint[0] != '=') {
@@ -3581,7 +3599,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
             try writer.writeAll(" __asm(\"");
             try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);
             try writer.writeAll("\") = ");
-            try f.writeCValue(writer, try f.resolveInst(input));
+            try f.writeCValue(writer, try f.resolveInst(input), .Initializer);
             try writer.writeAll(";\n");
         } else if (constraint.len >= 1 and std.mem.indexOfScalar(u8, "=+&%", constraint[0]) == null) {
             const input_val = try f.resolveInst(input);
@@ -3590,7 +3608,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
                     .local = input_locals_begin + index,
                 }, .Const, 0);
                 try writer.writeAll(" = ");
-                try f.writeCValue(writer, input_val);
+                try f.writeCValue(writer, input_val, .Initializer);
                 try writer.writeAll(";\n");
             }
         } else {
@@ -3626,7 +3644,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
         try writer.writeByte(' ');
         if (constraint[1] == '{') {
             try writer.print("{s}(", .{fmtStringLiteral("=r")});
-            try f.writeCValue(writer, .{ .local = output_locals_begin + index });
+            try f.writeCValue(writer, .{ .local = output_locals_begin + index }, .Other);
         } else {
             try writer.print("{s}(", .{fmtStringLiteral(constraint)});
             try f.writeCValueDeref(writer, try f.resolveInst(output));
@@ -3646,13 +3664,14 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
         try writer.writeByte(' ');
         if (constraint[0] == '{') {
             try writer.print("{s}(", .{fmtStringLiteral("r")});
-            try f.writeCValue(writer, .{ .local = input_locals_begin + index });
+            try f.writeCValue(writer, .{ .local = input_locals_begin + index }, .Other);
         } else {
             const input_val = try f.resolveInst(input);
             try writer.print("{s}(", .{fmtStringLiteral(constraint)});
-            try f.writeCValue(writer, if (input_val == .constant) CValue{
-                .local = input_locals_begin + index,
-            } else input_val);
+            try f.writeCValue(writer, if (input_val == .constant)
+                CValue{ .local = input_locals_begin + index }
+            else
+                input_val, .Other);
         }
         try writer.writeByte(')');
     }
@@ -3683,11 +3702,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
         extra_i += (constraint.len + name.len + (2 + 3)) / 4;
 
         if (constraint[1] == '{') {
-            try f.writeCValueDeref(writer, if (output == .none) CValue{
-                .local_ref = local.local,
-            } else try f.resolveInst(output));
+            try f.writeCValueDeref(writer, if (output == .none)
+                CValue{ .local_ref = local.local }
+            else
+                try f.resolveInst(output));
             try writer.writeAll(" = ");
-            try f.writeCValue(writer, .{ .local = output_locals_begin + index });
+            try f.writeCValue(writer, .{ .local = output_locals_begin + index }, .Other);
             try writer.writeAll(";\n");
         }
     }
@@ -3698,8 +3718,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
 fn airIsNull(
     f: *Function,
     inst: Air.Inst.Index,
-    operator: [*:0]const u8,
-    deref_suffix: [*:0]const u8,
+    operator: []const u8,
+    is_ptr: bool,
 ) !CValue {
     if (f.liveness.isUnused(inst))
         return CValue.none;
@@ -3709,25 +3729,23 @@ fn airIsNull(
     const operand = try f.resolveInst(un_op);
 
     const local = try f.allocLocal(Type.initTag(.bool), .Const);
-    try writer.writeAll(" = (");
-    try f.writeCValue(writer, operand);
+    try writer.writeAll(" = ");
+    try if (is_ptr) f.writeCValueDeref(writer, operand) else f.writeCValue(writer, operand, .Other);
 
-    const ty = f.air.typeOf(un_op);
-    var opt_buf: Type.Payload.ElemType = undefined;
-    const payload_ty = if (deref_suffix[0] != 0)
-        ty.childType().optionalChild(&opt_buf)
-    else
-        ty.optionalChild(&opt_buf);
+    const operand_ty = f.air.typeOf(un_op);
+    const optional_ty = if (is_ptr) operand_ty.childType() else operand_ty;
+    var payload_buf: Type.Payload.ElemType = undefined;
+    const payload_ty = optional_ty.optionalChild(&payload_buf);
 
     if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
-        try writer.print("){s} {s} true;\n", .{ deref_suffix, operator });
-    } else if (ty.isPtrLikeOptional()) {
+        try writer.print(" {s} true;\n", .{operator});
+    } else if (operand_ty.isPtrLikeOptional()) {
         // operand is a regular pointer, test `operand !=/== NULL`
-        try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator });
+        try writer.print(" {s} NULL;\n", .{operator});
     } else if (payload_ty.zigTypeTag() == .ErrorSet) {
-        try writer.print("){s} {s} 0;\n", .{ deref_suffix, operator });
+        try writer.print(" {s} 0;\n", .{operator});
     } else {
-        try writer.print("){s}.is_null {s} true;\n", .{ deref_suffix, operator });
+        try writer.print(".is_null {s} true;\n", .{operator});
     }
     return local;
 }
@@ -3754,7 +3772,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
     const inst_ty = f.air.typeOfIndex(inst);
     const local = try f.allocLocal(inst_ty, .Const);
     try writer.writeAll(" = (");
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .Other);
     try writer.writeAll(").payload;\n");
     return local;
 }
@@ -3781,7 +3799,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
 
     const local = try f.allocLocal(inst_ty, .Const);
     try writer.writeAll(" = &(");
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .Other);
     try writer.writeAll(")->payload;\n");
     return local;
 }
@@ -3882,7 +3900,7 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
         try writer.writeAll(" = (");
         try f.renderTypecast(writer, inst_ty);
         try writer.writeByte(')');
-        try f.writeCValue(writer, struct_ptr);
+        try f.writeCValue(writer, struct_ptr, .Other);
         try writer.writeAll(";\n");
     }
     return local;
@@ -3920,15 +3938,15 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
     if (is_array) {
         try writer.writeAll(";\n");
         try writer.writeAll("memcpy(");
-        try f.writeCValue(writer, local);
+        try f.writeCValue(writer, local, .FunctionArgument);
         try writer.writeAll(", ");
-        try f.writeCValue(writer, struct_byval);
+        try f.writeCValue(writer, struct_byval, .Other);
         try writer.print(".{s}{ }, sizeof(", .{ payload, fmtIdent(field_name) });
-        try f.writeCValue(writer, local);
+        try f.renderTypecast(writer, inst_ty);
         try writer.writeAll("));\n");
     } else {
         try writer.writeAll(" = ");
-        try f.writeCValue(writer, struct_byval);
+        try f.writeCValue(writer, struct_byval, .Other);
         try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) });
     }
     return local;
@@ -3956,7 +3974,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
         }
         const local = try f.allocLocal(inst_ty, .Const);
         try writer.writeAll(" = *");
-        try f.writeCValue(writer, operand);
+        try f.writeCValue(writer, operand, .Other);
         try writer.writeAll(";\n");
         return local;
     }
@@ -3972,13 +3990,13 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
     if (operand_ty.zigTypeTag() == .Pointer) {
         try f.writeCValueDeref(writer, operand);
     } else {
-        try f.writeCValue(writer, operand);
+        try f.writeCValue(writer, operand, .Other);
     }
     try writer.writeAll(".error;\n");
     return local;
 }
 
-fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: [*:0]const u8) !CValue {
+fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
     if (f.liveness.isUnused(inst))
         return CValue.none;
 
@@ -3994,13 +4012,15 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: [*:0]c
     }
 
     const inst_ty = f.air.typeOfIndex(inst);
-    const maybe_deref = if (operand_is_ptr) "->" else ".";
 
     const local = try f.allocLocal(inst_ty, .Const);
-    try writer.print(" = {s}(", .{maybe_addrof});
-    try f.writeCValue(writer, operand);
-
-    try writer.print("){s}payload;\n", .{maybe_deref});
+    try writer.writeAll(" = ");
+    if (is_ptr) try writer.writeByte('&');
+    try writer.writeByte('(');
+    try f.writeCValue(writer, operand, .Other);
+    try writer.writeByte(')');
+    try if (operand_is_ptr) writer.writeAll("->") else writer.writeByte('.');
+    try writer.writeAll("payload;\n");
     return local;
 }
 
@@ -4020,7 +4040,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
     // .wrap_optional is used to convert non-optionals into optionals so it can never be null.
     const local = try f.allocLocal(inst_ty, .Const);
     try writer.writeAll(" = { .payload = ");
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .Initializer);
     try writer.writeAll(", .is_null = false };\n");
     return local;
 }
@@ -4039,9 +4059,9 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
 
     const local = try f.allocLocal(err_un_ty, .Const);
     try writer.writeAll(" = { .payload = ");
-    try f.writeCValue(writer, .{ .undef = payload_ty });
+    try f.writeCValue(writer, .{ .undef = payload_ty }, .Initializer);
     try writer.writeAll(", .error = ");
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .Initializer);
     try writer.writeAll(" };\n");
     return local;
 }
@@ -4104,33 +4124,29 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
 
     const inst_ty = f.air.typeOfIndex(inst);
     const payload_ty = inst_ty.errorUnionPayload();
+    const error_ty = inst_ty.errorUnionSet();
     const is_array = payload_ty.zigTypeTag() == .Array;
     const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
     try writer.writeAll(" = { .payload = ");
-    try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else operand);
-    try writer.print(", .error = {} }};\n", .{
-        try f.fmtIntLiteral(inst_ty.errorUnionSet(), Value.zero),
-    });
+    try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else operand, .Initializer);
+    try writer.writeAll(", .error = ");
+    try f.object.dg.renderValue(writer, error_ty, Value.zero, .Initializer);
+    try writer.writeAll(" };\n");
 
     if (is_array) {
         try writer.writeAll("memcpy(");
-        try f.writeCValue(writer, local);
+        try f.writeCValue(writer, local, .Other);
         try writer.writeAll(".payload, ");
-        try f.writeCValue(writer, operand);
+        try f.writeCValue(writer, operand, .FunctionArgument);
         try writer.writeAll(", sizeof(");
-        try f.writeCValue(writer, local);
-        try writer.writeAll(".payload));\n");
+        try f.renderTypecast(writer, payload_ty);
+        try writer.writeAll("));\n");
     }
 
     return local;
 }
 
-fn airIsErr(
-    f: *Function,
-    inst: Air.Inst.Index,
-    is_ptr: bool,
-    op_str: [*:0]const u8,
-) !CValue {
+fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue {
     if (f.liveness.isUnused(inst))
         return CValue.none;
 
@@ -4146,18 +4162,17 @@ fn airIsErr(
     try writer.writeAll(" = ");
 
     if (error_ty.errorSetIsEmpty()) {
-        try writer.print("0 {s} 0;\n", .{op_str});
+        try writer.writeByte('0');
     } else {
-        if (is_ptr) {
-            try f.writeCValueDeref(writer, operand);
-        } else {
-            try f.writeCValue(writer, operand);
-        }
+        try f.writeCValue(writer, operand, .Other);
         if (payload_ty.hasRuntimeBits()) {
-            try writer.writeAll(".error");
+            try if (is_ptr) writer.writeAll("->") else writer.writeByte('.');
+            try writer.writeAll("error");
         }
-        try writer.print(" {s} 0;\n", .{op_str});
     }
+    try writer.writeByte(' ');
+    try writer.writeAll(operator);
+    try writer.writeAll(" 0;\n");
     return local;
 }
 
@@ -4177,13 +4192,16 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
         // Unfortunately, C does not support any equivalent to
         // &(*(void *)p)[0], although LLVM does via GetElementPtr
         var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-        try f.writeCValue(writer, CValue{ .undef = inst_ty.slicePtrFieldType(&buf) });
+        try f.writeCValue(writer, CValue{ .undef = inst_ty.slicePtrFieldType(&buf) }, .Initializer);
     } else {
         try writer.writeAll("&(");
         try f.writeCValueDeref(writer, operand);
         try writer.writeAll(")[0]");
     }
-    try writer.print(", .len = {d} }};\n", .{array_len});
+
+    var len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = array_len };
+    const len_val = Value.initPayload(&len_pl.base);
+    try writer.print(", .len = {} }};\n", .{try f.fmtIntLiteral(Type.usize, len_val)});
     return local;
 }
 
@@ -4199,7 +4217,7 @@ fn airSimpleCast(f: *Function, inst: Air.Inst.Index) !CValue {
     const operand = try f.resolveInst(ty_op.operand);
 
     try writer.writeAll(" = ");
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .Other);
     try writer.writeAll(";\n");
     return local;
 }
@@ -4216,7 +4234,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
     try writer.writeAll(" = (");
     try f.renderTypecast(writer, inst_ty);
     try writer.writeByte(')');
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .Other);
     try writer.writeAll(";\n");
     return local;
 }
@@ -4237,7 +4255,7 @@ fn airBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !C
 
     try writer.print(" = zig_{s}_", .{fn_name});
     try writer.print("{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });
-    try f.writeCValue(writer, try f.resolveInst(operand));
+    try f.writeCValue(writer, try f.resolveInst(operand), .FunctionArgument);
     try writer.print(", {d});\n", .{int_info.bits});
     return local;
 }
@@ -4266,9 +4284,9 @@ fn airBinOpBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u
     }
 
     try writer.writeByte('(');
-    try f.writeCValue(writer, try f.resolveInst(bin_op.lhs));
+    try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument);
     try writer.writeAll(", ");
-    try f.writeCValue(writer, try f.resolveInst(bin_op.rhs));
+    try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument);
     try writer.writeAll(");\n");
     return local;
 }
@@ -4287,12 +4305,12 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
     const local = try f.allocLocal(inst_ty, .Mut);
     try writer.writeAll(" = ");
     if (is_struct) try writer.writeAll("{ .payload = ");
-    try f.writeCValue(writer, expected_value);
+    try f.writeCValue(writer, expected_value, .Initializer);
     if (is_struct) try writer.writeAll(", .is_null = false }");
     try writer.writeAll(";\n");
 
     if (is_struct) {
-        try f.writeCValue(writer, local);
+        try f.writeCValue(writer, local, .Other);
         try writer.writeAll(".is_null = ");
     } else {
         try writer.writeAll("if (");
@@ -4302,14 +4320,14 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
     try writer.writeByte(')');
     if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
     try writer.writeAll(" *)");
-    try f.writeCValue(writer, ptr);
+    try f.writeCValue(writer, ptr, .Other);
     try writer.writeAll(", ");
-    try f.writeCValue(writer, local);
+    try f.writeCValue(writer, local, .FunctionArgument);
     if (is_struct) {
         try writer.writeAll(".payload");
     }
     try writer.writeAll(", ");
-    try f.writeCValue(writer, new_value);
+    try f.writeCValue(writer, new_value, .FunctionArgument);
     try writer.writeAll(", ");
     try writeMemoryOrder(writer, extra.successOrder());
     try writer.writeAll(", ");
@@ -4320,7 +4338,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
     } else {
         try writer.writeAll(") {\n");
         f.object.indent_writer.pushIndent();
-        try f.writeCValue(writer, local);
+        try f.writeCValue(writer, local, .Other);
         try writer.writeAll(" = NULL;\n");
         f.object.indent_writer.popIndent();
         try writer.writeAll("}\n");
@@ -4353,9 +4371,9 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
     }
     if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
     try writer.writeAll(" *)");
-    try f.writeCValue(writer, ptr);
+    try f.writeCValue(writer, ptr, .Other);
     try writer.writeAll(", ");
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .FunctionArgument);
     try writer.writeAll(", ");
     try writeMemoryOrder(writer, extra.ordering());
     try writer.writeAll(");\n");
@@ -4379,7 +4397,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
     try writer.writeByte(')');
     if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
     try writer.writeAll(" *)");
-    try f.writeCValue(writer, ptr);
+    try f.writeCValue(writer, ptr, .Other);
     try writer.writeAll(", ");
     try writeMemoryOrder(writer, atomic_load.order);
     try writer.writeAll(");\n");
@@ -4399,9 +4417,9 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
     try writer.writeByte(')');
     if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
     try writer.writeAll(" *)");
-    try f.writeCValue(writer, ptr);
+    try f.writeCValue(writer, ptr, .Other);
     try writer.writeAll(", ");
-    try f.writeCValue(writer, element);
+    try f.writeCValue(writer, element, .FunctionArgument);
     try writer.print(", {s});\n", .{order});
 
     return CValue.none;
@@ -4416,11 +4434,11 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
     const writer = f.object.writer();
 
     try writer.writeAll("memset(");
-    try f.writeCValue(writer, dest_ptr);
+    try f.writeCValue(writer, dest_ptr, .FunctionArgument);
     try writer.writeAll(", ");
-    try f.writeCValue(writer, value);
+    try f.writeCValue(writer, value, .FunctionArgument);
     try writer.writeAll(", ");
-    try f.writeCValue(writer, len);
+    try f.writeCValue(writer, len, .FunctionArgument);
     try writer.writeAll(");\n");
 
     return CValue.none;
@@ -4435,11 +4453,11 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
     const writer = f.object.writer();
 
     try writer.writeAll("memcpy(");
-    try f.writeCValue(writer, dest_ptr);
+    try f.writeCValue(writer, dest_ptr, .FunctionArgument);
     try writer.writeAll(", ");
-    try f.writeCValue(writer, src_ptr);
+    try f.writeCValue(writer, src_ptr, .FunctionArgument);
     try writer.writeAll(", ");
-    try f.writeCValue(writer, len);
+    try f.writeCValue(writer, len, .FunctionArgument);
     try writer.writeAll(");\n");
 
     return CValue.none;
@@ -4457,9 +4475,9 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
     if (layout.tag_size == 0) return CValue.none;
 
     try writer.writeByte('(');
-    try f.writeCValue(writer, union_ptr);
+    try f.writeCValue(writer, union_ptr, .Other);
     try writer.writeAll(")->tag = ");
-    try f.writeCValue(writer, new_tag);
+    try f.writeCValue(writer, new_tag, .Other);
     try writer.writeAll(";\n");
 
     return CValue.none;
@@ -4481,7 +4499,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
     if (layout.tag_size == 0) return CValue.none;
 
     try writer.writeAll(" = ");
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .Other);
     try writer.writeAll(".tag;\n");
     return local;
 }
@@ -4497,7 +4515,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
     const writer = f.object.writer();
     const local = try f.allocLocal(inst_ty, .Const);
     try writer.print(" = {s}(", .{try f.object.dg.getTagNameFn(enum_ty)});
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .Other);
     try writer.writeAll(");\n");
 
     try f.object.dg.fwd_decl.writer().writeAll("// This is where the fwd decl for tagName ended up\n");
@@ -4515,7 +4533,7 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
     const local = try f.allocLocal(inst_ty, .Const);
 
     try writer.writeAll(" = zig_errorName[");
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .Other);
     try writer.writeAll("];\n");
     return local;
 }
@@ -4600,12 +4618,12 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
             var empty = true;
             for (elements) |element| {
                 if (!empty) try writer.writeAll(", ");
-                try f.writeCValue(writer, try f.resolveInst(element));
+                try f.writeCValue(writer, try f.resolveInst(element), .Initializer);
                 empty = false;
             }
             if (inst_ty.sentinel()) |sentinel| {
                 if (!empty) try writer.writeAll(", ");
-                try f.object.dg.renderValue(writer, elem_ty, sentinel, .Other);
+                try f.object.dg.renderValue(writer, elem_ty, sentinel, .Initializer);
                 empty = false;
             }
             if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});
@@ -4625,7 +4643,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
                 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {
                     .Array => CValue{ .undef = element_ty },
                     else => try f.resolveInst(element),
-                });
+                }, .Initializer);
                 empty = false;
             }
             if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});
@@ -4647,12 +4665,12 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
 
                 try writer.writeAll(";\n");
                 try writer.writeAll("memcpy(");
-                try f.writeCValue(writer, local);
+                try f.writeCValue(writer, local, .Other);
                 try writer.print(".{ }, ", .{fmtIdent(field_name)});
-                try f.writeCValue(writer, try f.resolveInst(element));
+                try f.writeCValue(writer, try f.resolveInst(element), .FunctionArgument);
                 try writer.writeAll(", sizeof(");
-                try f.writeCValue(writer, local);
-                try writer.print(".{ }));\n", .{fmtIdent(field_name)});
+                try f.renderTypecast(writer, element_ty);
+                try writer.writeAll("));\n");
             }
         },
         .Vector => return f.fail("TODO: C backend: implement airAggregateInit for vectors", .{}),
@@ -4681,14 +4699,14 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
         if (layout.tag_size != 0) {
             const field_index = tag_ty.enumFieldIndex(field_name).?;
 
-            var tag_val_pl: Value.Payload.U32 = .{
+            var tag_pl: Value.Payload.U32 = .{
                 .base = .{ .tag = .enum_field_index },
                 .data = @intCast(u32, field_index),
             };
-            const tag_val = Value.initPayload(&tag_val_pl.base);
+            const tag_val = Value.initPayload(&tag_pl.base);
 
-            var int_val_pl: Value.Payload.U64 = undefined;
-            const int_val = tag_val.enumToInt(tag_ty, &int_val_pl);
+            var int_pl: Value.Payload.U64 = undefined;
+            const int_val = tag_val.enumToInt(tag_ty, &int_pl);
 
             try writer.print(".tag = {}, ", .{try f.fmtIntLiteral(tag_ty, int_val)});
         }
@@ -4696,7 +4714,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
     }
 
     try writer.print(".{ } = ", .{fmtIdent(field_name)});
-    try f.writeCValue(writer, payload);
+    try f.writeCValue(writer, payload, .Initializer);
 
     if (union_ty.unionTagTypeSafety()) |_| try writer.writeByte('}');
     try writer.writeAll("};\n");
@@ -4716,7 +4734,7 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
     const ptr = try f.resolveInst(prefetch.ptr);
     const writer = f.object.writer();
     try writer.writeAll("zig_prefetch(");
-    try f.writeCValue(writer, ptr);
+    try f.writeCValue(writer, ptr, .FunctionArgument);
     try writer.print(", {d}, {d});\n", .{
         @enumToInt(prefetch.rw), prefetch.locality,
     });
@@ -4748,7 +4766,7 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
 
     try writer.writeAll(" = ");
     try writer.print("zig_wasm_memory_grow({d}, ", .{pl_op.payload});
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .FunctionArgument);
     try writer.writeAll(");\n");
     return local;
 }
@@ -4762,7 +4780,7 @@ fn airNeg(f: *Function, inst: Air.Inst.Index) !CValue {
     const operand = try f.resolveInst(un_op);
     const local = try f.allocLocal(inst_ty, .Const);
     try writer.writeAll(" = -");
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .Other);
     try writer.writeAll(";\n");
     return local;
 }
@@ -4777,7 +4795,7 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, fn_name: []const u8) !CValue
     try writer.writeAll(" = ");
     try f.renderFloatFnName(fn_name, inst_ty);
     try writer.writeByte('(');
-    try f.writeCValue(writer, operand);
+    try f.writeCValue(writer, operand, .FunctionArgument);
     try writer.writeAll(");\n");
     return local;
 }
@@ -4793,9 +4811,9 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, fn_name: []const u8) !CValu
     try writer.writeAll(" = ");
     try f.renderFloatFnName(fn_name, inst_ty);
     try writer.writeByte('(');
-    try f.writeCValue(writer, lhs);
+    try f.writeCValue(writer, lhs, .FunctionArgument);
     try writer.writeAll(", ");
-    try f.writeCValue(writer, rhs);
+    try f.writeCValue(writer, rhs, .FunctionArgument);
     try writer.writeAll(");\n");
     return local;
 }
@@ -4813,11 +4831,11 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
     try writer.writeAll(" = ");
     try f.renderFloatFnName("fma", inst_ty);
     try writer.writeByte('(');
-    try f.writeCValue(writer, mulend1);
+    try f.writeCValue(writer, mulend1, .FunctionArgument);
     try writer.writeAll(", ");
-    try f.writeCValue(writer, mulend2);
+    try f.writeCValue(writer, mulend2, .FunctionArgument);
     try writer.writeAll(", ");
-    try f.writeCValue(writer, addend);
+    try f.writeCValue(writer, addend, .FunctionArgument);
     try writer.writeAll(");\n");
     return local;
 }
@@ -5013,15 +5031,15 @@ fn formatIntLiteral(
         }
 
         const split = std.math.min(int.limbs.len, limbs_count_64);
-        var upper_val_pl = Value.Payload.BigInt{
+        var upper_pl = Value.Payload.BigInt{
             .base = .{ .tag = .int_big_positive },
             .data = int.limbs[split..],
         };
-        const have_upper = !upper_val_pl.asBigInt().eqZero();
+        const have_upper = !upper_pl.asBigInt().eqZero();
         if (have_upper) try writer.writeByte('(');
         if (have_upper or !int.positive) try writer.writeAll("(uint128_t)");
         if (have_upper) {
-            const upper_val = Value.initPayload(&upper_val_pl.base);
+            const upper_val = Value.initPayload(&upper_pl.base);
             try formatIntLiteral(.{
                 .ty = Type.u64,
                 .val = upper_val,
@@ -5030,11 +5048,11 @@ fn formatIntLiteral(
             try writer.writeAll("<<64|");
         }
 
-        var lower_val_pl = Value.Payload.BigInt{
+        var lower_pl = Value.Payload.BigInt{
             .base = .{ .tag = .int_big_positive },
             .data = int.limbs[0..split],
         };
-        const lower_val = Value.initPayload(&lower_val_pl.base);
+        const lower_val = Value.initPayload(&lower_pl.base);
         try formatIntLiteral(.{
             .ty = Type.u64,
             .val = lower_val,