From a5fb16959423005de999fb541d5d5e9aebb8e09e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 7 May 2023 15:07:28 -0700 Subject: [PATCH] stage2: bug fixes related to Type/Value/InternPool --- src/Sema.zig | 68 ++++++++++++++++++------------------- src/arch/x86_64/CodeGen.zig | 2 +- src/codegen/c.zig | 8 ++--- src/codegen/llvm.zig | 28 +++++++++------ src/type.zig | 48 +++++++++++++++----------- src/value.zig | 10 +++++- 6 files changed, 94 insertions(+), 70 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 9b1da74982..ca6f28017b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1746,8 +1746,9 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { if (i < InternPool.static_len) return @intToEnum(Air.Inst.Ref, i); // The last section of indexes refers to the map of ZIR => AIR. const inst = sema.inst_map.get(i - InternPool.static_len).?; + if (inst == .generic_poison) return error.GenericPoison; const ty = sema.typeOf(inst); - if (ty.isGenericPoison()) return error.GenericPoison; + assert(!ty.isGenericPoison()); return inst; } @@ -2000,7 +2001,7 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( .constant => { const ty_pl = air_datas[i].ty_pl; const val = sema.air_values.items[ty_pl.payload]; - if (val.tag() == .runtime_value) make_runtime.* = true; + if (val.isRuntimeValue()) make_runtime.* = true; if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true; return val; }, @@ -9688,7 +9689,7 @@ fn intCast( // range shrinkage // requirement: int value fits into target type if (wanted_value_bits < actual_value_bits) { - const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod); + const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_ty); const dest_max_val = if (is_vector) try Value.Tag.repeated.create(sema.arena, dest_max_val_scalar) else @@ -10831,7 +10832,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError defer arena.deinit(); const min_int = try operand_ty.minInt(arena.allocator(), mod); - const max_int = try operand_ty.maxIntScalar(mod); + const max_int = try operand_ty.maxIntScalar(mod, Type.comptime_int); if (try range_set.spans(min_int, max_int, operand_ty)) { if (special_prong == .@"else") { return sema.fail( @@ -11683,7 +11684,7 @@ const RangeSetUnhandledIterator = struct { fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator { const mod = sema.mod; const min = try ty.minInt(sema.arena, mod); - const max = try ty.maxIntScalar(mod); + const max = try ty.maxIntScalar(mod, Type.comptime_int); return RangeSetUnhandledIterator{ .sema = sema, @@ -12294,7 +12295,7 @@ fn zirShl( { const max_int = try sema.addConstant( lhs_ty, - try lhs_ty.maxInt(sema.arena, mod), + try lhs_ty.maxInt(sema.arena, mod, lhs_ty), ); const rhs_limited = try sema.analyzeMinMax(block, rhs_src, .min, &.{ rhs, max_int }, &.{ rhs_src, rhs_src }); break :rhs try sema.intCast(block, src, lhs_ty, rhs_src, rhs_limited, rhs_src, false); @@ -16503,7 +16504,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai else try std.fmt.allocPrintZ(anon_decl.arena(), "{d}", .{i}); const new_decl = try anon_decl.finish( - try Type.array(anon_decl.arena(), bytes.len, try mod.intValue(Type.u8, 0), Type.u8, mod), + try Type.array(anon_decl.arena(), bytes.len, Value.zero_u8, Type.u8, mod), try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), 0, // default alignment ); @@ -22202,8 +22203,8 @@ fn analyzeMinMax( else => unreachable, }; const max_val = switch (air_tag) { - .min => try comptime_elem_ty.maxInt(sema.arena, mod), // @min(ct, rt) <= ct - .max => try unrefined_elem_ty.maxInt(sema.arena, mod), + .min => try comptime_elem_ty.maxInt(sema.arena, mod, Type.comptime_int), // @min(ct, rt) <= ct + .max => try unrefined_elem_ty.maxInt(sema.arena, mod, Type.comptime_int), else => unreachable, }; @@ -27931,33 +27932,32 @@ fn beginComptimePtrMutation( switch (parent.pointee) { .direct => |val_ptr| { const payload_ty = parent.ty.errorUnionPayload(); - switch (val_ptr.tag()) { - else => { - // An error union has been initialized to undefined at comptime and now we - // are for the first time setting the payload. We must change the - // representation of the error union from `undef` to `opt_payload`. - const arena = parent.beginArena(sema.mod); - defer parent.finishArena(sema.mod); - - const payload = try arena.create(Value.Payload.SubValue); - payload.* = .{ - .base = .{ .tag = .eu_payload }, - .data = Value.undef, - }; - - val_ptr.* = Value.initPayload(&payload.base); - - return ComptimePtrMutationKit{ - .decl_ref_mut = parent.decl_ref_mut, - .pointee = .{ .direct = &payload.data }, - .ty = payload_ty, - }; - }, - .eu_payload => return ComptimePtrMutationKit{ + if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) { + return ComptimePtrMutationKit{ .decl_ref_mut = parent.decl_ref_mut, .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data }, .ty = payload_ty, - }, + }; + } else { + // An error union has been initialized to undefined at comptime and now we + // are for the first time setting the payload. We must change the + // representation of the error union from `undef` to `opt_payload`. + const arena = parent.beginArena(sema.mod); + defer parent.finishArena(sema.mod); + + const payload = try arena.create(Value.Payload.SubValue); + payload.* = .{ + .base = .{ .tag = .eu_payload }, + .data = Value.undef, + }; + + val_ptr.* = Value.initPayload(&payload.base); + + return ComptimePtrMutationKit{ + .decl_ref_mut = parent.decl_ref_mut, + .pointee = .{ .direct = &payload.data }, + .ty = payload_ty, + }; } }, .bad_decl_ty, .bad_ptr_ty => return parent, @@ -33225,7 +33225,7 @@ fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref { pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref { const gpa = sema.gpa; - if (val.ip_index != .none) { + if (val.ip_index != .none and val.ip_index != .null_value) { if (@enumToInt(val.ip_index) < Air.ref_start_index) return @intToEnum(Air.Inst.Ref, @enumToInt(val.ip_index)); try sema.air_instructions.append(gpa, .{ diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index b208656a41..c5e3410947 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -4915,7 +4915,7 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { const sign_val = switch (tag) { .neg => try vec_ty.minInt(stack.get(), mod), - .fabs => try vec_ty.maxInt(stack.get(), mod), + .fabs => try vec_ty.maxInt(stack.get(), mod, vec_ty), else => unreachable, }; diff --git a/src/codegen/c.zig b/src/codegen/c.zig index aaeec05562..b688aada34 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3542,7 +3542,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { try v.elem(f, writer); } else switch (dest_int_info.signedness) { .unsigned => { - const mask_val = try inst_scalar_ty.maxIntScalar(mod); + const mask_val = try inst_scalar_ty.maxIntScalar(mod, scalar_ty); try writer.writeAll("zig_and_"); try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); try writer.writeByte('('); @@ -6681,13 +6681,13 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { .And => switch (scalar_ty.zigTypeTag(mod)) { .Bool => try mod.intValue(Type.comptime_int, 1), else => switch (scalar_ty.intInfo(mod).signedness) { - .unsigned => try scalar_ty.maxIntScalar(mod), + .unsigned => try scalar_ty.maxIntScalar(mod, scalar_ty), .signed => try mod.intValue(scalar_ty, -1), }, }, .Min => switch (scalar_ty.zigTypeTag(mod)) { - .Bool => try mod.intValue(Type.comptime_int, 1), - .Int => try scalar_ty.maxIntScalar(mod), + .Bool => Value.one_comptime_int, + .Int => try scalar_ty.maxIntScalar(mod, scalar_ty), .Float => try Value.floatToValue(std.math.nan(f128), stack.get(), scalar_ty, target), else => unreachable, }, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index c42719d07c..23340b5d34 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3570,15 +3570,21 @@ pub const DeclGen = struct { }, .ErrorSet => { const llvm_ty = try dg.lowerType(Type.anyerror); - switch (tv.val.tag()) { - .@"error" => { - const err_name = tv.val.castTag(.@"error").?.data.name; - const kv = try dg.module.getErrorValue(err_name); - return llvm_ty.constInt(kv.value, .False); + switch (tv.val.ip_index) { + .none => switch (tv.val.tag()) { + .@"error" => { + const err_name = tv.val.castTag(.@"error").?.data.name; + const kv = try dg.module.getErrorValue(err_name); + return llvm_ty.constInt(kv.value, .False); + }, + else => { + // In this case we are rendering an error union which has a 0 bits payload. + return llvm_ty.constNull(); + }, }, - else => { - // In this case we are rendering an error union which has a 0 bits payload. - return llvm_ty.constNull(); + else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { + .int => |int| return llvm_ty.constInt(int.storage.u64, .False), + else => unreachable, }, } }, @@ -3588,7 +3594,7 @@ pub const DeclGen = struct { if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { // We use the error type directly as the type. - const err_val = if (!is_pl) tv.val else try mod.intValue(Type.anyerror, 0); + const err_val = if (!is_pl) tv.val else try mod.intValue(Type.err_int, 0); return dg.lowerValue(.{ .ty = Type.anyerror, .val = err_val }); } @@ -3596,7 +3602,7 @@ pub const DeclGen = struct { const error_align = Type.anyerror.abiAlignment(mod); const llvm_error_value = try dg.lowerValue(.{ .ty = Type.anyerror, - .val = if (is_pl) try mod.intValue(Type.anyerror, 0) else tv.val, + .val = if (is_pl) try mod.intValue(Type.err_int, 0) else tv.val, }); const llvm_payload_value = try dg.lowerValue(.{ .ty = payload_type, @@ -6873,7 +6879,7 @@ pub const FuncGen = struct { const err_union_ty = self.typeOf(ty_op.operand).childType(mod); const payload_ty = err_union_ty.errorUnionPayload(); - const non_error_val = try self.dg.lowerValue(.{ .ty = Type.anyerror, .val = try mod.intValue(Type.anyerror, 0) }); + const non_error_val = try self.dg.lowerValue(.{ .ty = Type.anyerror, .val = try mod.intValue(Type.err_int, 0) }); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { _ = self.builder.buildStore(non_error_val, operand); return operand; diff --git a/src/type.zig b/src/type.zig index e6d0af9f46..68ac507037 100644 --- a/src/type.zig +++ b/src/type.zig @@ -4382,8 +4382,9 @@ pub const Type = struct { } // Works for vectors and vectors of integers. - pub fn maxInt(ty: Type, arena: Allocator, mod: *Module) !Value { - const scalar = try maxIntScalar(ty.scalarType(mod), mod); + /// The returned Value will have type dest_ty. + pub fn maxInt(ty: Type, arena: Allocator, mod: *Module, dest_ty: Type) !Value { + const scalar = try maxIntScalar(ty.scalarType(mod), mod, dest_ty); if (ty.zigTypeTag(mod) == .Vector and scalar.tag() != .the_only_possible_value) { return Value.Tag.repeated.create(arena, scalar); } else { @@ -4391,18 +4392,18 @@ pub const Type = struct { } } - /// Asserts that the type is an integer. - pub fn maxIntScalar(ty: Type, mod: *Module) !Value { + /// The returned Value will have type dest_ty. + pub fn maxIntScalar(ty: Type, mod: *Module, dest_ty: Type) !Value { const info = ty.intInfo(mod); switch (info.bits) { 0 => return switch (info.signedness) { - .signed => mod.intValue(ty, -1), - .unsigned => mod.intValue(ty, 0), + .signed => try mod.intValue(dest_ty, -1), + .unsigned => try mod.intValue(dest_ty, 0), }, 1 => return switch (info.signedness) { - .signed => mod.intValue(ty, 0), - .unsigned => mod.intValue(ty, 0), + .signed => try mod.intValue(dest_ty, 0), + .unsigned => try mod.intValue(dest_ty, 1), }, else => {}, } @@ -4410,11 +4411,11 @@ pub const Type = struct { if (std.math.cast(u6, info.bits - 1)) |shift| switch (info.signedness) { .signed => { const n = @as(i64, std.math.maxInt(i64)) >> (63 - shift); - return mod.intValue(Type.comptime_int, n); + return mod.intValue(dest_ty, n); }, .unsigned => { const n = @as(u64, std.math.maxInt(u64)) >> (63 - shift); - return mod.intValue(Type.comptime_int, n); + return mod.intValue(dest_ty, n); }, }; @@ -4423,7 +4424,7 @@ pub const Type = struct { try res.setTwosCompIntLimit(.max, info.signedness, info.bits); - return mod.intValue_big(Type.comptime_int, res.toConst()); + return mod.intValue_big(dest_ty, res.toConst()); } /// Asserts the type is an enum or a union. @@ -5068,6 +5069,7 @@ pub const Type = struct { pub fn isSimpleTuple(ty: Type) bool { return switch (ty.ip_index) { + .empty_struct => true, .none => switch (ty.tag()) { .tuple, .empty_struct_literal => true, else => false, @@ -5077,21 +5079,29 @@ pub const Type = struct { } pub fn isSimpleTupleOrAnonStruct(ty: Type) bool { - return switch (ty.tag()) { - .tuple, .empty_struct_literal, .anon_struct => true, + return switch (ty.ip_index) { + .empty_struct => true, + .none => switch (ty.tag()) { + .tuple, .empty_struct_literal, .anon_struct => true, + else => false, + }, else => false, }; } // Only allowed for simple tuple types pub fn tupleFields(ty: Type) Payload.Tuple.Data { - return switch (ty.tag()) { - .tuple => ty.castTag(.tuple).?.data, - .anon_struct => .{ - .types = ty.castTag(.anon_struct).?.data.types, - .values = ty.castTag(.anon_struct).?.data.values, + return switch (ty.ip_index) { + .empty_struct => .{ .types = &.{}, .values = &.{} }, + .none => switch (ty.tag()) { + .tuple => ty.castTag(.tuple).?.data, + .anon_struct => .{ + .types = ty.castTag(.anon_struct).?.data.types, + .values = ty.castTag(.anon_struct).?.data.values, + }, + .empty_struct_literal => .{ .types = &.{}, .values = &.{} }, + else => unreachable, }, - .empty_struct_literal => .{ .types = &.{}, .values = &.{} }, else => unreachable, }; } diff --git a/src/value.zig b/src/value.zig index 8268d1dde1..49ca651a79 100644 --- a/src/value.zig +++ b/src/value.zig @@ -2625,6 +2625,10 @@ pub const Value = struct { } } + pub fn isRuntimeValue(val: Value) bool { + return val.ip_index == .none and val.tag() == .runtime_value; + } + pub fn tagIsVariable(val: Value) bool { return val.ip_index == .none and val.tag() == .variable; } @@ -3402,7 +3406,7 @@ pub const Value = struct { if (lhs.isUndef() or rhs.isUndef()) return Value.undef; const anded = try bitwiseAnd(lhs, rhs, ty, arena, mod); - const all_ones = if (ty.isSignedInt(mod)) try mod.intValue(ty, -1) else try ty.maxIntScalar(mod); + const all_ones = if (ty.isSignedInt(mod)) try mod.intValue(ty, -1) else try ty.maxIntScalar(mod, ty); return bitwiseXor(anded, all_ones, ty, arena, mod); } @@ -5152,6 +5156,10 @@ pub const Value = struct { pub const BigIntSpace = InternPool.Key.Int.Storage.BigIntSpace; pub const zero_usize: Value = .{ .ip_index = .zero_usize, .legacy = undefined }; + pub const zero_u8: Value = .{ .ip_index = .zero_u8, .legacy = undefined }; + pub const zero_comptime_int: Value = .{ .ip_index = .zero, .legacy = undefined }; + pub const one_comptime_int: Value = .{ .ip_index = .one, .legacy = undefined }; + pub const negative_one_comptime_int: Value = .{ .ip_index = .negative_one, .legacy = undefined }; pub const undef: Value = .{ .ip_index = .undef, .legacy = undefined }; pub const float_zero: Value = .{ .ip_index = .zero, .legacy = undefined }; // TODO: replace this! pub const @"void": Value = .{ .ip_index = .void_value, .legacy = undefined };