aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/c.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-05-26 20:21:17 -0700
committerAndrew Kelley <andrew@ziglang.org>2023-06-10 20:47:56 -0700
commitfc358435cb5cbcc21967af438b190d4e18bba9ae (patch)
tree4f5fcbc488a55bb954bec3fbd4d81c172a372478 /src/codegen/c.zig
parenta596ea683c35d90c6af3e1fbeae2e06312ce392f (diff)
downloadzig-fc358435cb5cbcc21967af438b190d4e18bba9ae.tar.gz
zig-fc358435cb5cbcc21967af438b190d4e18bba9ae.zip
C backend: InternPool fixes
Diffstat (limited to 'src/codegen/c.zig')
-rw-r--r--src/codegen/c.zig295
1 files changed, 172 insertions, 123 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 0c5e6e6c48..a8e2077652 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -1110,14 +1110,16 @@ pub const DeclGen = struct {
.undef, .runtime_value => unreachable, // handled above
.simple_value => |simple_value| switch (simple_value) {
- .undefined,
- .void,
- .null,
- .empty_struct,
- .@"unreachable",
- .generic_poison,
- => unreachable, // non-runtime values
- .false, .true => try writer.writeAll(@tagName(simple_value)),
+ // non-runtime values
+ .undefined => unreachable,
+ .void => unreachable,
+ .null => unreachable,
+ .empty_struct => unreachable,
+ .@"unreachable" => unreachable,
+ .generic_poison => unreachable,
+
+ .false => try writer.writeAll("false"),
+ .true => try writer.writeAll("true"),
},
.variable,
.extern_func,
@@ -1138,10 +1140,10 @@ pub const DeclGen = struct {
.error_union => |error_union| {
const payload_ty = ty.errorUnionPayload(mod);
const error_ty = ty.errorUnionSet(mod);
- const error_val = if (val.errorUnionIsPayload(mod)) try mod.intValue(Type.anyerror, 0) else val;
+ const error_val = if (val.errorUnionIsPayload(mod)) try mod.intValue(Type.err_int, 0) else val;
if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
- return dg.renderValue(writer, error_ty, error_val, location);
+ return dg.renderValue(writer, Type.err_int, error_val, location);
}
if (!location.isInitializer()) {
@@ -1305,12 +1307,10 @@ pub const DeclGen = struct {
if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod))
return dg.renderValue(writer, Type.bool, is_null_val, location);
- if (ty.optionalReprIsPayload(mod)) {
- return dg.renderValue(writer, payload_ty, switch (opt.val) {
- .none => try mod.intValue(payload_ty, 0),
- else => opt.val.toValue(),
- }, location);
- }
+ if (ty.optionalReprIsPayload(mod)) switch (opt.val) {
+ .none => return writer.writeByte('0'),
+ else => return dg.renderValue(writer, payload_ty, opt.val.toValue(), location),
+ };
if (!location.isInitializer()) {
try writer.writeByte('(');
@@ -1327,7 +1327,7 @@ pub const DeclGen = struct {
try dg.renderValue(writer, Type.bool, is_null_val, initializer_type);
try writer.writeAll(" }");
},
- .aggregate => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
+ .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.ip_index)) {
.array_type, .vector_type => {
if (location == .FunctionArgument) {
try writer.writeByte('(');
@@ -1385,131 +1385,179 @@ pub const DeclGen = struct {
try writer.writeByte('}');
}
},
- .struct_type, .anon_struct_type => switch (ty.containerLayout(mod)) {
- .Auto, .Extern => {
- const field_vals = val.castTag(.aggregate).?.data;
-
- if (!location.isInitializer()) {
- try writer.writeByte('(');
- try dg.renderType(writer, ty);
- try writer.writeByte(')');
- }
-
- try writer.writeByte('{');
- var empty = true;
- for (field_vals, 0..) |field_val, field_i| {
- if (ty.structFieldIsComptime(field_i, mod)) continue;
- const field_ty = ty.structFieldType(field_i, mod);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
-
- if (!empty) try writer.writeByte(',');
- try dg.renderValue(writer, field_ty, field_val, initializer_type);
+ .anon_struct_type => |tuple| {
+ if (!location.isInitializer()) {
+ try writer.writeByte('(');
+ try dg.renderType(writer, ty);
+ try writer.writeByte(')');
+ }
- empty = false;
- }
- try writer.writeByte('}');
- },
- .Packed => {
- const field_vals = val.castTag(.aggregate).?.data;
- const int_info = ty.intInfo(mod);
+ try writer.writeByte('{');
+ var empty = true;
+ for (tuple.types, tuple.values, 0..) |field_ty, comptime_ty, field_i| {
+ if (comptime_ty != .none) continue;
+ if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
- const bits = Type.smallestUnsignedBits(int_info.bits - 1);
- const bit_offset_ty = try mod.intType(.unsigned, bits);
+ if (!empty) try writer.writeByte(',');
- var bit_offset: u64 = 0;
+ const field_val = switch (aggregate.storage) {
+ .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{
+ .ty = field_ty,
+ .storage = .{ .u64 = bytes[field_i] },
+ } }),
+ .elems => |elems| elems[field_i],
+ .repeated_elem => |elem| elem,
+ };
+ try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), initializer_type);
- var eff_num_fields: usize = 0;
- for (0..field_vals.len) |field_i| {
- if (ty.structFieldIsComptime(field_i, mod)) continue;
- const field_ty = ty.structFieldType(field_i, mod);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
+ empty = false;
+ }
+ try writer.writeByte('}');
+ },
+ .struct_type => |struct_type| {
+ const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
+ switch (struct_obj.layout) {
+ .Auto, .Extern => {
+ if (!location.isInitializer()) {
+ try writer.writeByte('(');
+ try dg.renderType(writer, ty);
+ try writer.writeByte(')');
+ }
- eff_num_fields += 1;
- }
+ try writer.writeByte('{');
+ var empty = true;
+ for (struct_obj.fields.values(), 0..) |field, field_i| {
+ if (field.is_comptime) continue;
+ if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
+
+ if (!empty) try writer.writeByte(',');
+ const field_val = switch (aggregate.storage) {
+ .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{
+ .ty = field.ty.toIntern(),
+ .storage = .{ .u64 = bytes[field_i] },
+ } }),
+ .elems => |elems| elems[field_i],
+ .repeated_elem => |elem| elem,
+ };
+ try dg.renderValue(writer, field.ty, field_val.toValue(), initializer_type);
- if (eff_num_fields == 0) {
- try writer.writeByte('(');
- try dg.renderValue(writer, ty, Value.undef, initializer_type);
- try writer.writeByte(')');
- } else if (ty.bitSize(mod) > 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('(');
+ empty = false;
}
+ try writer.writeByte('}');
+ },
+ .Packed => {
+ const int_info = ty.intInfo(mod);
- var eff_index: usize = 0;
- var needs_closing_paren = false;
- for (field_vals, 0..) |field_val, field_i| {
- if (ty.structFieldIsComptime(field_i, mod)) continue;
- const field_ty = ty.structFieldType(field_i, mod);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
+ const bits = Type.smallestUnsignedBits(int_info.bits - 1);
+ const bit_offset_ty = try mod.intType(.unsigned, bits);
- const cast_context = IntCastContext{ .value = .{ .value = field_val } };
- if (bit_offset != 0) {
- try writer.writeAll("zig_shl_");
- try dg.renderTypeForBuiltinFnName(writer, ty);
- try writer.writeByte('(');
- try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
- try writer.writeAll(", ");
- const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
- try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
- try writer.writeByte(')');
- } else {
- try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
- }
+ var bit_offset: u64 = 0;
+ var eff_num_fields: usize = 0;
- if (needs_closing_paren) try writer.writeByte(')');
- if (eff_index != eff_num_fields - 1) try writer.writeAll(", ");
+ for (struct_obj.fields.values()) |field| {
+ if (field.is_comptime) continue;
+ if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
- bit_offset += field_ty.bitSize(mod);
- needs_closing_paren = true;
- eff_index += 1;
+ eff_num_fields += 1;
}
- } else {
- try writer.writeByte('(');
- // a << a_off | b << b_off | c << c_off
- var empty = true;
- for (field_vals, 0..) |field_val, field_i| {
- if (ty.structFieldIsComptime(field_i, mod)) continue;
- const field_ty = ty.structFieldType(field_i, mod);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
- if (!empty) try writer.writeAll(" | ");
+ if (eff_num_fields == 0) {
try writer.writeByte('(');
- try dg.renderType(writer, ty);
+ try dg.renderValue(writer, ty, Value.undef, initializer_type);
try writer.writeByte(')');
+ } else if (ty.bitSize(mod) > 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('(');
+ }
- if (bit_offset != 0) {
- try dg.renderValue(writer, field_ty, field_val, .Other);
- try writer.writeAll(" << ");
- const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
- try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
- } else {
- try dg.renderValue(writer, field_ty, field_val, .Other);
+ var eff_index: usize = 0;
+ var needs_closing_paren = false;
+ for (struct_obj.fields.values(), 0..) |field, field_i| {
+ if (field.is_comptime) continue;
+ if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
+
+ const field_val = switch (aggregate.storage) {
+ .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{
+ .ty = field.ty.toIntern(),
+ .storage = .{ .u64 = bytes[field_i] },
+ } }),
+ .elems => |elems| elems[field_i],
+ .repeated_elem => |elem| elem,
+ };
+ const cast_context = IntCastContext{ .value = .{ .value = field_val.toValue() } };
+ if (bit_offset != 0) {
+ try writer.writeAll("zig_shl_");
+ try dg.renderTypeForBuiltinFnName(writer, ty);
+ try writer.writeByte('(');
+ try dg.renderIntCast(writer, ty, cast_context, field.ty, .FunctionArgument);
+ try writer.writeAll(", ");
+ const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
+ try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
+ try writer.writeByte(')');
+ } else {
+ 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 += field.ty.bitSize(mod);
+ needs_closing_paren = true;
+ eff_index += 1;
}
+ } else {
+ try writer.writeByte('(');
+ // a << a_off | b << b_off | c << c_off
+ var empty = true;
+ for (struct_obj.fields.values(), 0..) |field, field_i| {
+ if (field.is_comptime) continue;
+ if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
- bit_offset += field_ty.bitSize(mod);
- empty = false;
+ if (!empty) try writer.writeAll(" | ");
+ try writer.writeByte('(');
+ try dg.renderType(writer, ty);
+ try writer.writeByte(')');
+
+ const field_val = switch (aggregate.storage) {
+ .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{
+ .ty = field.ty.toIntern(),
+ .storage = .{ .u64 = bytes[field_i] },
+ } }),
+ .elems => |elems| elems[field_i],
+ .repeated_elem => |elem| elem,
+ };
+
+ if (bit_offset != 0) {
+ try dg.renderValue(writer, field.ty, field_val.toValue(), .Other);
+ try writer.writeAll(" << ");
+ const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
+ try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
+ } else {
+ try dg.renderValue(writer, field.ty, field_val.toValue(), .Other);
+ }
+
+ bit_offset += field.ty.bitSize(mod);
+ empty = false;
+ }
+ try writer.writeByte(')');
}
- try writer.writeByte(')');
- }
- },
+ },
+ }
},
else => unreachable,
},
- .un => {
- const union_obj = val.castTag(.@"union").?.data;
-
+ .un => |un| {
if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderType(writer, ty);
try writer.writeByte(')');
}
- const field_i = ty.unionTagFieldIndex(union_obj.tag, mod).?;
+ const field_i = ty.unionTagFieldIndex(un.tag.toValue(), mod).?;
const field_ty = ty.unionFields(mod).values()[field_i].ty;
const field_name = ty.unionFields(mod).keys()[field_i];
if (ty.containerLayout(mod) == .Packed) {
@@ -1523,7 +1571,7 @@ pub const DeclGen = struct {
try dg.renderType(writer, ty);
try writer.writeByte(')');
}
- try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);
+ try dg.renderValue(writer, field_ty, un.val.toValue(), initializer_type);
} else {
try writer.writeAll("0");
}
@@ -1535,7 +1583,7 @@ pub const DeclGen = struct {
const layout = ty.unionGetLayout(mod);
if (layout.tag_size != 0) {
try writer.writeAll(" .tag = ");
- try dg.renderValue(writer, tag_ty, union_obj.tag, initializer_type);
+ try dg.renderValue(writer, tag_ty, un.tag.toValue(), initializer_type);
}
if (ty.unionHasAllZeroBitFieldTypes(mod)) return try writer.writeByte('}');
if (layout.tag_size != 0) try writer.writeByte(',');
@@ -1543,7 +1591,7 @@ pub const DeclGen = struct {
}
if (field_ty.hasRuntimeBits(mod)) {
try writer.print(" .{ } = ", .{fmtIdent(field_name)});
- try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);
+ try dg.renderValue(writer, field_ty, un.val.toValue(), initializer_type);
try writer.writeByte(' ');
} else for (ty.unionFields(mod).values()) |field| {
if (!field.ty.hasRuntimeBits(mod)) continue;
@@ -5113,13 +5161,14 @@ fn airIsNull(
TypedValue{ .ty = Type.bool, .val = Value.true }
else if (optional_ty.isPtrLikeOptional(mod))
// operand is a regular pointer, test `operand !=/== NULL`
- TypedValue{ .ty = optional_ty, .val = Value.null }
+ TypedValue{ .ty = optional_ty, .val = try mod.nullValue(optional_ty) }
else if (payload_ty.zigTypeTag(mod) == .ErrorSet)
- TypedValue{ .ty = payload_ty, .val = try mod.intValue(payload_ty, 0) }
+ TypedValue{ .ty = Type.err_int, .val = try mod.intValue(Type.err_int, 0) }
else if (payload_ty.isSlice(mod) and optional_ty.optionalReprIsPayload(mod)) rhs: {
try writer.writeAll(".ptr");
const slice_ptr_ty = payload_ty.slicePtrFieldType(mod);
- break :rhs TypedValue{ .ty = slice_ptr_ty, .val = Value.null };
+ const opt_slice_ptr_ty = try mod.optionalType(slice_ptr_ty.toIntern());
+ break :rhs TypedValue{ .ty = opt_slice_ptr_ty, .val = try mod.nullValue(opt_slice_ptr_ty) };
} else rhs: {
try writer.writeAll(".is_null");
break :rhs TypedValue{ .ty = Type.bool, .val = Value.true };
@@ -5781,7 +5830,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
else
try f.writeCValueMember(writer, local, .{ .identifier = "error" });
try a.assign(f, writer);
- try f.object.dg.renderValue(writer, err_ty, try mod.intValue(err_ty, 0), .Other);
+ try f.object.dg.renderValue(writer, Type.err_int, try mod.intValue(Type.err_int, 0), .Other);
try a.end(f, writer);
}
return local;
@@ -5812,11 +5861,11 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
else
try f.writeCValue(writer, operand, .Other)
else
- try f.object.dg.renderValue(writer, error_ty, try mod.intValue(error_ty, 0), .Other);
+ try f.object.dg.renderValue(writer, Type.err_int, try mod.intValue(Type.err_int, 0), .Other);
try writer.writeByte(' ');
try writer.writeAll(operator);
try writer.writeByte(' ');
- try f.object.dg.renderValue(writer, error_ty, try mod.intValue(error_ty, 0), .Other);
+ try f.object.dg.renderValue(writer, Type.err_int, try mod.intValue(Type.err_int, 0), .Other);
try writer.writeAll(";\n");
return local;
}