Commit 00b54a5fe5

kcbanner <kcbanner@gmail.com>
2022-12-12 05:31:41
cbe: more msvc fixes
- Add Function.renderIntcast to handle common casting cases - Fixup casting inside aggregate initialization - Remove redundant cast in aggregate initialization - Fix renderValue .Packed branch for > 64 bit types
1 parent 36212e9
Changed files (1)
src
codegen
src/codegen/c.zig
@@ -431,6 +431,10 @@ pub const Function = struct {
         return f.object.dg.renderTypecast(w, t);
     }
 
+    fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, src_ty: Type, location: ValueRenderLocation) !void {
+        return f.object.dg.renderIntCast(w, dest_ty, .{ .c_value = .{ .f = f, .value = src } }, src_ty, location);
+    }
+
     fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) {
         return f.object.dg.fmtIntLiteral(ty, val);
     }
@@ -1263,25 +1267,85 @@ pub const DeclGen = struct {
                     var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 };
                     const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
 
-                    try writer.writeByte('(');
-                    var empty = true;
-                    for (field_vals) |field_val, index| {
+                    var eff_num_fields: usize = 0;
+                    for (field_vals) |_, index| {
                         const field_ty = ty.structFieldType(index);
                         if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
 
-                        if (!empty) try writer.writeAll(" | ");
+                        eff_num_fields += 1;
+                    }
+
+                    if (eff_num_fields == 0) {
                         try writer.writeByte('(');
-                        try dg.renderTypecast(writer, ty);
+                        try dg.renderValue(writer, ty, Value.undef, .Initializer);
                         try writer.writeByte(')');
-                        try dg.renderValue(writer, field_ty, field_val, .Other);
-                        try writer.writeAll(" << ");
-                        try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
+                    } else if (ty.bitSize(target) > 64) {
+                        // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))
+                        var num_or = eff_num_fields - 1;
+                        while (num_or > 0) : (num_or -= 1) {
+                            try writer.writeAll("zig_or_");
+                            try dg.renderTypeForBuiltinFnName(writer, ty);
+                            try writer.writeByte('(');
+                        }
 
-                        bit_offset_val_pl.data += field_ty.bitSize(target);
-                        empty = false;
+                        var eff_index: usize = 0;
+                        var needs_closing_paren = false;
+                        for (field_vals) |field_val, index| {
+                            const field_ty = ty.structFieldType(index);
+                            if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
+
+                            //const cast_context = IntCastContext{ .value = .{ .value = field_val } };
+                            if (bit_offset_val_pl.data != 0) {
+                                try writer.writeAll("zig_shl_");
+                                try dg.renderTypeForBuiltinFnName(writer, ty);
+                                try writer.writeByte('(');
+
+                                //try dg.renderIntCast(writer, ty,_context, field_ty, .FunctionArgument);
+                                try dg.renderValue(writer, field_ty, field_val, .FunctionArgument);
+
+                                try writer.writeAll(", ");
+                                try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
+                                try writer.writeByte(')');
+                            } else {
+
+                                try dg.renderValue(writer, field_ty, field_val, .FunctionArgument);
+                                //try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
+
+                            }
+
+                            if (needs_closing_paren) try writer.writeByte(')');
+                            if (eff_index != eff_num_fields - 1) try writer.writeAll(", ");
+
+                            bit_offset_val_pl.data += field_ty.bitSize(target);
+                            needs_closing_paren = true;
+                            eff_index += 1;
+                        }
+                    } else {
+                        try writer.writeByte('(');
+                        // a << a_off | b << b_off | c << c_off
+                        var empty = true;
+                        for (field_vals) |field_val, index| {
+                            const field_ty = ty.structFieldType(index);
+                            if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
+
+                            if (!empty) try writer.writeAll(" | ");
+                            try writer.writeByte('(');
+                            try dg.renderTypecast(writer, ty);
+                            try writer.writeByte(')');
+
+                            if (bit_offset_val_pl.data != 0) {
+                                try dg.renderValue(writer, field_ty, field_val, .Other);
+                                try writer.writeAll(" << ");
+                                try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
+                            } else {
+                                try dg.renderValue(writer, field_ty, field_val, .Other);
+                            }
+
+                            bit_offset_val_pl.data += field_ty.bitSize(target);
+                            empty = false;
+                        }
+                        try writer.writeByte(')');
                     }
-                    if (empty) try dg.renderValue(writer, ty, Value.undef, .Initializer);
-                    try writer.writeByte(')');
                 },
             },
             .Union => {
@@ -2103,6 +2167,101 @@ pub const DeclGen = struct {
         });
     }
 
