Commit f07d33f54b

kcbanner <kcbanner@gmail.com>
2022-12-24 05:48:44
cbe: fixes for compiling zig2.c under msvc
- add zig_mul_i128 - render slice structs in static initializers without casts / c99 style init - add negative numbers and u128 to 128-bit multiply test
1 parent 55c3551
Changed files (3)
lib
src
codegen
test
behavior
lib/zig.h
@@ -1465,6 +1465,11 @@ static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) {
 static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs); // TODO
 #endif
 
+zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs);
+static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) {
+    return __multi3(lhs, rhs);
+}
+
 static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
     return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits);
 }
src/codegen/c.zig
@@ -320,7 +320,7 @@ pub const Function = struct {
             try writer.writeAll("static ");
             try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, alignment, .Complete);
             try writer.writeAll(" = ");
-            try f.object.dg.renderValue(writer, ty, val, .Initializer);
+            try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);
             try writer.writeAll(";\n ");
             break :result decl_c_value;
         } else CValue{ .constant = inst };
@@ -514,6 +514,7 @@ pub const DeclGen = struct {
         ty: Type,
         val: Value,
         decl_index: Decl.Index,
+        location: ValueRenderLocation,
     ) error{ OutOfMemory, AnalysisFail }!void {
         const decl = dg.module.declPtr(decl_index);
         assert(decl.has_tv);
@@ -527,12 +528,16 @@ pub const DeclGen = struct {
         inline for (.{ .function, .extern_fn }) |tag|
             if (decl.val.castTag(tag)) |func|
                 if (func.data.owner_decl != decl_index)
-                    return dg.renderDeclValue(writer, ty, val, func.data.owner_decl);
+                    return dg.renderDeclValue(writer, ty, val, func.data.owner_decl, location);
 
         if (ty.isSlice()) {
-            try writer.writeByte('(');
-            try dg.renderTypecast(writer, ty);
-            try writer.writeAll("){ .ptr = ");
+            if (location == .StaticInitializer) {
+                try writer.writeByte('{');
+            } else {
+                try writer.writeByte('(');
+                try dg.renderTypecast(writer, ty);
+                try writer.writeAll("){ .ptr = ");
+            }
 
             var buf: Type.SlicePtrFieldTypeBuffer = undefined;
             try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Initializer);
@@ -542,7 +547,12 @@ pub const DeclGen = struct {
                 .data = val.sliceLen(dg.module),
             };
             const len_val = Value.initPayload(&len_pl.base);
-            return writer.print(", .len = {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)});
+
+            if (location == .StaticInitializer) {
+                return writer.print(", {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)});
+            } else {
+                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
@@ -564,7 +574,7 @@ pub const DeclGen = struct {
     // that its contents are defined with respect to.
     //
     // Used for .elem_ptr, .field_ptr, .opt_payload_ptr, .eu_payload_ptr
-    fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type) error{ OutOfMemory, AnalysisFail }!void {
+    fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type, location: ValueRenderLocation) error{ OutOfMemory, AnalysisFail }!void {
         if (!ptr_ty.isSlice()) {
             try writer.writeByte('(');
             try dg.renderTypecast(writer, ptr_ty);
@@ -579,7 +589,7 @@ pub const DeclGen = struct {
                     .variable => ptr_val.castTag(.variable).?.data.owner_decl,
                     else => unreachable,
                 };
-                try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index);
+                try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index, location);
             },
             .field_ptr => {
                 const ptr_info = ptr_ty.ptrInfo();
@@ -617,7 +627,7 @@ pub const DeclGen = struct {
                             try writer.writeAll("&((");
                             try dg.renderTypecast(writer, u8_ptr_ty);
                             try writer.writeByte(')');
-                            try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);
+                            try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);
                             return writer.print(")[{}]", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)});
                         } else {
                             var host_pl = Type.Payload.Bits{
@@ -629,7 +639,7 @@ pub const DeclGen = struct {
                             try writer.writeByte('(');
                             try dg.renderTypecast(writer, ptr_ty);
                             try writer.writeByte(')');
-                            return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty);
+                            return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty, location);
                         },
                     },
                     .Union => switch (container_ty.containerLayout()) {
@@ -638,7 +648,7 @@ pub const DeclGen = struct {
                             .ty = container_ty.unionFields().values()[index].ty,
                         },
                         .Packed => {
-                            return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty);
+                            return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty, location);
                         },
                     },
                     .Pointer => field_info: {
@@ -657,7 +667,7 @@ pub const DeclGen = struct {
                     try dg.renderType(std.io.null_writer, field_ptr.container_ty, .Complete);
 
                     try writer.writeAll("&(");
-                    try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);
+                    try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);
                     try writer.writeAll(")->");
                     switch (field_ptr.container_ty.tag()) {
                         .union_tagged, .union_safety_tagged => try writer.writeAll("payload."),
@@ -665,7 +675,7 @@ pub const DeclGen = struct {
                     }
                     try writer.print("{ }", .{fmtIdent(field_info.name)});
                 } else {
-                    try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);
+                    try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);
                 }
             },
             .elem_ptr => {
@@ -677,7 +687,7 @@ pub const DeclGen = struct {
                 const elem_ptr_ty = Type.initPayload(&elem_ptr_ty_pl.base);
 
                 try writer.writeAll("&(");
-                try dg.renderParentPtr(writer, elem_ptr.array_ptr, elem_ptr_ty);
+                try dg.renderParentPtr(writer, elem_ptr.array_ptr, elem_ptr_ty, location);
                 try writer.print(")[{d}]", .{elem_ptr.index});
             },
             .opt_payload_ptr, .eu_payload_ptr => {
@@ -692,7 +702,7 @@ pub const DeclGen = struct {
                 try dg.renderType(std.io.null_writer, payload_ptr.container_ty, .Complete);
 
                 try writer.writeAll("&(");
-                try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty);
+                try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty, location);
                 try writer.writeAll(")->payload");
             },
             else => unreachable,
