aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/c.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen/c.zig')
-rw-r--r--src/codegen/c.zig95
1 files changed, 71 insertions, 24 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 8f26141d7a..444e76c212 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -90,7 +90,15 @@ const FormatTypeAsCIdentContext = struct {
const ValueRenderLocation = enum {
FunctionArgument,
Initializer,
+ StaticInitializer,
Other,
+
+ pub fn isInitializer(self: ValueRenderLocation) bool {
+ return switch (self) {
+ .Initializer, .StaticInitializer => true,
+ else => false,
+ };
+ }
};
const BuiltinInfo = enum {
@@ -718,7 +726,7 @@ pub const DeclGen = struct {
return writer.writeAll("false");
}
},
- .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, val)}),
+ .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteralLoc(ty, val, location)}),
.Float => {
const bits = ty.floatBits(target);
var int_pl = Type.Payload.Bits{ .base = .{ .tag = .int_signed }, .data = bits };
@@ -742,7 +750,7 @@ pub const DeclGen = struct {
return writer.writeByte(')');
},
.Pointer => if (ty.isSlice()) {
- if (location != .Initializer) {
+ if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
@@ -770,7 +778,7 @@ pub const DeclGen = struct {
return dg.renderValue(writer, payload_ty, val, location);
}
- if (location != .Initializer) {
+ if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
@@ -784,7 +792,7 @@ pub const DeclGen = struct {
},
.Struct => switch (ty.containerLayout()) {
.Auto, .Extern => {
- if (location != .Initializer) {
+ if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
@@ -806,7 +814,7 @@ pub const DeclGen = struct {
.Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}),
},
.Union => {
- if (location != .Initializer) {
+ if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
@@ -831,7 +839,7 @@ pub const DeclGen = struct {
return writer.writeByte('}');
},
.ErrorUnion => {
- if (location != .Initializer) {
+ if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
@@ -844,7 +852,7 @@ pub const DeclGen = struct {
});
},
.Array, .Vector => {
- if (location != .Initializer) {
+ if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
@@ -899,7 +907,7 @@ pub const DeclGen = struct {
.decl_ref_mut,
.decl_ref,
=> try dg.renderParentPtr(writer, val, ty),
- else => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val)}),
+ else => try writer.print("{}", .{try dg.fmtIntLiteralLoc(ty, val, location)}),
},
.Float => {
const bits = ty.floatBits(target);
@@ -934,6 +942,7 @@ pub const DeclGen = struct {
try writer.writeAll("zig_cast_");
try dg.renderTypeForBuiltinFnName(writer, ty);
try writer.writeByte(' ');
+ var empty = true;
if (std.math.isFinite(f128_val)) {
try writer.writeAll("zig_as_");
try dg.renderTypeForBuiltinFnName(writer, ty);
@@ -946,11 +955,14 @@ pub const DeclGen = struct {
128 => try writer.print("{x}", .{f128_val}),
else => unreachable,
}
- } else {
- const operation = if (std.math.isSignalNan(f128_val))
- "nans"
- else if (std.math.isNan(f128_val))
+ try writer.writeAll(", ");
+ empty = false;
+ } else if (location != .StaticInitializer) {
+ // isSignalNan is equivalent to isNan currently, and MSVC doens't have nans, so prefer nan
+ const operation = if (std.math.isNan(f128_val))
"nan"
+ else if (std.math.isSignalNan(f128_val))
+ "nans"
else if (std.math.isInf(f128_val))
"inf"
else
@@ -973,8 +985,13 @@ pub const DeclGen = struct {
128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, f128_val)}),
else => unreachable,
};
+ try writer.writeAll(", ");
+ empty = false;
+
}
- return writer.print(", {x})", .{try dg.fmtIntLiteral(int_ty, int_val)});
+ try writer.print("{x}", .{try dg.fmtIntLiteralLoc(int_ty, int_val, location)});
+ if (!empty) try writer.writeByte(')');
+ return;
},
.Pointer => switch (val.tag()) {
.null_value, .zero => if (ty.isSlice()) {
@@ -995,7 +1012,7 @@ pub const DeclGen = struct {
return dg.renderDeclValue(writer, ty, val, decl);
},
.slice => {
- if (location != .Initializer) {
+ if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
@@ -1136,7 +1153,7 @@ pub const DeclGen = struct {
return dg.renderValue(writer, payload_ty, payload_val, location);
}
- if (location != .Initializer) {
+ if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
@@ -1170,7 +1187,7 @@ pub const DeclGen = struct {
return dg.renderValue(writer, error_ty, val, location);
}
- if (location != .Initializer) {
+ if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
@@ -1234,7 +1251,7 @@ pub const DeclGen = struct {
.Auto, .Extern => {
const field_vals = val.castTag(.aggregate).?.data;
- if (location != .Initializer) {
+ if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
@@ -1247,7 +1264,10 @@ pub const DeclGen = struct {
if (!field_ty.hasRuntimeBits()) continue;
if (!empty) try writer.writeByte(',');
- try dg.renderValue(writer, field_ty, field_val, .Initializer);
+ try dg.renderValue(writer, field_ty, field_val, switch (location) {
+ .StaticInitializer => .StaticInitializer,
+ else => .Initializer,
+ });
empty = false;
}
@@ -1345,7 +1365,7 @@ pub const DeclGen = struct {
.Union => {
const union_obj = val.castTag(.@"union").?.data;
- if (location != .Initializer) {
+ if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
@@ -2561,6 +2581,24 @@ pub const DeclGen = struct {
.mod = dg.module,
} };
}
+
+ fn fmtIntLiteralLoc(
+ dg: *DeclGen,
+ ty: Type,
+ val: Value,
+ location: ValueRenderLocation, // TODO: Instead add this as optional arg to fmtIntLiteralLoc
+ ) !std.fmt.Formatter(formatIntLiteral) {
+ const int_info = ty.intInfo(dg.module.getTarget());
+ const c_bits = toCIntBits(int_info.bits);
+ if (c_bits == null or c_bits.? > 128)
+ return dg.fail("TODO implement integer constants larger than 128 bits", .{});
+ return std.fmt.Formatter(formatIntLiteral){ .data = .{
+ .ty = ty,
+ .val = val,
+ .mod = dg.module,
+ .location = location
+ } };
+ }
};
pub fn genGlobalAsm(mod: *Module, code: *std.ArrayList(u8)) !void {
@@ -2606,7 +2644,7 @@ pub fn genErrDecls(o: *Object) !void {
try writer.writeAll("static ");
try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0, .Complete);
try writer.writeAll(" = ");
- try o.dg.renderValue(writer, name_ty, name_val, .Initializer);
+ try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer);
try writer.writeAll(";\n");
}
@@ -2777,7 +2815,7 @@ pub fn genDecl(o: *Object) !void {
if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
try w.writeAll(" = ");
- try o.dg.renderValue(w, tv.ty, variable.init, .Initializer);
+ try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);
try w.writeByte(';');
try o.indent_writer.insertNewline();
} else {
@@ -2794,7 +2832,7 @@ pub fn genDecl(o: *Object) !void {
// https://github.com/ziglang/zig/issues/7582
try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
try writer.writeAll(" = ");
- try o.dg.renderValue(writer, tv.ty, tv.val, .Initializer);
+ try o.dg.renderValue(writer, tv.ty, tv.val, .StaticInitializer);
try writer.writeAll(";\n");
}
}
@@ -7027,7 +7065,7 @@ fn compilerRtAbbrev(ty: Type, target: std.Target) []const u8 {
}
fn StringLiteral(comptime WriterType: type) type {
- // msvc has a length limit of 16380 per string literal (before concatenation)
+ // MSVC has a length limit of 16380 per string literal (before concatenation)
const max_char_len = 4;
const max_len = 16380 - max_char_len;
@@ -7117,6 +7155,7 @@ const FormatIntLiteralContext = struct {
ty: Type,
val: Value,
mod: *Module,
+ location: ?ValueRenderLocation = null
};
fn formatIntLiteral(
data: FormatIntLiteralContext,
@@ -7188,6 +7227,7 @@ fn formatIntLiteral(
if (!int.positive) {
if (c_bits > 64) {
// TODO: Could use negate function instead?
+ // TODO: Use fmtIntLiteral for 0?
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 });
} else {
try writer.writeByte('-');
@@ -7196,7 +7236,14 @@ fn formatIntLiteral(
switch (data.ty.tag()) {
.c_short, .c_ushort, .c_int, .c_uint, .c_long, .c_ulong, .c_longlong, .c_ulonglong => {},
- else => try writer.print("zig_as_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits }),
+ 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 });
+ } else {
+ try writer.print("zig_as_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });
+ }
+ }
}
const limbs_count_64 = @divExact(64, @bitSizeOf(BigIntLimb));