+    const IntCastContext = union(enum) {
+        c_value: struct {
+            f: *Function,
+            value: CValue,
+        },
+        value: struct {
+            value: Value,
+        },
+
+        pub fn writeValue(self: *const IntCastContext, dg: *DeclGen, w: anytype, value_ty: Type, location: ValueRenderLocation) !void {
+            switch (self.*) {
+                .c_value => |v| {
+                    try v.f.writeCValue(w, v.value, location);
+                },
+                .value => |v| {
+                    try dg.renderValue(w, value_ty, v.value, location);
+                },
+            }
+        }
+    };
+
+    /// Renders a cast to an int type, from either an int or a pointer.
+    ///
+    /// Some platforms don't have 128 bit integers, so we need to use
+    /// the zig_as_ and zig_lo_ macros in those cases.
+    ///
+    ///   | Dest type bits   | Src type         | Result
+    ///   |------------------|------------------|---------------------------|
+    ///   | < 64 bit integer | pointer          | (zig_<dest_ty>)(zig_<u|i>size)src
+    ///   | < 64 bit integer | < 64 bit integer | (zig_<dest_ty>)src
+    ///   | < 64 bit integer | > 64 bit integer | zig_lo(src)
+    ///   | > 64 bit integer | pointer          | zig_as_<dest_ty>(0, (zig_<u|i>size)src)
+    ///   | > 64 bit integer | < 64 bit integer | zig_as_<dest_ty>(0, src)
+    ///   | > 64 bit integer | > 64 bit integer | zig_as_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src))
+    fn renderIntCast(dg: *DeclGen, w: anytype, dest_ty: Type, context: IntCastContext, src_ty: Type, location: ValueRenderLocation) !void {
+        const target = dg.module.getTarget();
+        const dest_bits = dest_ty.bitSize(target);
+        const dest_int_info = dest_ty.intInfo(target);
+
+        const src_is_ptr = src_ty.isPtrAtRuntime();
+        const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) {
+            .unsigned => Type.usize,
+            .signed => Type.isize,
+        } else src_ty;
+
+        const src_bits = src_eff_ty.bitSize(target);
+        const src_int_info = src_eff_ty.intInfo(target);
+        if (dest_bits <= 64 and src_bits <= 64) {
+            const needs_cast = toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.bits) or
+                dest_int_info.signedness != src_int_info.signedness;
+            if (needs_cast) {
+                try w.writeByte('(');
+                try dg.renderTypecast(w, dest_ty);
+                try w.writeByte(')');
+            }
+            if (src_is_ptr) {
+                try w.writeByte('(');
+                try dg.renderTypecast(w, src_eff_ty);
+                try w.writeByte(')');
+            }
+            try context.writeValue(dg, w, src_ty, location);
+        } else if (dest_bits <= 64 and src_bits > 64) {
+            assert(!src_is_ptr);
+            try w.writeAll("zig_lo_");
+            try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
+            try w.writeByte('(');
+            try context.writeValue(dg, w, src_ty, .FunctionArgument);
+            try w.writeByte(')');
+        } else if (dest_bits > 64 and src_bits <= 64) {
+            try w.writeAll("zig_as_");
+            try dg.renderTypeForBuiltinFnName(w, dest_ty);
+            try w.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral?
+            if (src_is_ptr) {
+                try w.writeByte('(');
+                try dg.renderTypecast(w, src_eff_ty);
+                try w.writeByte(')');
+            }
+            try context.writeValue(dg, w, src_ty, .FunctionArgument);
+            try w.writeByte(')');
+        } else {
+            assert(!src_is_ptr);
+            try w.writeAll("zig_as_");
+            try dg.renderTypeForBuiltinFnName(w, dest_ty);
+            try w.writeAll("(zig_hi_");
+            try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
+            try w.writeByte('(');
+            try context.writeValue(dg, w, src_ty, .FunctionArgument);
+            try w.writeAll("), zig_lo_");
+            try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
+            try w.writeByte('(');
+            try context.writeValue(dg, w, src_ty, .FunctionArgument);
+            try w.writeAll("))");
+        }
+    }
+
     /// Renders a type in C typecast format.
     ///
     /// This is guaranteed to be valid in a typecast expression, but not
@@ -3344,55 +3503,16 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
         return CValue.none;
     }
 
-    const target = f.object.dg.module.getTarget();
     const operand = try f.resolveInst(ty_op.operand);
     try reap(f, inst, &.{ty_op.operand});
     const writer = f.object.writer();
     const inst_ty = f.air.typeOfIndex(inst);
     const local = try f.allocLocal(inst, inst_ty);
