compiler: move unions into InternPool

There are a couple concepts here worth understanding:

Key.UnionType - This type is available *before* resolving the union's
fields. The enum tag type, number of fields, and field names, field
types, and field alignments are not available with this.

InternPool.UnionType - This one can be obtained from the above type with
`InternPool.loadUnionType` which asserts that the union's enum tag type
has been resolved. This one has all the information available.

Additionally:

* ZIR: Turn an unused bit into `any_aligned_fields` flag to help
  semantic analysis know whether a union has explicit alignment on any
  fields (usually not).
* Sema: delete `resolveTypeRequiresComptime` which had the same type
  signature and near-duplicate logic to `typeRequiresComptime`.
  - Make opaque types not report comptime-only (this was inconsistent
    between the two implementations of this function).
* Implement accepted proposal #12556 which is a breaking change.
This commit is contained in:
Andrew Kelley
2023-08-21 14:27:34 -07:00
parent 6a5463951f
commit ada0010471
27 changed files with 1478 additions and 1440 deletions

View File

@@ -708,8 +708,10 @@ pub const DeclGen = struct {
location: ValueRenderLocation,
) error{ OutOfMemory, AnalysisFail }!void {
const mod = dg.module;
const ip = &mod.intern_pool;
var val = arg_val;
switch (mod.intern_pool.indexToKey(val.ip_index)) {
switch (ip.indexToKey(val.ip_index)) {
.runtime_value => |rt| val = rt.val.toValue(),
else => {},
}
@@ -836,9 +838,10 @@ pub const DeclGen = struct {
if (layout.tag_size != 0) try writer.writeByte(',');
try writer.writeAll(" .payload = {");
}
for (ty.unionFields(mod).values()) |field| {
if (!field.ty.hasRuntimeBits(mod)) continue;
try dg.renderValue(writer, field.ty, val, initializer_type);
const union_obj = mod.typeToUnion(ty).?;
for (union_obj.field_types.get(ip)) |field_ty| {
if (!field_ty.toType().hasRuntimeBits(mod)) continue;
try dg.renderValue(writer, field_ty.toType(), val, initializer_type);
break;
}
if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}');
@@ -912,7 +915,7 @@ pub const DeclGen = struct {
unreachable;
}
switch (mod.intern_pool.indexToKey(val.ip_index)) {
switch (ip.indexToKey(val.ip_index)) {
// types, not values
.int_type,
.ptr_type,
@@ -962,7 +965,7 @@ pub const DeclGen = struct {
},
},
.err => |err| try writer.print("zig_error_{}", .{
fmtIdent(mod.intern_pool.stringToSlice(err.name)),
fmtIdent(ip.stringToSlice(err.name)),
}),
.error_union => |error_union| {
const payload_ty = ty.errorUnionPayload(mod);
@@ -1024,8 +1027,8 @@ pub const DeclGen = struct {
try writer.writeAll(" }");
},
.enum_tag => {
const enum_tag = mod.intern_pool.indexToKey(val.ip_index).enum_tag;
const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int);
const enum_tag = ip.indexToKey(val.ip_index).enum_tag;
const int_tag_ty = ip.typeOf(enum_tag.int);
try dg.renderValue(writer, int_tag_ty.toType(), enum_tag.int.toValue(), location);
},
.float => {
@@ -1205,7 +1208,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 => switch (ip.indexToKey(ty.ip_index)) {
.array_type, .vector_type => {
if (location == .FunctionArgument) {
try writer.writeByte('(');
@@ -1278,8 +1281,8 @@ pub const DeclGen = struct {
if (!empty) try writer.writeByte(',');
const field_val = switch (mod.intern_pool.indexToKey(val.ip_index).aggregate.storage) {
.bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{
const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
.bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
.ty = field_ty,
.storage = .{ .u64 = bytes[field_i] },
} }),
@@ -1309,8 +1312,8 @@ pub const DeclGen = struct {
if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
if (!empty) try writer.writeByte(',');
const field_val = switch (mod.intern_pool.indexToKey(val.ip_index).aggregate.storage) {
.bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{
const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
.bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
.ty = field.ty.toIntern(),
.storage = .{ .u64 = bytes[field_i] },
} }),
@@ -1358,8 +1361,8 @@ pub const DeclGen = struct {
if (field.is_comptime) continue;
if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
const field_val = switch (mod.intern_pool.indexToKey(val.ip_index).aggregate.storage) {
.bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{
const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
.bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
.ty = field.ty.toIntern(),
.storage = .{ .u64 = bytes[field_i] },
} }),
@@ -1400,8 +1403,8 @@ pub const DeclGen = struct {
try dg.renderType(writer, ty);
try writer.writeByte(')');
const field_val = switch (mod.intern_pool.indexToKey(val.ip_index).aggregate.storage) {
.bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{
const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
.bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
.ty = field.ty.toIntern(),
.storage = .{ .u64 = bytes[field_i] },
} }),
@@ -1435,10 +1438,11 @@ pub const DeclGen = struct {
try writer.writeByte(')');
}
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) {
const union_obj = mod.typeToUnion(ty).?;
const field_i = mod.unionTagFieldIndex(union_obj, un.tag.toValue()).?;
const field_ty = union_obj.field_types.get(ip)[field_i].toType();
const field_name = union_obj.field_names.get(ip)[field_i];
if (union_obj.getLayout(ip) == .Packed) {
if (field_ty.hasRuntimeBits(mod)) {
if (field_ty.isPtrAtRuntime(mod)) {
try writer.writeByte('(');
@@ -1458,7 +1462,7 @@ pub const DeclGen = struct {
try writer.writeByte('{');
if (ty.unionTagTypeSafety(mod)) |tag_ty| {
const layout = ty.unionGetLayout(mod);
const layout = mod.getUnionLayout(union_obj);
if (layout.tag_size != 0) {
try writer.writeAll(" .tag = ");
try dg.renderValue(writer, tag_ty, un.tag.toValue(), initializer_type);
@@ -1468,12 +1472,12 @@ pub const DeclGen = struct {
try writer.writeAll(" .payload = {");
}
if (field_ty.hasRuntimeBits(mod)) {
try writer.print(" .{ } = ", .{fmtIdent(mod.intern_pool.stringToSlice(field_name))});
try writer.print(" .{ } = ", .{fmtIdent(ip.stringToSlice(field_name))});
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;
try dg.renderValue(writer, field.ty, Value.undef, initializer_type);
} else for (union_obj.field_types.get(ip)) |this_field_ty| {
if (!this_field_ty.toType().hasRuntimeBits(mod)) continue;
try dg.renderValue(writer, this_field_ty.toType(), Value.undef, initializer_type);
break;
}
if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}');
@@ -5237,22 +5241,25 @@ fn fieldLocation(
else
.begin,
},
.Union => switch (container_ty.containerLayout(mod)) {
.Auto, .Extern => {
const field_ty = container_ty.structFieldType(field_index, mod);
if (!field_ty.hasRuntimeBitsIgnoreComptime(mod))
return if (container_ty.unionTagTypeSafety(mod) != null and
!container_ty.unionHasAllZeroBitFieldTypes(mod))
.{ .field = .{ .identifier = "payload" } }
.Union => {
const union_obj = mod.typeToUnion(container_ty).?;
return switch (union_obj.getLayout(ip)) {
.Auto, .Extern => {
const field_ty = union_obj.field_types.get(ip)[field_index].toType();
if (!field_ty.hasRuntimeBitsIgnoreComptime(mod))
return if (container_ty.unionTagTypeSafety(mod) != null and
!container_ty.unionHasAllZeroBitFieldTypes(mod))
.{ .field = .{ .identifier = "payload" } }
else
.begin;
const field_name = union_obj.field_names.get(ip)[field_index];
return .{ .field = if (container_ty.unionTagTypeSafety(mod)) |_|
.{ .payload_identifier = ip.stringToSlice(field_name) }
else
.begin;
const field_name = container_ty.unionFields(mod).keys()[field_index];
return .{ .field = if (container_ty.unionTagTypeSafety(mod)) |_|
.{ .payload_identifier = ip.stringToSlice(field_name) }
else
.{ .identifier = ip.stringToSlice(field_name) } };
},
.Packed => .begin,
.{ .identifier = ip.stringToSlice(field_name) } };
},
.Packed => .begin,
};
},
.Pointer => switch (container_ty.ptrSize(mod)) {
.Slice => switch (field_index) {
@@ -5479,8 +5486,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
.{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) },
.union_type => |union_type| field_name: {
const union_obj = mod.unionPtr(union_type.index);
if (union_obj.layout == .Packed) {
const union_obj = ip.loadUnionType(union_type);
if (union_obj.flagsPtr(ip).layout == .Packed) {
const operand_lval = if (struct_byval == .constant) blk: {
const operand_local = try f.allocLocal(inst, struct_ty);
try f.writeCValue(writer, operand_local, .Other);
@@ -5505,8 +5512,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
} else {
const name = union_obj.fields.keys()[extra.field_index];
break :field_name if (union_type.hasTag()) .{
const name = union_obj.field_names.get(ip)[extra.field_index];
break :field_name if (union_type.hasTag(ip)) .{
.payload_identifier = ip.stringToSlice(name),
} else .{
.identifier = ip.stringToSlice(name),
@@ -6902,14 +6909,14 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
const union_ty = f.typeOfIndex(inst);
const union_obj = mod.typeToUnion(union_ty).?;
const field_name = union_obj.fields.keys()[extra.field_index];
const field_name = union_obj.field_names.get(ip)[extra.field_index];
const payload_ty = f.typeOf(extra.init);
const payload = try f.resolveInst(extra.init);
try reap(f, inst, &.{extra.init});
const writer = f.object.writer();
const local = try f.allocLocal(inst, union_ty);
if (union_obj.layout == .Packed) {
if (union_obj.getLayout(ip) == .Packed) {
try f.writeCValue(writer, local, .Other);
try writer.writeAll(" = ");
try f.writeCValue(writer, payload, .Initializer);

View File

@@ -303,7 +303,7 @@ pub const CType = extern union {
}
pub fn unionPayloadAlign(union_ty: Type, mod: *Module) AlignAs {
const union_obj = mod.typeToUnion(union_ty).?;
const union_payload_align = union_obj.abiAlignment(mod, false);
const union_payload_align = mod.unionAbiAlignment(union_obj);
return init(union_payload_align, union_payload_align);
}
@@ -1499,7 +1499,7 @@ pub const CType = extern union {
if (lookup.isMutable()) {
for (0..switch (zig_ty_tag) {
.Struct => ty.structFieldCount(mod),
.Union => ty.unionFields(mod).count(),
.Union => mod.typeToUnion(ty).?.field_names.len,
else => unreachable,
}) |field_i| {
const field_ty = ty.structFieldType(field_i, mod);
@@ -1581,7 +1581,7 @@ pub const CType = extern union {
var is_packed = false;
for (0..switch (zig_ty_tag) {
.Struct => ty.structFieldCount(mod),
.Union => ty.unionFields(mod).count(),
.Union => mod.typeToUnion(ty).?.field_names.len,
else => unreachable,
}) |field_i| {
const field_ty = ty.structFieldType(field_i, mod);
@@ -1912,6 +1912,7 @@ pub const CType = extern union {
kind: Kind,
convert: Convert,
) !CType {
const ip = &mod.intern_pool;
const arena = store.arena.allocator();
switch (convert.value) {
.cty => |c| return c.copy(arena),
@@ -1932,7 +1933,7 @@ pub const CType = extern union {
const zig_ty_tag = ty.zigTypeTag(mod);
const fields_len = switch (zig_ty_tag) {
.Struct => ty.structFieldCount(mod),
.Union => ty.unionFields(mod).count(),
.Union => mod.typeToUnion(ty).?.field_names.len,
else => unreachable,
};
@@ -1956,9 +1957,9 @@ pub const CType = extern union {
.name = try if (ty.isSimpleTuple(mod))
std.fmt.allocPrintZ(arena, "f{}", .{field_i})
else
arena.dupeZ(u8, mod.intern_pool.stringToSlice(switch (zig_ty_tag) {
arena.dupeZ(u8, ip.stringToSlice(switch (zig_ty_tag) {
.Struct => ty.structFieldName(field_i, mod),
.Union => ty.unionFields(mod).keys()[field_i],
.Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
else => unreachable,
})),
.type = store.set.typeToIndex(field_ty, mod, switch (kind) {
@@ -2015,7 +2016,6 @@ pub const CType = extern union {
.function,
.varargs_function,
=> {
const ip = &mod.intern_pool;
const info = mod.typeToFunc(ty).?;
assert(!info.is_generic);
const param_kind: Kind = switch (kind) {
@@ -2068,6 +2068,7 @@ pub const CType = extern union {
pub fn eql(self: @This(), ty: Type, cty: CType) bool {
const mod = self.lookup.getModule();
const ip = &mod.intern_pool;
switch (self.convert.value) {
.cty => |c| return c.eql(cty),
.tag => |t| {
@@ -2088,7 +2089,7 @@ pub const CType = extern union {
var c_field_i: usize = 0;
for (0..switch (zig_ty_tag) {
.Struct => ty.structFieldCount(mod),
.Union => ty.unionFields(mod).count(),
.Union => mod.typeToUnion(ty).?.field_names.len,
else => unreachable,
}) |field_i| {
const field_ty = ty.structFieldType(field_i, mod);
@@ -2108,9 +2109,9 @@ pub const CType = extern union {
if (ty.isSimpleTuple(mod))
std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable
else
mod.intern_pool.stringToSlice(switch (zig_ty_tag) {
ip.stringToSlice(switch (zig_ty_tag) {
.Struct => ty.structFieldName(field_i, mod),
.Union => ty.unionFields(mod).keys()[field_i],
.Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
else => unreachable,
}),
mem.span(c_field.name),
@@ -2149,7 +2150,6 @@ pub const CType = extern union {
=> {
if (ty.zigTypeTag(mod) != .Fn) return false;
const ip = &mod.intern_pool;
const info = mod.typeToFunc(ty).?;
assert(!info.is_generic);
const data = cty.cast(Payload.Function).?.data;
@@ -2217,7 +2217,7 @@ pub const CType = extern union {
const zig_ty_tag = ty.zigTypeTag(mod);
for (0..switch (ty.zigTypeTag(mod)) {
.Struct => ty.structFieldCount(mod),
.Union => ty.unionFields(mod).count(),
.Union => mod.typeToUnion(ty).?.field_names.len,
else => unreachable,
}) |field_i| {
const field_ty = ty.structFieldType(field_i, mod);
@@ -2235,7 +2235,7 @@ pub const CType = extern union {
else
mod.intern_pool.stringToSlice(switch (zig_ty_tag) {
.Struct => ty.structFieldName(field_i, mod),
.Union => ty.unionFields(mod).keys()[field_i],
.Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
else => unreachable,
}));
autoHash(hasher, AlignAs.fieldAlign(ty, field_i, mod).@"align");

View File

@@ -2382,7 +2382,7 @@ pub const Object = struct {
break :blk fwd_decl;
};
switch (mod.intern_pool.indexToKey(ty.toIntern())) {
switch (ip.indexToKey(ty.toIntern())) {
.anon_struct_type => |tuple| {
var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
defer di_fields.deinit(gpa);
@@ -2401,7 +2401,7 @@ pub const Object = struct {
offset = field_offset + field_size;
const field_name = if (tuple.names.len != 0)
mod.intern_pool.stringToSlice(tuple.names[i])
ip.stringToSlice(tuple.names[i])
else
try std.fmt.allocPrintZ(gpa, "{d}", .{i});
defer if (tuple.names.len == 0) gpa.free(field_name);
@@ -2491,7 +2491,7 @@ pub const Object = struct {
const field_offset = std.mem.alignForward(u64, offset, field_align);
offset = field_offset + field_size;
const field_name = mod.intern_pool.stringToSlice(fields.keys()[field_and_index.index]);
const field_name = ip.stringToSlice(fields.keys()[field_and_index.index]);
try di_fields.append(gpa, dib.createMemberType(
fwd_decl.toScope(),
@@ -2546,8 +2546,8 @@ pub const Object = struct {
break :blk fwd_decl;
};
const union_obj = mod.typeToUnion(ty).?;
if (!union_obj.haveFieldTypes() or !ty.hasRuntimeBitsIgnoreComptime(mod)) {
const union_type = ip.indexToKey(ty.toIntern()).union_type;
if (!union_type.haveFieldTypes(ip) or !ty.hasRuntimeBitsIgnoreComptime(mod)) {
const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);
dib.replaceTemporary(fwd_decl, union_di_ty);
// The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
@@ -2556,10 +2556,11 @@ pub const Object = struct {
return union_di_ty;
}
const layout = ty.unionGetLayout(mod);
const union_obj = ip.loadUnionType(union_type);
const layout = mod.getUnionLayout(union_obj);
if (layout.payload_size == 0) {
const tag_di_ty = try o.lowerDebugType(union_obj.tag_ty, .full);
const tag_di_ty = try o.lowerDebugType(union_obj.enum_tag_ty.toType(), .full);
const di_fields = [_]*llvm.DIType{tag_di_ty};
const full_di_ty = dib.createStructType(
compile_unit_scope,
@@ -2586,22 +2587,20 @@ pub const Object = struct {
var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
defer di_fields.deinit(gpa);
try di_fields.ensureUnusedCapacity(gpa, union_obj.fields.count());
try di_fields.ensureUnusedCapacity(gpa, union_obj.field_names.len);
var it = union_obj.fields.iterator();
while (it.next()) |kv| {
const field_name = kv.key_ptr.*;
const field = kv.value_ptr.*;
for (0..union_obj.field_names.len) |field_index| {
const field_ty = union_obj.field_types.get(ip)[field_index];
if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
const field_size = field_ty.toType().abiSize(mod);
const field_align = mod.unionFieldNormalAlignment(union_obj, @intCast(field_index));
const field_size = field.ty.abiSize(mod);
const field_align = field.normalAlignment(mod);
const field_di_ty = try o.lowerDebugType(field.ty, .full);
const field_di_ty = try o.lowerDebugType(field_ty.toType(), .full);
const field_name = union_obj.field_names.get(ip)[field_index];
di_fields.appendAssumeCapacity(dib.createMemberType(
fwd_decl.toScope(),
mod.intern_pool.stringToSlice(field_name),
ip.stringToSlice(field_name),
null, // file
0, // line
field_size * 8, // size in bits
@@ -2659,7 +2658,7 @@ pub const Object = struct {
layout.tag_align * 8, // align in bits
tag_offset * 8, // offset in bits
0, // flags
try o.lowerDebugType(union_obj.tag_ty, .full),
try o.lowerDebugType(union_obj.enum_tag_ty.toType(), .full),
);
const payload_di = dib.createMemberType(
@@ -3078,6 +3077,7 @@ pub const Object = struct {
fn lowerTypeInner(o: *Object, t: Type) Allocator.Error!Builder.Type {
const mod = o.module;
const target = mod.getTarget();
const ip = &mod.intern_pool;
return switch (t.toIntern()) {
.u0_type, .i0_type => unreachable,
inline .u1_type,
@@ -3172,7 +3172,7 @@ pub const Object = struct {
.var_args_param_type,
.none,
=> unreachable,
else => switch (mod.intern_pool.indexToKey(t.toIntern())) {
else => switch (ip.indexToKey(t.toIntern())) {
.int_type => |int_type| try o.builder.intType(int_type.bits),
.ptr_type => |ptr_type| type: {
const ptr_ty = try o.builder.ptrType(
@@ -3264,7 +3264,7 @@ pub const Object = struct {
return int_ty;
}
const name = try o.builder.string(mod.intern_pool.stringToSlice(
const name = try o.builder.string(ip.stringToSlice(
try struct_obj.getFullyQualifiedName(mod),
));
const ty = try o.builder.opaqueType(name);
@@ -3357,40 +3357,40 @@ pub const Object = struct {
const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
if (gop.found_existing) return gop.value_ptr.*;
const union_obj = mod.unionPtr(union_type.index);
const layout = union_obj.getLayout(mod, union_type.hasTag());
const union_obj = ip.loadUnionType(union_type);
const layout = mod.getUnionLayout(union_obj);
if (union_obj.layout == .Packed) {
if (union_obj.flagsPtr(ip).layout == .Packed) {
const int_ty = try o.builder.intType(@intCast(t.bitSize(mod)));
gop.value_ptr.* = int_ty;
return int_ty;
}
if (layout.payload_size == 0) {
const enum_tag_ty = try o.lowerType(union_obj.tag_ty);
const enum_tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
gop.value_ptr.* = enum_tag_ty;
return enum_tag_ty;
}
const name = try o.builder.string(mod.intern_pool.stringToSlice(
try union_obj.getFullyQualifiedName(mod),
const name = try o.builder.string(ip.stringToSlice(
try mod.declPtr(union_obj.decl).getFullyQualifiedName(mod),
));
const ty = try o.builder.opaqueType(name);
gop.value_ptr.* = ty; // must be done before any recursive calls
const aligned_field = union_obj.fields.values()[layout.most_aligned_field];
const aligned_field_ty = try o.lowerType(aligned_field.ty);
const aligned_field_ty = union_obj.field_types.get(ip)[layout.most_aligned_field].toType();
const aligned_field_llvm_ty = try o.lowerType(aligned_field_ty);
const payload_ty = ty: {
if (layout.most_aligned_field_size == layout.payload_size) {
break :ty aligned_field_ty;
break :ty aligned_field_llvm_ty;
}
const padding_len = if (layout.tag_size == 0)
layout.abi_size - layout.most_aligned_field_size
else
layout.payload_size - layout.most_aligned_field_size;
break :ty try o.builder.structType(.@"packed", &.{
aligned_field_ty,
aligned_field_llvm_ty,
try o.builder.arrayType(padding_len, .i8),
});
};
@@ -3402,7 +3402,7 @@ pub const Object = struct {
);
return ty;
}
const enum_tag_ty = try o.lowerType(union_obj.tag_ty);
const enum_tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
// Put the tag before or after the payload depending on which one's
// alignment is greater.
@@ -3430,7 +3430,7 @@ pub const Object = struct {
.opaque_type => |opaque_type| {
const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
if (!gop.found_existing) {
const name = try o.builder.string(mod.intern_pool.stringToSlice(
const name = try o.builder.string(ip.stringToSlice(
try mod.opaqueFullyQualifiedName(opaque_type),
));
gop.value_ptr.* = try o.builder.opaqueType(name);
@@ -3551,10 +3551,11 @@ pub const Object = struct {
fn lowerValue(o: *Object, arg_val: InternPool.Index) Error!Builder.Constant {
const mod = o.module;
const ip = &mod.intern_pool;
const target = mod.getTarget();
var val = arg_val.toValue();
const arg_val_key = mod.intern_pool.indexToKey(arg_val);
const arg_val_key = ip.indexToKey(arg_val);
switch (arg_val_key) {
.runtime_value => |rt| val = rt.val.toValue(),
else => {},
@@ -3563,7 +3564,7 @@ pub const Object = struct {
return o.builder.undefConst(try o.lowerType(arg_val_key.typeOf().toType()));
}
const val_key = mod.intern_pool.indexToKey(val.toIntern());
const val_key = ip.indexToKey(val.toIntern());
const ty = val_key.typeOf().toType();
return switch (val_key) {
.int_type,
@@ -3749,7 +3750,7 @@ pub const Object = struct {
fields[0..llvm_ty_fields.len],
), vals[0..llvm_ty_fields.len]);
},
.aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.toIntern())) {
.aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) {
.array_type => |array_type| switch (aggregate.storage) {
.bytes => |bytes| try o.builder.stringConst(try o.builder.string(bytes)),
.elems => |elems| {
@@ -4024,11 +4025,10 @@ pub const Object = struct {
if (layout.payload_size == 0) return o.lowerValue(un.tag);
const union_obj = mod.typeToUnion(ty).?;
const field_index = ty.unionTagFieldIndex(un.tag.toValue(), o.module).?;
assert(union_obj.haveFieldTypes());
const field_index = mod.unionTagFieldIndex(union_obj, un.tag.toValue()).?;
const field_ty = union_obj.fields.values()[field_index].ty;
if (union_obj.layout == .Packed) {
const field_ty = union_obj.field_types.get(ip)[field_index].toType();
if (union_obj.getLayout(ip) == .Packed) {
if (!field_ty.hasRuntimeBits(mod)) return o.builder.intConst(union_ty, 0);
const small_int_val = try o.builder.castConst(
if (field_ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast,
@@ -9676,6 +9676,7 @@ pub const FuncGen = struct {
fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = self.dg.object;
const mod = o.module;
const ip = &mod.intern_pool;
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
const union_ty = self.typeOfIndex(inst);
@@ -9683,13 +9684,13 @@ pub const FuncGen = struct {
const layout = union_ty.unionGetLayout(mod);
const union_obj = mod.typeToUnion(union_ty).?;
if (union_obj.layout == .Packed) {
if (union_obj.getLayout(ip) == .Packed) {
const big_bits = union_ty.bitSize(mod);
const int_llvm_ty = try o.builder.intType(@intCast(big_bits));
const field = union_obj.fields.values()[extra.field_index];
const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType();
const non_int_val = try self.resolveInst(extra.init);
const small_int_ty = try o.builder.intType(@intCast(field.ty.bitSize(mod)));
const small_int_val = if (field.ty.isPtrAtRuntime(mod))
const small_int_ty = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
const small_int_val = if (field_ty.isPtrAtRuntime(mod))
try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")
else
try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
@@ -9698,7 +9699,7 @@ pub const FuncGen = struct {
const tag_int = blk: {
const tag_ty = union_ty.unionTagTypeHypothetical(mod);
const union_field_name = union_obj.fields.keys()[extra.field_index];
const union_field_name = union_obj.field_names.get(ip)[extra.field_index];
const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;
const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);
@@ -9719,18 +9720,17 @@ pub const FuncGen = struct {
const alignment = Builder.Alignment.fromByteUnits(layout.abi_align);
const result_ptr = try self.buildAlloca(union_llvm_ty, alignment);
const llvm_payload = try self.resolveInst(extra.init);
assert(union_obj.haveFieldTypes());
const field = union_obj.fields.values()[extra.field_index];
const field_llvm_ty = try o.lowerType(field.ty);
const field_size = field.ty.abiSize(mod);
const field_align = field.normalAlignment(mod);
const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType();
const field_llvm_ty = try o.lowerType(field_ty);
const field_size = field_ty.abiSize(mod);
const field_align = mod.unionFieldNormalAlignment(union_obj, extra.field_index);
const llvm_usize = try o.lowerType(Type.usize);
const usize_zero = try o.builder.intValue(llvm_usize, 0);
const i32_zero = try o.builder.intValue(.i32, 0);
const llvm_union_ty = t: {
const payload_ty = p: {
if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) {
if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {
const padding_len = layout.payload_size;
break :p try o.builder.arrayType(padding_len, .i8);
}
@@ -9743,7 +9743,7 @@ pub const FuncGen = struct {
});
};
if (layout.tag_size == 0) break :t try o.builder.structType(.normal, &.{payload_ty});
const tag_ty = try o.lowerType(union_obj.tag_ty);
const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
var fields: [3]Builder.Type = undefined;
var fields_len: usize = 2;
if (layout.tag_align >= layout.payload_align) {
@@ -9761,7 +9761,7 @@ pub const FuncGen = struct {
// Now we follow the layout as expressed above with GEP instructions to set the
// tag and the payload.
const field_ptr_ty = try mod.ptrType(.{
.child = field.ty.toIntern(),
.child = field_ty.toIntern(),
.flags = .{ .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align) },
});
if (layout.tag_size == 0) {
@@ -9786,9 +9786,9 @@ pub const FuncGen = struct {
const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };
const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");
const tag_ty = try o.lowerType(union_obj.tag_ty);
const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
const llvm_tag = try o.builder.intValue(tag_ty, tag_int);
const tag_alignment = Builder.Alignment.fromByteUnits(union_obj.tag_ty.abiAlignment(mod));
const tag_alignment = Builder.Alignment.fromByteUnits(union_obj.enum_tag_ty.toType().abiAlignment(mod));
_ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);
}

View File

@@ -619,9 +619,10 @@ pub const DeclGen = struct {
fn lower(self: *@This(), ty: Type, arg_val: Value) !void {
const dg = self.dg;
const mod = dg.module;
const ip = &mod.intern_pool;
var val = arg_val;
switch (mod.intern_pool.indexToKey(val.toIntern())) {
switch (ip.indexToKey(val.toIntern())) {
.runtime_value => |rt| val = rt.val.toValue(),
else => {},
}
@@ -631,7 +632,7 @@ pub const DeclGen = struct {
return try self.addUndef(size);
}
switch (mod.intern_pool.indexToKey(val.toIntern())) {
switch (ip.indexToKey(val.toIntern())) {
.int_type,
.ptr_type,
.array_type,
@@ -770,7 +771,7 @@ pub const DeclGen = struct {
try self.addConstBool(payload_val != null);
try self.addUndef(padding);
},
.aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.ip_index)) {
.aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) {
.array_type => |array_type| {
const elem_ty = array_type.child.toType();
switch (aggregate.storage) {
@@ -801,7 +802,7 @@ pub const DeclGen = struct {
if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue;
const field_val = switch (aggregate.storage) {
.bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{
.bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
.ty = field.ty.toIntern(),
.storage = .{ .u64 = bytes[i] },
} }),
@@ -828,13 +829,13 @@ pub const DeclGen = struct {
return try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue());
}
const union_ty = mod.typeToUnion(ty).?;
if (union_ty.layout == .Packed) {
const union_obj = mod.typeToUnion(ty).?;
if (union_obj.getLayout(ip) == .Packed) {
return dg.todo("packed union constants", .{});
}
const active_field = ty.unionTagFieldIndex(un.tag.toValue(), dg.module).?;
const active_field_ty = union_ty.fields.values()[active_field].ty;
const active_field_ty = union_obj.field_types.get(ip)[active_field].toType();
const has_tag = layout.tag_size != 0;
const tag_first = layout.tag_align >= layout.payload_align;
@@ -1162,16 +1163,17 @@ pub const DeclGen = struct {
/// resulting struct will be *underaligned*.
fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef {
const mod = self.module;
const ip = &mod.intern_pool;
const layout = ty.unionGetLayout(mod);
const union_ty = mod.typeToUnion(ty).?;
const union_obj = mod.typeToUnion(ty).?;
if (union_ty.layout == .Packed) {
if (union_obj.getLayout(ip) == .Packed) {
return self.todo("packed union types", .{});
}
if (layout.payload_size == 0) {
// No payload, so represent this as just the tag type.
return try self.resolveType(union_ty.tag_ty, .indirect);
return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);
}
var member_types = std.BoundedArray(CacheRef, 4){};
@@ -1182,13 +1184,13 @@ pub const DeclGen = struct {
const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled?
if (has_tag and tag_first) {
const tag_ty_ref = try self.resolveType(union_ty.tag_ty, .indirect);
const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);
member_types.appendAssumeCapacity(tag_ty_ref);
member_names.appendAssumeCapacity(try self.spv.resolveString("tag"));
}
const active_field = maybe_active_field orelse layout.most_aligned_field;
const active_field_ty = union_ty.fields.values()[active_field].ty;
const active_field_ty = union_obj.field_types.get(ip)[active_field].toType();
const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: {
const active_payload_ty_ref = try self.resolveType(active_field_ty, .indirect);
@@ -1205,7 +1207,7 @@ pub const DeclGen = struct {
}
if (has_tag and !tag_first) {
const tag_ty_ref = try self.resolveType(union_ty.tag_ty, .indirect);
const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);
member_types.appendAssumeCapacity(tag_ty_ref);
member_names.appendAssumeCapacity(try self.spv.resolveString("tag"));
}