@@ -910,7 +920,7 @@ pub const DeclGen = struct {
                 .eu_payload_ptr,
                 .decl_ref_mut,
                 .decl_ref,
-                => try dg.renderParentPtr(writer, val, ty),
+                => try dg.renderParentPtr(writer, val, ty, location),
                 else => try writer.print("{}", .{try dg.fmtIntLiteralLoc(ty, val, location)}),
             },
             .Float => {
@@ -1024,7 +1034,7 @@ pub const DeclGen = struct {
                 },
                 .variable => {
                     const decl = val.castTag(.variable).?.data.owner_decl;
-                    return dg.renderDeclValue(writer, ty, val, decl);
+                    return dg.renderDeclValue(writer, ty, val, decl, location);
                 },
                 .slice => {
                     if (!location.isInitializer()) {
@@ -1061,7 +1071,7 @@ pub const DeclGen = struct {
                 .eu_payload_ptr,
                 .decl_ref_mut,
                 .decl_ref,
-                => try dg.renderParentPtr(writer, val, ty),
+                => try dg.renderParentPtr(writer, val, ty, location),
                 else => unreachable,
             },
             .Array, .Vector => {
@@ -1255,11 +1265,11 @@ pub const DeclGen = struct {
             .Fn => switch (val.tag()) {
                 .function => {
                     const decl = val.castTag(.function).?.data.owner_decl;
-                    return dg.renderDeclValue(writer, ty, val, decl);
+                    return dg.renderDeclValue(writer, ty, val, decl, location);
                 },
                 .extern_fn => {
                     const decl = val.castTag(.extern_fn).?.data.owner_decl;
-                    return dg.renderDeclValue(writer, ty, val, decl);
+                    return dg.renderDeclValue(writer, ty, val, decl, location);
                 },
                 else => unreachable,
             },
@@ -2512,6 +2522,9 @@ pub const DeclGen = struct {
         try dg.writeCValue(writer, member);
     }
 
+    const IdentHasher = std.crypto.auth.siphash.SipHash128(1, 3);
+    const ident_hasher_init: IdentHasher = IdentHasher.init(&[_]u8{0} ** IdentHasher.key_length);
+
     fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index, export_index: u32) !void {
         const decl = dg.module.declPtr(decl_index);
         dg.module.markDeclAlive(decl);
@@ -2529,7 +2542,18 @@ pub const DeclGen = struct {
             const gpa = dg.gpa;
             const name = try decl.getFullyQualifiedName(dg.module);
             defer gpa.free(name);
-            return writer.print("{}", .{fmtIdent(name)});
+
+            // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case), expand
+            // to 3x the length of its input
+            if (name.len > 1365) {
+                var hash = ident_hasher_init;
+                hash.update(name);
+                const ident_hash = hash.finalInt();
+                try writer.writeAll("zig_D_");
+                return std.fmt.formatIntValue(ident_hash, "x", .{}, writer);
+            } else {
+                return writer.print("{}", .{fmtIdent(name)});
+            }
         }
     }
 
@@ -4648,7 +4672,15 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
     try f.writeCValue(writer, cond, .Other);
     try writer.writeAll(") ");
     try genBody(f, then_body);
-    try writer.writeAll(" else ");
+
+    // TODO: If body ends in goto, elide the else block?
+    const needs_else = then_body.len <= 0 or f.air.instructions.items(.tag)[then_body[then_body.len - 1]] != .br;
+    if (needs_else) {
+        try writer.writeAll(" else ");
+    } else {
+        try writer.writeByte('\n');
+    }
+
     f.value_map.deinit();
     f.value_map = cloned_map.move();
     const free_locals = f.getFreeLocals();
@@ -4661,7 +4693,12 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
 
     try noticeBranchFrees(f, pre_locals_len, inst);
 
-    try genBody(f, else_body);
+    if (needs_else) {
+        try genBody(f, else_body);
+    } else {
+        try genBodyInner(f, else_body);
+    }
+
     try f.object.indent_writer.insertNewline();
 
     return CValue.none;
test/behavior/math.zig
@@ -632,10 +632,25 @@ test "128-bit multiplication" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 
-    var a: i128 = 3;
-    var b: i128 = 2;
-    var c = a * b;
-    try expect(c == 6);
+    {
+        var a: i128 = 3;
+        var b: i128 = 2;
+        var c = a * b;
+        try expect(c == 6);
+
+        a = -3;
+        b = 2;
+        c = a * b;
+        try expect(c == -6);
+    }
+
+    {
+        var a: u128 = 0xffffffffffffffff;
+        var b: u128 = 100;
+        var c = a * b;
+        try expect(c == 0x63ffffffffffffff9c);
+    }
+
 }
 
 test "@addWithOverflow" {