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:
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user