authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2022-12-12 02:57:57-05:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-01-01 16:44:28-05:00
log7f3bc45772d6af33e0e663ba534eba5653792843
treeabcb77b390eecffcc1822de31d64c5773429d8e6
parent4fe71977e0c2bec28b4cb8015d59ce837dfc80cb

cbe: nan builtins on msvc, fixup C2099 errors in static initializers

- Map the __builtin_nan(f|l)? functions to nan(f|l)? on msvc - MSVC throws C2099 when initializing a struct with cast syntax in a global initializer. Added zig_as_init_ to handle this case, and generate it only in static initializers for > 64 bit ints. - Change float initialization to emit the integer representation in global initializers to avoid C2099 caused by calling nan.

2 files changed, 81 insertions(+), 24 deletions(-)

lib/zig.h+10
......@@ -1151,6 +1151,8 @@ typedef signed __int128 zig_i128;
11511151
11521152#define zig_as_u128(hi, lo) ((zig_u128)(hi)<<64|(lo))
11531153#define zig_as_i128(hi, lo) ((zig_i128)zig_as_u128(hi, lo))
1154#define zig_as_init_u128(hi, lo) zig_as_u128(hi, lo)
1155#define zig_as_init_i128(hi, lo) zig_as_i128(hi, lo)
11541156#define zig_hi_u128(val) ((zig_u64)((val) >> 64))
11551157#define zig_lo_u128(val) ((zig_u64)((val) >> 0))
11561158#define zig_hi_i128(val) ((zig_i64)((val) >> 64))
......@@ -1178,6 +1180,8 @@ typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128;
11781180
11791181#define zig_as_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) })
11801182#define zig_as_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) })
1183#define zig_as_init_u128(hi, lo) { .h##i = (hi), .l##o = (lo) }
1184#define zig_as_init_i128(hi, lo) { .h##i = (hi), .l##o = (lo) }
11811185#define zig_hi_u128(val) ((val).hi)
11821186#define zig_lo_u128(val) ((val).lo)
11831187#define zig_hi_i128(val) ((val).hi)
......@@ -1631,6 +1635,12 @@ static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, zig_u8 bits) {
16311635
16321636/* ========================= Floating Point Support ========================= */
16331637
1638#if _MSC_VER
1639#define __builtin_nan(str) nan(str)
1640#define __builtin_nanf(str) nanf(str)
1641#define __builtin_nanl(str) nanl(str)
1642#endif
1643
16341644#define zig_has_f16 1
16351645#define zig_bitSizeOf_f16 16
16361646#define zig_libc_name_f16(name) __##name##h
src/codegen/c.zig+71-24
......@@ -90,7 +90,15 @@ const FormatTypeAsCIdentContext = struct {
9090const ValueRenderLocation = enum {
9191 FunctionArgument,
9292 Initializer,
93 StaticInitializer,
9394 Other,
95
96 pub fn isInitializer(self: ValueRenderLocation) bool {
97 return switch (self) {
98 .Initializer, .StaticInitializer => true,
99 else => false,
100 };
101 }
94102};
95103
96104const BuiltinInfo = enum {
......@@ -718,7 +726,7 @@ pub const DeclGen = struct {
718726 return writer.writeAll("false");
719727 }
720728 },
721 .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, val)}),
729 .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteralLoc(ty, val, location)}),
722730 .Float => {
723731 const bits = ty.floatBits(target);
724732 var int_pl = Type.Payload.Bits{ .base = .{ .tag = .int_signed }, .data = bits };
......@@ -742,7 +750,7 @@ pub const DeclGen = struct {
742750 return writer.writeByte(')');
743751 },
744752 .Pointer => if (ty.isSlice()) {
745 if (location != .Initializer) {
753 if (!location.isInitializer()) {
746754 try writer.writeByte('(');
747755 try dg.renderTypecast(writer, ty);
748756 try writer.writeByte(')');
......@@ -770,7 +778,7 @@ pub const DeclGen = struct {
770778 return dg.renderValue(writer, payload_ty, val, location);
771779 }
772780
773 if (location != .Initializer) {
781 if (!location.isInitializer()) {
774782 try writer.writeByte('(');
775783 try dg.renderTypecast(writer, ty);
776784 try writer.writeByte(')');
......@@ -784,7 +792,7 @@ pub const DeclGen = struct {
784792 },
785793 .Struct => switch (ty.containerLayout()) {
786794 .Auto, .Extern => {
787 if (location != .Initializer) {
795 if (!location.isInitializer()) {
788796 try writer.writeByte('(');
789797 try dg.renderTypecast(writer, ty);
790798 try writer.writeByte(')');
......@@ -806,7 +814,7 @@ pub const DeclGen = struct {
806814 .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}),
807815 },
808816 .Union => {
809 if (location != .Initializer) {
817 if (!location.isInitializer()) {
810818 try writer.writeByte('(');
811819 try dg.renderTypecast(writer, ty);
812820 try writer.writeByte(')');
......@@ -831,7 +839,7 @@ pub const DeclGen = struct {
831839 return writer.writeByte('}');
832840 },
833841 .ErrorUnion => {
834 if (location != .Initializer) {
842 if (!location.isInitializer()) {
835843 try writer.writeByte('(');
836844 try dg.renderTypecast(writer, ty);
837845 try writer.writeByte(')');
......@@ -844,7 +852,7 @@ pub const DeclGen = struct {
844852 });
845853 },
846854 .Array, .Vector => {
847 if (location != .Initializer) {
855 if (!location.isInitializer()) {
848856 try writer.writeByte('(');
849857 try dg.renderTypecast(writer, ty);
850858 try writer.writeByte(')');
......@@ -899,7 +907,7 @@ pub const DeclGen = struct {
899907 .decl_ref_mut,
900908 .decl_ref,
901909 => try dg.renderParentPtr(writer, val, ty),
902 else => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val)}),
910 else => try writer.print("{}", .{try dg.fmtIntLiteralLoc(ty, val, location)}),
903911 },
904912 .Float => {
905913 const bits = ty.floatBits(target);
......@@ -934,6 +942,7 @@ pub const DeclGen = struct {
934942 try writer.writeAll("zig_cast_");
935943 try dg.renderTypeForBuiltinFnName(writer, ty);
936944 try writer.writeByte(' ');
945 var empty = true;
937946 if (std.math.isFinite(f128_val)) {
938947 try writer.writeAll("zig_as_");
939948 try dg.renderTypeForBuiltinFnName(writer, ty);
......@@ -946,11 +955,14 @@ pub const DeclGen = struct {
946955 128 => try writer.print("{x}", .{f128_val}),
947956 else => unreachable,
948957 }
949 } else {
950 const operation = if (std.math.isSignalNan(f128_val))
951 "nans"
952 else if (std.math.isNan(f128_val))
958 try writer.writeAll(", ");
959 empty = false;
960 } else if (location != .StaticInitializer) {
961 // isSignalNan is equivalent to isNan currently, and MSVC doens't have nans, so prefer nan
962 const operation = if (std.math.isNan(f128_val))
953963 "nan"
964 else if (std.math.isSignalNan(f128_val))
965 "nans"
954966 else if (std.math.isInf(f128_val))
955967 "inf"
956968 else
......@@ -973,8 +985,13 @@ pub const DeclGen = struct {
973985 128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, f128_val)}),
974986 else => unreachable,
975987 };
988 try writer.writeAll(", ");
989 empty = false;
990
976991 }
977 return writer.print(", {x})", .{try dg.fmtIntLiteral(int_ty, int_val)});
992 try writer.print("{x}", .{try dg.fmtIntLiteralLoc(int_ty, int_val, location)});
993 if (!empty) try writer.writeByte(')');
994 return;
978995 },
979996 .Pointer => switch (val.tag()) {
980997 .null_value, .zero => if (ty.isSlice()) {
......@@ -995,7 +1012,7 @@ pub const DeclGen = struct {
9951012 return dg.renderDeclValue(writer, ty, val, decl);
9961013 },
9971014 .slice => {
998 if (location != .Initializer) {
1015 if (!location.isInitializer()) {
9991016 try writer.writeByte('(');
10001017 try dg.renderTypecast(writer, ty);
10011018 try writer.writeByte(')');
......@@ -1136,7 +1153,7 @@ pub const DeclGen = struct {
11361153 return dg.renderValue(writer, payload_ty, payload_val, location);
11371154 }
11381155
1139 if (location != .Initializer) {
1156 if (!location.isInitializer()) {
11401157 try writer.writeByte('(');
11411158 try dg.renderTypecast(writer, ty);
11421159 try writer.writeByte(')');
......@@ -1170,7 +1187,7 @@ pub const DeclGen = struct {
11701187 return dg.renderValue(writer, error_ty, val, location);
11711188 }
11721189
1173 if (location != .Initializer) {
1190 if (!location.isInitializer()) {
11741191 try writer.writeByte('(');
11751192 try dg.renderTypecast(writer, ty);
11761193 try writer.writeByte(')');
......@@ -1234,7 +1251,7 @@ pub const DeclGen = struct {
12341251 .Auto, .Extern => {
12351252 const field_vals = val.castTag(.aggregate).?.data;
12361253
1237 if (location != .Initializer) {
1254 if (!location.isInitializer()) {
12381255 try writer.writeByte('(');
12391256 try dg.renderTypecast(writer, ty);
12401257 try writer.writeByte(')');
......@@ -1247,7 +1264,10 @@ pub const DeclGen = struct {
12471264 if (!field_ty.hasRuntimeBits()) continue;
12481265
12491266 if (!empty) try writer.writeByte(',');
1250 try dg.renderValue(writer, field_ty, field_val, .Initializer);
1267 try dg.renderValue(writer, field_ty, field_val, switch (location) {
1268 .StaticInitializer => .StaticInitializer,
1269 else => .Initializer,
1270 });
12511271
12521272 empty = false;
12531273 }
......@@ -1345,7 +1365,7 @@ pub const DeclGen = struct {
13451365 .Union => {
13461366 const union_obj = val.castTag(.@"union").?.data;
13471367
1348 if (location != .Initializer) {
1368 if (!location.isInitializer()) {
13491369 try writer.writeByte('(');
13501370 try dg.renderTypecast(writer, ty);
13511371 try writer.writeByte(')');
......@@ -2561,6 +2581,24 @@ pub const DeclGen = struct {
25612581 .mod = dg.module,
25622582 } };
25632583 }
2584
2585 fn fmtIntLiteralLoc(
2586 dg: *DeclGen,
2587 ty: Type,
2588 val: Value,
2589 location: ValueRenderLocation, // TODO: Instead add this as optional arg to fmtIntLiteralLoc
2590 ) !std.fmt.Formatter(formatIntLiteral) {
2591 const int_info = ty.intInfo(dg.module.getTarget());
2592 const c_bits = toCIntBits(int_info.bits);
2593 if (c_bits == null or c_bits.? > 128)
2594 return dg.fail("TODO implement integer constants larger than 128 bits", .{});
2595 return std.fmt.Formatter(formatIntLiteral){ .data = .{
2596 .ty = ty,
2597 .val = val,
2598 .mod = dg.module,
2599 .location = location
2600 } };
2601 }
25642602};
25652603
25662604pub fn genGlobalAsm(mod: *Module, code: *std.ArrayList(u8)) !void {
......@@ -2606,7 +2644,7 @@ pub fn genErrDecls(o: *Object) !void {
26062644 try writer.writeAll("static ");
26072645 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0, .Complete);
26082646 try writer.writeAll(" = ");
2609 try o.dg.renderValue(writer, name_ty, name_val, .Initializer);
2647 try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer);
26102648 try writer.writeAll(";\n");
26112649 }
26122650
......@@ -2777,7 +2815,7 @@ pub fn genDecl(o: *Object) !void {
27772815 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
27782816 try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
27792817 try w.writeAll(" = ");
2780 try o.dg.renderValue(w, tv.ty, variable.init, .Initializer);
2818 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);
27812819 try w.writeByte(';');
27822820 try o.indent_writer.insertNewline();
27832821 } else {
......@@ -2794,7 +2832,7 @@ pub fn genDecl(o: *Object) !void {
27942832 // https://github.com/ziglang/zig/issues/7582
27952833 try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
27962834 try writer.writeAll(" = ");
2797 try o.dg.renderValue(writer, tv.ty, tv.val, .Initializer);
2835 try o.dg.renderValue(writer, tv.ty, tv.val, .StaticInitializer);
27982836 try writer.writeAll(";\n");
27992837 }
28002838}
......@@ -7027,7 +7065,7 @@ fn compilerRtAbbrev(ty: Type, target: std.Target) []const u8 {
70277065}
70287066
70297067fn StringLiteral(comptime WriterType: type) type {
7030 // msvc has a length limit of 16380 per string literal (before concatenation)
7068 // MSVC has a length limit of 16380 per string literal (before concatenation)
70317069 const max_char_len = 4;
70327070 const max_len = 16380 - max_char_len;
70337071
......@@ -7117,6 +7155,7 @@ const FormatIntLiteralContext = struct {
71177155 ty: Type,
71187156 val: Value,
71197157 mod: *Module,
7158 location: ?ValueRenderLocation = null
71207159};
71217160fn formatIntLiteral(
71227161 data: FormatIntLiteralContext,
......@@ -7188,6 +7227,7 @@ fn formatIntLiteral(
71887227 if (!int.positive) {
71897228 if (c_bits > 64) {
71907229 // TODO: Could use negate function instead?
7230 // TODO: Use fmtIntLiteral for 0?
71917231 try writer.print("zig_sub_{c}{d}(zig_as_{c}{d}(0, 0), ", .{ signAbbrev(int_info.signedness), c_bits, signAbbrev(int_info.signedness), c_bits });
71927232 } else {
71937233 try writer.writeByte('-');
......@@ -7196,7 +7236,14 @@ fn formatIntLiteral(
71967236
71977237 switch (data.ty.tag()) {
71987238 .c_short, .c_ushort, .c_int, .c_uint, .c_long, .c_ulong, .c_longlong, .c_ulonglong => {},
7199 else => try writer.print("zig_as_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits }),
7239 else => {
7240 if (int_info.bits > 64 and data.location != null and data.location.? == .StaticInitializer) {
7241 // MSVC treats casting the struct initializer as not constant (C2099), so an alternate form is used in global initializers
7242 try writer.print("zig_as_init_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });
7243 } else {
7244 try writer.print("zig_as_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });
7245 }
7246 }
72007247 }
72017248
72027249 const limbs_count_64 = @divExact(64, @bitSizeOf(BigIntLimb));