stage2: move enum tag values into the InternPool

I'm seeing a new assertion trip: the call to `enumTagFieldIndex` in the
implementation of `@Type` is attempting to query the field index of an
union's enum tag, but the type of the enum tag value provided is not the
same as the union's tag type. Most likely this is a problem with type
coercion, since values are now typed.

Another problem is that I added some hacks in std.builtin because I
didn't see any convenient way to access them from Sema. That should
definitely be cleaned up before merging this branch.
This commit is contained in:
Andrew Kelley
2023-05-12 16:22:37 -07:00
parent d89807efbb
commit 88dbd62bcb
19 changed files with 771 additions and 674 deletions

View File

@@ -748,7 +748,7 @@ pub const DeclGen = struct {
.ReleaseFast, .ReleaseSmall => false,
};
if (val.isUndefDeep()) {
if (val.isUndefDeep(mod)) {
switch (ty.zigTypeTag(mod)) {
.Bool => {
if (safety_on) {
@@ -1183,7 +1183,7 @@ pub const DeclGen = struct {
var index: usize = 0;
while (index < ai.len) : (index += 1) {
const elem_val = try val.elemValue(mod, index);
const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod));
const elem_val_u8 = if (elem_val.isUndef(mod)) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod));
try literal.writeChar(elem_val_u8);
}
if (ai.sentinel) |s| {
@@ -1197,7 +1197,7 @@ pub const DeclGen = struct {
while (index < ai.len) : (index += 1) {
if (index != 0) try writer.writeByte(',');
const elem_val = try val.elemValue(mod, index);
const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod));
const elem_val_u8 = if (elem_val.isUndef(mod)) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod));
try writer.print("'\\x{x}'", .{elem_val_u8});
}
if (ai.sentinel) |s| {
@@ -1284,23 +1284,16 @@ pub const DeclGen = struct {
try dg.renderValue(writer, error_ty, error_val, initializer_type);
try writer.writeAll(" }");
},
.Enum => {
switch (val.tag()) {
.enum_field_index => {
const field_index = val.castTag(.enum_field_index).?.data;
const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
if (enum_type.values.len != 0) {
const tag_val = enum_type.values[field_index];
return dg.renderValue(writer, enum_type.tag_ty.toType(), tag_val.toValue(), location);
} else {
return writer.print("{d}", .{field_index});
}
},
else => {
const int_tag_ty = try ty.intTagType(mod);
return dg.renderValue(writer, int_tag_ty, val, location);
},
}
.Enum => switch (val.ip_index) {
.none => {
const int_tag_ty = try ty.intTagType(mod);
return dg.renderValue(writer, int_tag_ty, val, location);
},
else => {
const enum_tag = mod.intern_pool.indexToKey(val.ip_index).enum_tag;
const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int);
return dg.renderValue(writer, int_tag_ty.toType(), enum_tag.int.toValue(), location);
},
},
.Fn => switch (val.tag()) {
.function => {
@@ -2524,13 +2517,10 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
try w.writeByte('(');
try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete);
try w.writeAll(") {\n switch (tag) {\n");
for (enum_ty.enumFields(mod), 0..) |name_ip, index| {
for (enum_ty.enumFields(mod), 0..) |name_ip, index_usize| {
const index = @intCast(u32, index_usize);
const name = mod.intern_pool.stringToSlice(name_ip);
var tag_pl: Value.Payload.U32 = .{
.base = .{ .tag = .enum_field_index },
.data = @intCast(u32, index),
};
const tag_val = Value.initPayload(&tag_pl.base);
const tag_val = try mod.enumValueFieldIndex(enum_ty, index);
const int_val = try tag_val.enumToInt(enum_ty, mod);
@@ -3609,7 +3599,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
const ptr_val = try f.resolveInst(bin_op.lhs);
const src_ty = f.typeOf(bin_op.rhs);
const val_is_undef = if (try f.air.value(bin_op.rhs, mod)) |v| v.isUndefDeep() else false;
const val_is_undef = if (try f.air.value(bin_op.rhs, mod)) |v| v.isUndefDeep(mod) else false;
if (val_is_undef) {
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
@@ -4267,7 +4257,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
const mod = f.object.dg.module;
const pl_op = f.air.instructions.items(.data)[inst].pl_op;
const name = f.air.nullTerminatedString(pl_op.payload);
const operand_is_undef = if (try f.air.value(pl_op.operand, mod)) |v| v.isUndefDeep() else false;
const operand_is_undef = if (try f.air.value(pl_op.operand, mod)) |v| v.isUndefDeep(mod) else false;
if (!operand_is_undef) _ = try f.resolveInst(pl_op.operand);
try reap(f, inst, &.{pl_op.operand});
@@ -6290,7 +6280,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
const value = try f.resolveInst(bin_op.rhs);
const elem_ty = f.typeOf(bin_op.rhs);
const elem_abi_size = elem_ty.abiSize(mod);
const val_is_undef = if (try f.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep() else false;
const val_is_undef = if (try f.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep(mod) else false;
const writer = f.object.writer();
if (val_is_undef) {
@@ -6907,11 +6897,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
if (layout.tag_size != 0) {
const field_index = tag_ty.enumFieldIndex(field_name, mod).?;
var tag_pl: Value.Payload.U32 = .{
.base = .{ .tag = .enum_field_index },
.data = @intCast(u32, field_index),
};
const tag_val = Value.initPayload(&tag_pl.base);
const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
const int_val = try tag_val.enumToInt(tag_ty, mod);
@@ -7438,7 +7424,7 @@ fn formatIntLiteral(
defer allocator.free(undef_limbs);
var int_buf: Value.BigIntSpace = undefined;
const int = if (data.val.isUndefDeep()) blk: {
const int = if (data.val.isUndefDeep(mod)) blk: {
undef_limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(data.int_info.bits));
@memset(undef_limbs, undefPattern(BigIntLimb));

View File

@@ -3233,16 +3233,16 @@ pub const DeclGen = struct {
}
fn lowerValue(dg: *DeclGen, arg_tv: TypedValue) Error!*llvm.Value {
const mod = dg.module;
const target = mod.getTarget();
var tv = arg_tv;
if (tv.val.castTag(.runtime_value)) |rt| {
tv.val = rt.data;
}
if (tv.val.isUndef()) {
if (tv.val.isUndef(mod)) {
const llvm_type = try dg.lowerType(tv.ty);
return llvm_type.getUndef();
}
const mod = dg.module;
const target = mod.getTarget();
switch (tv.ty.zigTypeTag(mod)) {
.Bool => {
const llvm_type = try dg.lowerType(tv.ty);
@@ -8204,7 +8204,7 @@ pub const FuncGen = struct {
const ptr_ty = self.typeOf(bin_op.lhs);
const operand_ty = ptr_ty.childType(mod);
const val_is_undef = if (try self.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep() else false;
const val_is_undef = if (try self.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep(mod) else false;
if (val_is_undef) {
// Even if safety is disabled, we still emit a memset to undefined since it conveys
// extra information to LLVM. However, safety makes the difference between using
@@ -8496,7 +8496,7 @@ pub const FuncGen = struct {
const is_volatile = ptr_ty.isVolatilePtr(mod);
if (try self.air.value(bin_op.rhs, mod)) |elem_val| {
if (elem_val.isUndefDeep()) {
if (elem_val.isUndefDeep(mod)) {
// Even if safety is disabled, we still emit a memset to undefined since it conveys
// extra information to LLVM. However, safety makes the difference between using
// 0xaa or actual undefined for the fill byte.
@@ -8890,15 +8890,12 @@ pub const FuncGen = struct {
const tag_int_value = fn_val.getParam(0);
const switch_instr = self.builder.buildSwitch(tag_int_value, unnamed_block, @intCast(c_uint, enum_type.names.len));
for (enum_type.names, 0..) |_, field_index| {
for (enum_type.names, 0..) |_, field_index_usize| {
const field_index = @intCast(u32, field_index_usize);
const this_tag_int_value = int: {
var tag_val_payload: Value.Payload.U32 = .{
.base = .{ .tag = .enum_field_index },
.data = @intCast(u32, field_index),
};
break :int try self.dg.lowerValue(.{
.ty = enum_ty,
.val = Value.initPayload(&tag_val_payload.base),
.val = try mod.enumValueFieldIndex(enum_ty, field_index),
});
};
switch_instr.addCase(this_tag_int_value, named_block);
@@ -8973,7 +8970,8 @@ pub const FuncGen = struct {
usize_llvm_ty.constNull(), usize_llvm_ty.constNull(),
};
for (enum_type.names, 0..) |name_ip, field_index| {
for (enum_type.names, 0..) |name_ip, field_index_usize| {
const field_index = @intCast(u32, field_index_usize);
const name = mod.intern_pool.stringToSlice(name_ip);
const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False);
const str_init_llvm_ty = str_init.typeOf();
@@ -8997,16 +8995,10 @@ pub const FuncGen = struct {
slice_global.setAlignment(slice_alignment);
const return_block = self.context.appendBasicBlock(fn_val, "Name");
const this_tag_int_value = int: {
var tag_val_payload: Value.Payload.U32 = .{
.base = .{ .tag = .enum_field_index },
.data = @intCast(u32, field_index),
};
break :int try self.dg.lowerValue(.{
.ty = enum_ty,
.val = Value.initPayload(&tag_val_payload.base),
});
};
const this_tag_int_value = try self.dg.lowerValue(.{
.ty = enum_ty,
.val = try mod.enumValueFieldIndex(enum_ty, field_index),
});
switch_instr.addCase(this_tag_int_value, return_block);
self.builder.positionBuilderAtEnd(return_block);
@@ -9094,7 +9086,7 @@ pub const FuncGen = struct {
for (values, 0..) |*val, i| {
const elem = try mask.elemValue(mod, i);
if (elem.isUndef()) {
if (elem.isUndef(mod)) {
val.* = llvm_i32.getUndef();
} else {
const int = elem.toSignedInt(mod);
@@ -9419,11 +9411,7 @@ pub const FuncGen = struct {
const tag_ty = union_ty.unionTagTypeHypothetical(mod);
const union_field_name = union_obj.fields.keys()[extra.field_index];
const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;
var tag_val_payload: Value.Payload.U32 = .{
.base = .{ .tag = .enum_field_index },
.data = @intCast(u32, enum_field_index),
};
const tag_val = Value.initPayload(&tag_val_payload.base);
const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
const tag_int_val = try tag_val.enumToInt(tag_ty, mod);
break :blk tag_int_val.toUnsignedInt(mod);
};

View File

@@ -614,7 +614,7 @@ pub const DeclGen = struct {
const dg = self.dg;
const mod = dg.module;
if (val.isUndef()) {
if (val.isUndef(mod)) {
const size = ty.abiSize(mod);
return try self.addUndef(size);
}
@@ -882,7 +882,7 @@ pub const DeclGen = struct {
// const target = self.getTarget();
// TODO: Fix the resulting global linking for these paths.
// if (val.isUndef()) {
// if (val.isUndef(mod)) {
// // Special case: the entire value is undefined. In this case, we can just
// // generate an OpVariable with no initializer.
// return try section.emit(self.spv.gpa, .OpVariable, .{
@@ -978,7 +978,7 @@ pub const DeclGen = struct {
log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) });
if (val.isUndef()) {
if (val.isUndef(mod)) {
return self.spv.constUndef(result_ty_ref);
}
@@ -2091,7 +2091,7 @@ pub const DeclGen = struct {
var i: usize = 0;
while (i < mask_len) : (i += 1) {
const elem = try mask.elemValue(self.module, i);
if (elem.isUndef()) {
if (elem.isUndef(mod)) {
self.func.body.writeOperand(spec.LiteralInteger, 0xFFFF_FFFF);
} else {
const int = elem.toSignedInt(mod);