aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/c.zig
diff options
context:
space:
mode:
authorkcbanner <kcbanner@gmail.com>2022-12-13 01:19:21 -0500
committerkcbanner <kcbanner@gmail.com>2023-01-01 16:44:28 -0500
commit7fb3683c32fc24d12452f49e0c1639531e57c47d (patch)
tree0b9e38fd34be870ba2eb1e50147a58ec81709fd5 /src/codegen/c.zig
parent7f3bc45772d6af33e0e663ba534eba5653792843 (diff)
downloadzig-7fb3683c32fc24d12452f49e0c1639531e57c47d.tar.gz
zig-7fb3683c32fc24d12452f49e0c1639531e57c47d.zip
cbe: more msvc compatibility work
- Add .StaticInitializer to ValueRenderLocation to indicate that the emitted values must be constant expressions (no function calls, struct casting). - Add new path for special float types (nan, inf) that works in constant expressions - Implement windows.teb() using a syscall for .stage2_c because x64 MSVC doesn't support any kind of inline asm
Diffstat (limited to 'src/codegen/c.zig')
-rw-r--r--src/codegen/c.zig71
1 files changed, 42 insertions, 29 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 444e76c212..7bfa59ea41 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -711,6 +711,10 @@ pub const DeclGen = struct {
val = rt.data;
}
const target = dg.module.getTarget();
+ const initializer_type: ValueRenderLocation = switch (location) {
+ .StaticInitializer => .StaticInitializer,
+ else => .Initializer,
+ };
const safety_on = switch (dg.module.optimizeMode()) {
.Debug, .ReleaseSafe => true,
@@ -785,9 +789,9 @@ pub const DeclGen = struct {
}
try writer.writeAll("{ .payload = ");
- try dg.renderValue(writer, payload_ty, val, .Initializer);
+ try dg.renderValue(writer, payload_ty, val, initializer_type);
try writer.writeAll(", .is_null = ");
- try dg.renderValue(writer, Type.bool, val, .Initializer);
+ try dg.renderValue(writer, Type.bool, val, initializer_type);
return writer.writeAll(" }");
},
.Struct => switch (ty.containerLayout()) {
@@ -804,7 +808,7 @@ pub const DeclGen = struct {
if (!field.ty.hasRuntimeBits()) continue;
if (!empty) try writer.writeByte(',');
- try dg.renderValue(writer, field.ty, val, .Initializer);
+ try dg.renderValue(writer, field.ty, val, initializer_type);
empty = false;
}
@@ -825,14 +829,14 @@ pub const DeclGen = struct {
const layout = ty.unionGetLayout(target);
if (layout.tag_size != 0) {
try writer.writeAll(" .tag = ");
- try dg.renderValue(writer, tag_ty, val, .Initializer);
+ try dg.renderValue(writer, tag_ty, val, initializer_type);
try writer.writeByte(',');
}
try writer.writeAll(" .payload = {");
}
for (ty.unionFields().values()) |field| {
if (!field.ty.hasRuntimeBits()) continue;
- try dg.renderValue(writer, field.ty, val, .Initializer);
+ try dg.renderValue(writer, field.ty, val, initializer_type);
break;
} else try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)});
if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');
@@ -846,7 +850,7 @@ pub const DeclGen = struct {
}
try writer.writeAll("{ .payload = ");
- try dg.renderValue(writer, ty.errorUnionPayload(), val, .Initializer);
+ try dg.renderValue(writer, ty.errorUnionPayload(), val, initializer_type);
return writer.print(", .error = {x} }}", .{
try dg.fmtIntLiteral(ty.errorUnionSet(), val),
});
@@ -873,7 +877,7 @@ pub const DeclGen = struct {
var index: usize = 0;
while (index < c_len) : (index += 1) {
if (index > 0) try writer.writeAll(", ");
- try dg.renderValue(writer, ty.childType(), val, .Initializer);
+ try dg.renderValue(writer, ty.childType(), val, initializer_type);
}
return writer.writeByte('}');
}
@@ -957,7 +961,7 @@ pub const DeclGen = struct {
}
try writer.writeAll(", ");
empty = false;
- } else if (location != .StaticInitializer) {
+ } else {
// isSignalNan is equivalent to isNan currently, and MSVC doens't have nans, so prefer nan
const operation = if (std.math.isNan(f128_val))
"nan"
@@ -968,7 +972,19 @@ pub const DeclGen = struct {
else
unreachable;
+ if (location == .StaticInitializer) {
+ if (!std.math.isNan(f128_val) and std.math.isSignalNan(f128_val))
+ return dg.fail("TODO: C backend: implement nans rendering in static initializers", .{});
+
+ // MSVC doesn't have a way to define a custom or signaling NaN value in a constant expression
+
+ // TODO: Re-enable this check, otherwise we're writing qnan bit patterns on msvc incorrectly
+ // if (std.math.isNan(f128_val) and f128_val != std.math.qnan_f128)
+ // return dg.fail("Only quiet nans are supported in global variable initializers", .{});
+ }
+
try writer.writeAll("zig_as_special_");
+ if (location == .StaticInitializer) try writer.writeAll("constant_");
try dg.renderTypeForBuiltinFnName(writer, ty);
try writer.writeByte('(');
if (std.math.signbit(f128_val)) try writer.writeByte('-');
@@ -987,7 +1003,6 @@ pub const DeclGen = struct {
};
try writer.writeAll(", ");
empty = false;
-
}
try writer.print("{x}", .{try dg.fmtIntLiteralLoc(int_ty, int_val, location)});
if (!empty) try writer.writeByte(')');
@@ -1022,9 +1037,9 @@ pub const DeclGen = struct {
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
try writer.writeByte('{');
- try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, .Initializer);
+ try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, initializer_type);
try writer.writeAll(", ");
- try dg.renderValue(writer, Type.usize, slice.len, .Initializer);
+ try dg.renderValue(writer, Type.usize, slice.len, initializer_type);
try writer.writeByte('}');
},
.function => {
@@ -1062,7 +1077,7 @@ pub const DeclGen = struct {
try writer.writeByte('{');
const ai = ty.arrayInfo();
if (ai.sentinel) |s| {
- try dg.renderValue(writer, ai.elem_type, s, .Initializer);
+ try dg.renderValue(writer, ai.elem_type, s, initializer_type);
} else {
try writer.writeByte('0');
}
@@ -1085,6 +1100,7 @@ pub const DeclGen = struct {
// MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal
const max_string_initializer_len = 65535;
+
const ai = ty.arrayInfo();
if (ai.elem_type.eql(Type.u8, dg.module)) {
if (ai.len <= max_string_initializer_len) {
@@ -1112,7 +1128,7 @@ pub const DeclGen = struct {
}
if (ai.sentinel) |s| {
if (index != 0) try writer.writeByte(',');
- try dg.renderValue(writer, ai.elem_type, s, .Initializer);
+ try dg.renderValue(writer, ai.elem_type, s, initializer_type);
}
try writer.writeByte('}');
}
@@ -1122,11 +1138,11 @@ pub const DeclGen = struct {
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, .Initializer);
+ try dg.renderValue(writer, ai.elem_type, elem_val, initializer_type);
}
if (ai.sentinel) |s| {
if (index != 0) try writer.writeByte(',');
- try dg.renderValue(writer, ai.elem_type, s, .Initializer);
+ try dg.renderValue(writer, ai.elem_type, s, initializer_type);
}
try writer.writeByte('}');
}
@@ -1162,9 +1178,9 @@ pub const DeclGen = struct {
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 dg.renderValue(writer, payload_ty, payload_val, initializer_type);
try writer.writeAll(", .is_null = ");
- try dg.renderValue(writer, Type.bool, is_null_val, .Initializer);
+ try dg.renderValue(writer, Type.bool, is_null_val, initializer_type);
try writer.writeAll(" }");
},
.ErrorSet => {
@@ -1197,9 +1213,9 @@ pub const DeclGen = struct {
const error_val = if (val.errorUnionIsPayload()) Value.zero else val;
try writer.writeAll("{ .payload = ");
- try dg.renderValue(writer, payload_ty, payload_val, .Initializer);
+ try dg.renderValue(writer, payload_ty, payload_val, initializer_type);
try writer.writeAll(", .error = ");
- try dg.renderValue(writer, error_ty, error_val, .Initializer);
+ try dg.renderValue(writer, error_ty, error_val, initializer_type);
try writer.writeAll(" }");
},
.Enum => {
@@ -1264,10 +1280,7 @@ pub const DeclGen = struct {
if (!field_ty.hasRuntimeBits()) continue;
if (!empty) try writer.writeByte(',');
- try dg.renderValue(writer, field_ty, field_val, switch (location) {
- .StaticInitializer => .StaticInitializer,
- else => .Initializer,
- });
+ try dg.renderValue(writer, field_ty, field_val, initializer_type);
empty = false;
}
@@ -1297,7 +1310,7 @@ pub const DeclGen = struct {
if (eff_num_fields == 0) {
try writer.writeByte('(');
- try dg.renderValue(writer, ty, Value.undef, .Initializer);
+ try dg.renderValue(writer, ty, Value.undef, initializer_type);
try writer.writeByte(')');
} 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))
@@ -1385,7 +1398,7 @@ pub const DeclGen = struct {
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
}
- try dg.renderValue(writer, field_ty, union_obj.val, .Initializer);
+ try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);
} else {
try writer.writeAll("0");
}
@@ -1397,7 +1410,7 @@ pub const DeclGen = struct {
const layout = ty.unionGetLayout(target);
if (layout.tag_size != 0) {
try writer.writeAll(".tag = ");
- try dg.renderValue(writer, tag_ty, union_obj.tag, .Initializer);
+ try dg.renderValue(writer, tag_ty, union_obj.tag, initializer_type);
try writer.writeAll(", ");
}
try writer.writeAll(".payload = {");
@@ -1406,11 +1419,11 @@ pub const DeclGen = struct {
var it = ty.unionFields().iterator();
if (field_ty.hasRuntimeBits()) {
try writer.print(".{ } = ", .{fmtIdent(field_name)});
- try dg.renderValue(writer, field_ty, union_obj.val, .Initializer);
+ try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);
} else while (it.next()) |field| {
if (!field.value_ptr.ty.hasRuntimeBits()) continue;
try writer.print(".{ } = ", .{fmtIdent(field.key_ptr.*)});
- try dg.renderValue(writer, field.value_ptr.ty, Value.undef, .Initializer);
+ try dg.renderValue(writer, field.value_ptr.ty, Value.undef, initializer_type);
break;
} else try writer.writeAll(".empty_union = 0");
if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');
@@ -7239,7 +7252,7 @@ fn formatIntLiteral(
else => {
if (int_info.bits > 64 and data.location != null and data.location.? == .StaticInitializer) {
// MSVC treats casting the struct initializer as not constant (C2099), so an alternate form is used in global initializers
- try writer.print("zig_as_init_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });
+ try writer.print("zig_as_constant_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });
} else {
try writer.print("zig_as_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });
}