-    const inst_bits = inst_ty.bitSize(target);
-    const inst_int_info = inst_ty.intInfo(target);
     const operand_ty = f.air.typeOf(ty_op.operand);
-    const operand_bits = operand_ty.bitSize(target);
-    const operand_int_info = operand_ty.intInfo(target);
 
     try f.writeCValue(writer, local, .Other);
     try writer.writeAll(" = ");
-
-    if (inst_bits <= 64 and operand_bits <= 64) {
-        if (toCIntBits(inst_int_info.bits) != toCIntBits(operand_int_info.bits) or inst_int_info.signedness != operand_int_info.signedness) {
-            try writer.writeByte('(');
-            try f.renderTypecast(writer, inst_ty);
-            try writer.writeByte(')');
-        }
-
-        try f.writeCValue(writer, operand, .Other);
-    } else if (inst_bits > 64 and operand_bits <= 64) {
-        try writer.writeAll("zig_as_");
-        try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
-        try writer.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral?
-        try f.writeCValue(writer, operand, .FunctionArgument);
-        try writer.writeByte(')');
-    } else if (inst_bits <= 64 and operand_bits > 64) {
-        try writer.writeAll("zig_lo_");
-        try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
-        try writer.writeByte('(');
-        try f.writeCValue(writer, operand, .FunctionArgument);
-        try writer.writeByte(')');
-    } else {
-        try writer.writeAll("zig_as_");
-        try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
-        try writer.writeAll("(zig_hi_");
-        try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
-        try writer.writeByte('(');
-        try f.writeCValue(writer, operand, .FunctionArgument);
-        try writer.writeAll("), zig_lo_");
-        try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
-        try writer.writeByte('(');
-        try f.writeCValue(writer, operand, .FunctionArgument);
-        try writer.writeAll("))");
-    }
-
+    try f.renderIntCast(writer, inst_ty, operand, operand_ty, .Other);
     try writer.writeAll(";\n");
     return local;
 }
@@ -6509,9 +6629,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
             },
             .Packed => {
                 try f.writeCValue(writer, local, .Other);
-                try writer.writeAll(" = (");
-                try f.renderTypecast(writer, inst_ty);
-                try writer.writeAll(")");
+                try writer.writeAll(" = ");
                 const int_info = inst_ty.intInfo(target);
 
                 var bit_offset_ty_pl = Type.Payload.Bits{
@@ -6541,20 +6659,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
                     if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
 
                     if (!empty) try writer.writeAll(", ");
+                    // TODO: Skip this entire shift if val is 0?
                     try writer.writeAll("zig_shlw_");
                     try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
-                    try writer.writeAll("((");
-                    try f.renderTypecast(writer, inst_ty);
-                    try writer.writeByte(')');
-                    if (field_ty.isPtrAtRuntime()) {
+                    try writer.writeByte('(');
+
+                    if (inst_ty.isAbiInt() and (field_ty.isAbiInt() or field_ty.isPtrAtRuntime())) {
+                        try f.renderIntCast(writer, inst_ty, element, field_ty, .FunctionArgument);
+                    } else {
                         try writer.writeByte('(');
-                        try f.renderTypecast(writer, switch (int_info.signedness) {
-                            .unsigned => Type.usize,
-                            .signed => Type.isize,
-                        });
+                        try f.renderTypecast(writer, inst_ty);
                         try writer.writeByte(')');
+                        if (field_ty.isPtrAtRuntime()) {
+                            try writer.writeByte('(');
+                            try f.renderTypecast(writer, switch (int_info.signedness) {
+                                .unsigned => Type.usize,
+                                .signed => Type.isize,
+                            });
+                            try writer.writeByte(')');
+                        }
+                        try f.writeCValue(writer, element, .Other);
                     }
-                    try f.writeCValue(writer, element, .Other);
+
                     try writer.writeAll(", ");
                     try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
                     try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits);
@@ -6564,7 +6690,14 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
                     bit_offset_val_pl.data += field_ty.bitSize(target);
                     empty = false;
                 }
-                if (empty) try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer);
+
+                if (empty) {
+                    try writer.writeByte('(');
+                    try f.renderTypecast(writer, inst_ty);
+                    try writer.writeByte(')');
+                    try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer);
+                }
+
                 try writer.writeAll(";\n");
             },
         },
@@ -6937,7 +7070,7 @@ fn StringLiteral(comptime WriterType: type) type {
             }
         }
 
-        pub fn writeChar(self: *Self,  c: u8) Error!void {
+        pub fn writeChar(self: *Self, c: u8) Error!void {
             const writer = self.counting_writer.writer();
 
             if (self.cur_len == 0 and self.counting_writer.bytes_written > 1)