From 2f05b1482a6f62658cc70c252d48a24a40404aa8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 5 May 2023 14:57:23 -0700 Subject: [PATCH] Sema: update core comptime detection logic to be InternPool aware * Add some assertions to make sure instructions are not none. I tested all these with master branch as well and made sure the behavior tests still passed with the assertions intact (along with a handful of callsite updates). * Fix Sema.resolveMaybeUndefValAllowVariablesMaybeRuntime not noticing that interned values are comptime-known. This was causing all kinds of chaos. * Fix print_air writeType calling tag() without checking for ip_index --- src/Air.zig | 16 +++++++++++----- src/Liveness.zig | 4 ++-- src/Liveness/Verify.zig | 2 +- src/Sema.zig | 33 +++++++++++++++++++-------------- src/Zir.zig | 10 ++++++++-- src/print_air.zig | 10 ++++++---- 6 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/Air.zig b/src/Air.zig index 64212d3b9a..3c04d17073 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -925,7 +925,7 @@ pub const Inst = struct { /// This Ref does not correspond to any AIR instruction or constant /// value and may instead be used as a sentinel to indicate null. - none = std.math.maxInt(u32), + none = @enumToInt(InternPool.Index.none), _, }; @@ -1461,11 +1461,12 @@ pub fn deinit(air: *Air, gpa: std.mem.Allocator) void { pub const ref_start_index: u32 = InternPool.static_len; -pub fn indexToRef(inst: Air.Inst.Index) Air.Inst.Ref { - return @intToEnum(Air.Inst.Ref, ref_start_index + inst); +pub fn indexToRef(inst: Inst.Index) Inst.Ref { + return @intToEnum(Inst.Ref, ref_start_index + inst); } -pub fn refToIndex(inst: Air.Inst.Ref) ?Air.Inst.Index { +pub fn refToIndex(inst: Inst.Ref) ?Inst.Index { + assert(inst != .none); const ref_int = @enumToInt(inst); if (ref_int >= ref_start_index) { return ref_int - ref_start_index; @@ -1474,8 +1475,13 @@ pub fn refToIndex(inst: Air.Inst.Ref) ?Air.Inst.Index { } } +pub fn refToIndexAllowNone(inst: Inst.Ref) ?Inst.Index { + if (inst == .none) return null; + return refToIndex(inst); +} + /// Returns `null` if runtime-known. -pub fn value(air: Air, inst: Air.Inst.Ref, mod: *const Module) ?Value { +pub fn value(air: Air, inst: Inst.Ref, mod: *const Module) ?Value { const ref_int = @enumToInt(inst); if (ref_int < ref_start_index) { const ip_index = @intToEnum(InternPool.Index, ref_int); diff --git a/src/Liveness.zig b/src/Liveness.zig index 19659940af..da705cfab8 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -1268,7 +1268,7 @@ fn analyzeOperands( _ = data.live_set.remove(inst); for (operands) |op_ref| { - const operand = Air.refToIndex(op_ref) orelse continue; + const operand = Air.refToIndexAllowNone(op_ref) orelse continue; // Don't compute any liveness for constants switch (inst_tags[operand]) { @@ -1304,7 +1304,7 @@ fn analyzeOperands( while (i > 0) { i -= 1; const op_ref = operands[i]; - const operand = Air.refToIndex(op_ref) orelse continue; + const operand = Air.refToIndexAllowNone(op_ref) orelse continue; // Don't compute any liveness for constants switch (inst_tags[operand]) { diff --git a/src/Liveness/Verify.zig b/src/Liveness/Verify.zig index 7059fec507..dbdbf32174 100644 --- a/src/Liveness/Verify.zig +++ b/src/Liveness/Verify.zig @@ -555,7 +555,7 @@ fn verifyDeath(self: *Verify, inst: Air.Inst.Index, operand: Air.Inst.Index) Err } fn verifyOperand(self: *Verify, inst: Air.Inst.Index, op_ref: Air.Inst.Ref, dies: bool) Error!void { - const operand = Air.refToIndex(op_ref) orelse return; + const operand = Air.refToIndexAllowNone(op_ref) orelse return; switch (self.air.instructions.items(.tag)[operand]) { .constant, .const_ty, .interned => {}, else => { diff --git a/src/Sema.zig b/src/Sema.zig index 37d6f3e902..8abe6484ee 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -968,7 +968,7 @@ fn analyzeBodyInner( .int_big => try sema.zirIntBig(block, inst), .float => try sema.zirFloat(block, inst), .float128 => try sema.zirFloat128(block, inst), - .int_type => try sema.zirIntType(block, inst), + .int_type => try sema.zirIntType(inst), .is_non_err => try sema.zirIsNonErr(block, inst), .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst), .ret_is_non_err => try sema.zirRetIsNonErr(block, inst), @@ -1694,7 +1694,7 @@ fn analyzeBodyInner( const extra = sema.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data; const defer_body = sema.code.extra[extra.index..][0..extra.len]; const err_code = try sema.resolveInst(inst_data.err_code); - sema.inst_map.putAssumeCapacity(extra.remapped_err_code, err_code); + map.putAssumeCapacity(extra.remapped_err_code, err_code); const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) { error.ComptimeBreak => sema.comptime_break_inst, else => |e| return e, @@ -1730,7 +1730,16 @@ fn analyzeBodyInner( return result; } +pub fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { + if (zir_ref == .none) { + return .none; + } else { + return resolveInst(sema, zir_ref); + } +} + pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { + assert(zir_ref != .none); const i = @enumToInt(zir_ref); // First section of indexes correspond to a set number of constant values. // We intentionally map the same indexes to the same values between ZIR and AIR. @@ -1969,6 +1978,7 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( inst: Air.Inst.Ref, make_runtime: *bool, ) CompileError!?Value { + assert(inst != .none); // First section of indexes correspond to a set number of constant values. const int = @enumToInt(inst); if (int < InternPool.static_len) { @@ -1985,17 +1995,17 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( } return opv; } + const air_datas = sema.air_instructions.items(.data); switch (air_tags[i]) { .constant => { - const ty_pl = sema.air_instructions.items(.data)[i].ty_pl; + 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.isPtrToThreadLocal(sema.mod)) make_runtime.* = true; return val; }, - .const_ty => { - return try sema.air_instructions.items(.data)[i].ty.toValue(sema.arena); - }, + .const_ty => return try air_datas[i].ty.toValue(sema.arena), + .interned => return air_datas[i].interned.toValue(), else => return null, } } @@ -7913,15 +7923,10 @@ fn emitDbgInline( }); } -fn zirIntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - _ = block; - const tracy = trace(@src()); - defer tracy.end(); - +fn zirIntType(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const mod = sema.mod; const int_type = sema.code.instructions.items(.data)[inst].int_type; const ty = try mod.intType(int_type.signedness, int_type.bit_count); - return sema.addType(ty); } @@ -17509,7 +17514,7 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) const tracy = trace(@src()); defer tracy.end(); - const saved_index = if (Zir.refToIndex(inst_data.block)) |zir_block| b: { + const saved_index = if (Zir.refToIndexAllowNone(inst_data.block)) |zir_block| b: { var block = start_block; while (true) { if (block.label) |label| { @@ -17535,7 +17540,7 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) assert(saved_index != .none); // The .error_return_trace_index field was dropped somewhere - const operand = try sema.resolveInst(inst_data.operand); + const operand = try sema.resolveInstAllowNone(inst_data.operand); return sema.popErrorReturnTrace(start_block, src, operand, saved_index); } diff --git a/src/Zir.zig b/src/Zir.zig index 7b708ab04e..8c03dfd060 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -2132,7 +2132,7 @@ pub const Inst = struct { /// This Ref does not correspond to any ZIR instruction or constant /// value and may instead be used as a sentinel to indicate null. - none = std.math.maxInt(u32), + none = @enumToInt(InternPool.Index.none), _, }; @@ -3814,13 +3814,14 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { }; } -const ref_start_index: u32 = InternPool.static_len; +pub const ref_start_index: u32 = InternPool.static_len; pub fn indexToRef(inst: Inst.Index) Inst.Ref { return @intToEnum(Inst.Ref, ref_start_index + inst); } pub fn refToIndex(inst: Inst.Ref) ?Inst.Index { + assert(inst != .none); const ref_int = @enumToInt(inst); if (ref_int >= ref_start_index) { return ref_int - ref_start_index; @@ -3828,3 +3829,8 @@ pub fn refToIndex(inst: Inst.Ref) ?Inst.Index { return null; } } + +pub fn refToIndexAllowNone(inst: Inst.Ref) ?Inst.Index { + if (inst == .none) return null; + return refToIndex(inst); +} diff --git a/src/print_air.zig b/src/print_air.zig index 8717bdc6bf..4396a26f44 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -366,10 +366,12 @@ const Writer = struct { } fn writeType(w: *Writer, s: anytype, ty: Type) !void { - const t = ty.tag(); - switch (t) { - .inferred_alloc_const => try s.writeAll("(inferred_alloc_const)"), - .inferred_alloc_mut => try s.writeAll("(inferred_alloc_mut)"), + switch (ty.ip_index) { + .none => switch (ty.tag()) { + .inferred_alloc_const => try s.writeAll("(inferred_alloc_const)"), + .inferred_alloc_mut => try s.writeAll("(inferred_alloc_mut)"), + else => try ty.print(s, w.module), + }, else => try ty.print(s, w.module), } }