From d25f0106e5523acbda452d43f690c9fed63d0096 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 2 Sep 2025 21:46:57 -0700 Subject: [PATCH 01/12] frontend: remove elem_val and field_val ZIR instructions --- lib/std/zig/AstGen.zig | 73 +++++++++++++----------------------------- lib/std/zig/Zir.zig | 26 ++------------- src/Sema.zig | 52 ------------------------------ src/print_zir.zig | 6 +--- 4 files changed, 26 insertions(+), 131 deletions(-) diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index 848f11ddcec2..bd42fc0e3761 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -2728,12 +2728,9 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As .elem_ptr, .elem_val, .elem_ptr_node, - .elem_val_node, .elem_val_imm, .field_ptr, - .field_val, .field_ptr_named, - .field_val_named, .func, .func_inferred, .func_fancy, @@ -6156,37 +6153,28 @@ fn fieldAccess( scope: *Scope, ri: ResultInfo, node: Ast.Node.Index, -) InnerError!Zir.Inst.Ref { - switch (ri.rl) { - .ref, .ref_coerced_ty => return addFieldAccess(.field_ptr, gz, scope, .{ .rl = .ref }, node), - else => { - const access = try addFieldAccess(.field_val, gz, scope, .{ .rl = .none }, node); - return rvalue(gz, ri, access, node); - }, - } -} - -fn addFieldAccess( - tag: Zir.Inst.Tag, - gz: *GenZir, - scope: *Scope, - lhs_ri: ResultInfo, - node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; const object_node, const field_ident = tree.nodeData(node).node_and_token; const str_index = try astgen.identAsString(field_ident); - const lhs = try expr(gz, scope, lhs_ri, object_node); + const lhs = try expr(gz, scope, .{ .rl = .ref }, object_node); const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); try emitDbgStmt(gz, cursor); - return gz.addPlNode(tag, node, Zir.Inst.Field{ + const ref = try gz.addPlNode(.field_ptr, node, Zir.Inst.Field{ .lhs = lhs, .field_name_start = str_index, }); + switch (ri.rl) { + .ref, .ref_coerced_ty => return ref, + else => { + const loaded = try gz.addUnNode(.load, ref, node); + return rvalue(gz, ri, loaded, node); + }, + } } fn arrayAccess( @@ -6196,28 +6184,17 @@ fn arrayAccess( node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const tree = gz.astgen.tree; + const lhs_node, const rhs_node = tree.nodeData(node).node_and_node; + const lhs = try expr(gz, scope, .{ .rl = .ref }, lhs_node); + const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); + const rhs = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, rhs_node); + try emitDbgStmt(gz, cursor); + const ref = try gz.addPlNode(.elem_ptr_node, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs }); switch (ri.rl) { - .ref, .ref_coerced_ty => { - const lhs_node, const rhs_node = tree.nodeData(node).node_and_node; - const lhs = try expr(gz, scope, .{ .rl = .ref }, lhs_node); - - const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); - - const rhs = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, rhs_node); - try emitDbgStmt(gz, cursor); - - return gz.addPlNode(.elem_ptr_node, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs }); - }, + .ref, .ref_coerced_ty => return ref, else => { - const lhs_node, const rhs_node = tree.nodeData(node).node_and_node; - const lhs = try expr(gz, scope, .{ .rl = .none }, lhs_node); - - const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); - - const rhs = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, rhs_node); - try emitDbgStmt(gz, cursor); - - return rvalue(gz, ri, try gz.addPlNode(.elem_val_node, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs }), node); + const loaded = try gz.addUnNode(.load, ref, node); + return rvalue(gz, ri, loaded, node); }, } } @@ -9286,17 +9263,13 @@ fn builtinCall( return rvalue(gz, ri, result, node); }, .field => { - if (ri.rl == .ref or ri.rl == .ref_coerced_ty) { - return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ - .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]), - .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .field_name), - }); - } - const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{ - .lhs = try expr(gz, scope, .{ .rl = .none }, params[0]), + const ref = try gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ + .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]), .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .field_name), }); - return rvalue(gz, ri, result, node); + if (ri.rl == .ref or ri.rl == .ref_coerced_ty) return ref; + const loaded = try gz.addUnNode(.load, ref, node); + return rvalue(gz, ri, loaded, node); }, .FieldType => { const ty_inst = try typeExpr(gz, scope, params[0]); diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig index e4728dc7ada1..f5025d0f6ad3 100644 --- a/lib/std/zig/Zir.zig +++ b/lib/std/zig/Zir.zig @@ -1,6 +1,6 @@ //! Zig Intermediate Representation. //! -//! Astgen.zig converts AST nodes to these untyped IR instructions. Next, +//! `std.zig.AstGen` converts AST nodes to these untyped IR instructions. Next, //! Sema.zig processes these into AIR. //! The minimum amount of information needed to represent a list of ZIR instructions. //! Once this structure is completed, it can be used to generate AIR, followed by @@ -442,8 +442,7 @@ pub const Inst = struct { elem_ptr, /// Given an array, slice, or pointer, returns the element at the provided index. /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`. - elem_val_node, - /// Same as `elem_val_node` but used only for for loop. + /// Used only for for loop. /// Uses the `pl_node` union field. AST node is the condition of a for loop. /// Payload is `Bin`. /// No OOB safety check is emitted. @@ -472,19 +471,10 @@ pub const Inst = struct { /// to the named field. The field name is stored in string_bytes. Used by a.b syntax. /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field. field_ptr, - /// Given a struct or object that contains virtual fields, returns the named field. - /// The field name is stored in string_bytes. Used by a.b syntax. - /// This instruction also accepts a pointer. - /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field. - field_val, /// Given a pointer to a struct or object that contains virtual fields, returns a pointer /// to the named field. The field name is a comptime instruction. Used by @field. /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed. field_ptr_named, - /// Given a struct or object that contains virtual fields, returns the named field. - /// The field name is a comptime instruction. Used by @field. - /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed. - field_val_named, /// Returns a function type, or a function instance, depending on whether /// the body_len is 0. Calling convention is auto. /// Uses the `pl_node` union field. `payload_index` points to a `Func`. @@ -1138,16 +1128,13 @@ pub const Inst = struct { .elem_ptr, .elem_val, .elem_ptr_node, - .elem_val_node, .elem_val_imm, .ensure_result_used, .ensure_result_non_error, .ensure_err_union_payload_void, .@"export", .field_ptr, - .field_val, .field_ptr_named, - .field_val_named, .func, .func_inferred, .func_fancy, @@ -1432,12 +1419,9 @@ pub const Inst = struct { .elem_ptr, .elem_val, .elem_ptr_node, - .elem_val_node, .elem_val_imm, .field_ptr, - .field_val, .field_ptr_named, - .field_val_named, .func, .func_inferred, .func_fancy, @@ -1679,7 +1663,6 @@ pub const Inst = struct { .elem_ptr = .pl_node, .elem_ptr_node = .pl_node, .elem_val = .pl_node, - .elem_val_node = .pl_node, .elem_val_imm = .elem_val_imm, .ensure_result_used = .un_node, .ensure_result_non_error = .un_node, @@ -1688,9 +1671,7 @@ pub const Inst = struct { .error_value = .str_tok, .@"export" = .pl_node, .field_ptr = .pl_node, - .field_val = .pl_node, .field_ptr_named = .pl_node, - .field_val_named = .pl_node, .func = .pl_node, .func_inferred = .pl_node, .func_fancy = .pl_node, @@ -4215,7 +4196,6 @@ fn findTrackableInner( .div, .elem_ptr_node, .elem_ptr, - .elem_val_node, .elem_val, .elem_val_imm, .ensure_result_used, @@ -4225,9 +4205,7 @@ fn findTrackableInner( .error_value, .@"export", .field_ptr, - .field_val, .field_ptr_named, - .field_val_named, .import, .int, .int_big, diff --git a/src/Sema.zig b/src/Sema.zig index 007e1a7feff9..847658a97cc4 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1193,7 +1193,6 @@ fn analyzeBodyInner( .elem_ptr => try sema.zirElemPtr(block, inst), .elem_ptr_node => try sema.zirElemPtrNode(block, inst), .elem_val => try sema.zirElemVal(block, inst), - .elem_val_node => try sema.zirElemValNode(block, inst), .elem_val_imm => try sema.zirElemValImm(block, inst), .elem_type => try sema.zirElemType(block, inst), .indexable_ptr_elem_type => try sema.zirIndexablePtrElemType(block, inst), @@ -1211,8 +1210,6 @@ fn analyzeBodyInner( .error_value => try sema.zirErrorValue(block, inst), .field_ptr => try sema.zirFieldPtr(block, inst), .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), - .field_val => try sema.zirFieldVal(block, inst), - .field_val_named => try sema.zirFieldValNamed(block, inst), .func => try sema.zirFunc(block, inst, false), .func_inferred => try sema.zirFunc(block, inst, true), .func_fancy => try sema.zirFuncFancy(block, inst), @@ -9704,26 +9701,6 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! return block.addBitCast(dest_ty, operand); } -fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - - const pt = sema.pt; - const zcu = pt.zcu; - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; - const src = block.nodeOffset(inst_data.src_node); - const field_name_src = block.src(.{ .node_offset_field_name = inst_data.src_node }); - const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; - const field_name = try zcu.intern_pool.getOrPutString( - sema.gpa, - pt.tid, - sema.code.nullTerminatedString(extra.field_name_start), - .no_embedded_nulls, - ); - const object = try sema.resolveInst(extra.lhs); - return sema.fieldVal(block, src, object, field_name, field_name_src); -} - fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const tracy = trace(@src()); defer tracy.end(); @@ -9772,19 +9749,6 @@ fn zirStructInitFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi } } -fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; - const src = block.nodeOffset(inst_data.src_node); - const field_name_src = block.builtinCallArgSrc(inst_data.src_node, 1); - const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; - const object = try sema.resolveInst(extra.lhs); - const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ .simple = .field_name }); - return sema.fieldVal(block, src, object, field_name, field_name_src); -} - fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const tracy = trace(@src()); defer tracy.end(); @@ -10095,20 +10059,6 @@ fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air return sema.elemVal(block, src, array, elem_index, src, false); } -fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; - const src = block.nodeOffset(inst_data.src_node); - const elem_index_src = block.src(.{ .node_offset_array_access_index = inst_data.src_node }); - const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; - const array = try sema.resolveInst(extra.lhs); - const uncoerced_elem_index = try sema.resolveInst(extra.rhs); - const elem_index = try sema.coerce(block, .usize, uncoerced_elem_index, elem_index_src); - return sema.elemVal(block, src, array, elem_index, elem_index_src, true); -} - fn zirElemValImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const tracy = trace(@src()); defer tracy.end(); @@ -13605,7 +13555,6 @@ fn maybeErrorUnwrap( .str, .as_node, .panic, - .field_val, => {}, else => return false, } @@ -13624,7 +13573,6 @@ fn maybeErrorUnwrap( }, .str => try sema.zirStr(inst), .as_node => try sema.zirAsNode(block, inst), - .field_val => try sema.zirFieldVal(block, inst), .@"unreachable" => { try safetyPanicUnwrapError(sema, block, operand_src, operand); return true; diff --git a/src/print_zir.zig b/src/print_zir.zig index f875aaa5520b..005c8357fe93 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -406,7 +406,6 @@ const Writer = struct { .memset, .memmove, .elem_ptr_node, - .elem_val_node, .elem_ptr, .elem_val, .array_type, @@ -450,15 +449,12 @@ const Writer = struct { .switch_block_err_union => try self.writeSwitchBlockErrUnion(stream, inst), - .field_val, .field_ptr, .decl_literal, .decl_literal_no_coerce, => try self.writePlNodeField(stream, inst), - .field_ptr_named, - .field_val_named, - => try self.writePlNodeFieldNamed(stream, inst), + .field_ptr_named => try self.writePlNodeFieldNamed(stream, inst), .as_node, .as_shift_operand => try self.writeAs(stream, inst), From bfb58c25a1d6aeff48503a6dbcde6938d64bbdf3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 2 Sep 2025 23:10:18 -0700 Subject: [PATCH 02/12] llvm backend: remove canElideLoad mechanism --- src/Air/Liveness.zig | 495 ------------------------------------------- src/codegen/llvm.zig | 102 ++------- 2 files changed, 21 insertions(+), 576 deletions(-) diff --git a/src/Air/Liveness.zig b/src/Air/Liveness.zig index 65e78e089e86..58169730e880 100644 --- a/src/Air/Liveness.zig +++ b/src/Air/Liveness.zig @@ -207,501 +207,6 @@ pub fn operandDies(l: Liveness, inst: Air.Inst.Index, operand: OperandInt) bool return (l.tomb_bits[usize_index] & mask) != 0; } -const OperandCategory = enum { - /// The operand lives on, but this instruction cannot possibly mutate memory. - none, - /// The operand lives on and this instruction can mutate memory. - write, - /// The operand dies at this instruction. - tomb, - /// The operand lives on, and this instruction is noreturn. - noret, - /// This instruction is too complicated for analysis, no information is available. - complex, -}; - -/// Given an instruction that we are examining, and an operand that we are looking for, -/// returns a classification. -pub fn categorizeOperand( - l: Liveness, - air: Air, - zcu: *Zcu, - inst: Air.Inst.Index, - operand: Air.Inst.Index, - ip: *const InternPool, -) OperandCategory { - const air_tags = air.instructions.items(.tag); - const air_datas = air.instructions.items(.data); - const operand_ref = operand.toRef(); - switch (air_tags[@intFromEnum(inst)]) { - .add, - .add_safe, - .add_wrap, - .add_sat, - .add_optimized, - .sub, - .sub_safe, - .sub_wrap, - .sub_sat, - .sub_optimized, - .mul, - .mul_safe, - .mul_wrap, - .mul_sat, - .mul_optimized, - .div_float, - .div_trunc, - .div_floor, - .div_exact, - .rem, - .mod, - .bit_and, - .bit_or, - .xor, - .cmp_lt, - .cmp_lte, - .cmp_eq, - .cmp_gte, - .cmp_gt, - .cmp_neq, - .bool_and, - .bool_or, - .array_elem_val, - .slice_elem_val, - .ptr_elem_val, - .shl, - .shl_exact, - .shl_sat, - .shr, - .shr_exact, - .min, - .max, - .div_float_optimized, - .div_trunc_optimized, - .div_floor_optimized, - .div_exact_optimized, - .rem_optimized, - .mod_optimized, - .neg_optimized, - .cmp_lt_optimized, - .cmp_lte_optimized, - .cmp_eq_optimized, - .cmp_gte_optimized, - .cmp_gt_optimized, - .cmp_neq_optimized, - => { - const o = air_datas[@intFromEnum(inst)].bin_op; - if (o.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - if (o.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none); - return .none; - }, - - .store, - .store_safe, - .atomic_store_unordered, - .atomic_store_monotonic, - .atomic_store_release, - .atomic_store_seq_cst, - .set_union_tag, - .memset, - .memset_safe, - .memcpy, - .memmove, - => { - const o = air_datas[@intFromEnum(inst)].bin_op; - if (o.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write); - if (o.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .write); - return .write; - }, - - .vector_store_elem => { - const o = air_datas[@intFromEnum(inst)].vector_store_elem; - const extra = air.extraData(Air.Bin, o.payload).data; - if (o.vector_ptr == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write); - if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none); - if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 2, .none); - return .write; - }, - - .arg, - .alloc, - .inferred_alloc, - .inferred_alloc_comptime, - .ret_ptr, - .trap, - .breakpoint, - .repeat, - .switch_dispatch, - .dbg_stmt, - .dbg_empty_stmt, - .unreach, - .ret_addr, - .frame_addr, - .wasm_memory_size, - .err_return_trace, - .save_err_return_trace_index, - .runtime_nav_ptr, - .c_va_start, - .work_item_id, - .work_group_size, - .work_group_id, - => return .none, - - .not, - .bitcast, - .load, - .fpext, - .fptrunc, - .intcast, - .intcast_safe, - .trunc, - .optional_payload, - .optional_payload_ptr, - .wrap_optional, - .unwrap_errunion_payload, - .unwrap_errunion_err, - .unwrap_errunion_payload_ptr, - .unwrap_errunion_err_ptr, - .wrap_errunion_payload, - .wrap_errunion_err, - .slice_ptr, - .slice_len, - .ptr_slice_len_ptr, - .ptr_slice_ptr_ptr, - .struct_field_ptr_index_0, - .struct_field_ptr_index_1, - .struct_field_ptr_index_2, - .struct_field_ptr_index_3, - .array_to_slice, - .int_from_float, - .int_from_float_optimized, - .int_from_float_safe, - .int_from_float_optimized_safe, - .float_from_int, - .get_union_tag, - .clz, - .ctz, - .popcount, - .byte_swap, - .bit_reverse, - .splat, - .error_set_has_value, - .addrspace_cast, - .c_va_arg, - .c_va_copy, - .abs, - => { - const o = air_datas[@intFromEnum(inst)].ty_op; - if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - return .none; - }, - - .optional_payload_ptr_set, - .errunion_payload_ptr_set, - => { - const o = air_datas[@intFromEnum(inst)].ty_op; - if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write); - return .write; - }, - - .is_null, - .is_non_null, - .is_null_ptr, - .is_non_null_ptr, - .is_err, - .is_non_err, - .is_err_ptr, - .is_non_err_ptr, - .is_named_enum_value, - .tag_name, - .error_name, - .sqrt, - .sin, - .cos, - .tan, - .exp, - .exp2, - .log, - .log2, - .log10, - .floor, - .ceil, - .round, - .trunc_float, - .neg, - .cmp_lt_errors_len, - .c_va_end, - => { - const o = air_datas[@intFromEnum(inst)].un_op; - if (o == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - return .none; - }, - - .ret, - .ret_safe, - .ret_load, - => { - const o = air_datas[@intFromEnum(inst)].un_op; - if (o == operand_ref) return matchOperandSmallIndex(l, inst, 0, .noret); - return .noret; - }, - - .set_err_return_trace => { - const o = air_datas[@intFromEnum(inst)].un_op; - if (o == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write); - return .write; - }, - - .add_with_overflow, - .sub_with_overflow, - .mul_with_overflow, - .shl_with_overflow, - .ptr_add, - .ptr_sub, - .ptr_elem_ptr, - .slice_elem_ptr, - .slice, - => { - const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; - const extra = air.extraData(Air.Bin, ty_pl.payload).data; - if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none); - return .none; - }, - - .dbg_var_ptr, - .dbg_var_val, - .dbg_arg_inline, - => { - const o = air_datas[@intFromEnum(inst)].pl_op.operand; - if (o == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - return .none; - }, - - .prefetch => { - const prefetch = air_datas[@intFromEnum(inst)].prefetch; - if (prefetch.ptr == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - return .none; - }, - - .call, .call_always_tail, .call_never_tail, .call_never_inline => { - const inst_data = air_datas[@intFromEnum(inst)].pl_op; - const callee = inst_data.operand; - const extra = air.extraData(Air.Call, inst_data.payload); - const args = @as([]const Air.Inst.Ref, @ptrCast(air.extra.items[extra.end..][0..extra.data.args_len])); - if (args.len + 1 <= bpi - 1) { - if (callee == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write); - for (args, 0..) |arg, i| { - if (arg == operand_ref) return matchOperandSmallIndex(l, inst, @as(OperandInt, @intCast(i + 1)), .write); - } - return .write; - } - var bt = l.iterateBigTomb(inst); - if (bt.feed()) { - if (callee == operand_ref) return .tomb; - } else { - if (callee == operand_ref) return .write; - } - for (args) |arg| { - if (bt.feed()) { - if (arg == operand_ref) return .tomb; - } else { - if (arg == operand_ref) return .write; - } - } - return .write; - }, - .select => { - const pl_op = air_datas[@intFromEnum(inst)].pl_op; - const extra = air.extraData(Air.Bin, pl_op.payload).data; - if (pl_op.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none); - if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 2, .none); - return .none; - }, - .shuffle_one => { - const unwrapped = air.unwrapShuffleOne(zcu, inst); - if (unwrapped.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - return .none; - }, - .shuffle_two => { - const unwrapped = air.unwrapShuffleTwo(zcu, inst); - if (unwrapped.operand_a == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - if (unwrapped.operand_b == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none); - return .none; - }, - .reduce, .reduce_optimized => { - const reduce = air_datas[@intFromEnum(inst)].reduce; - if (reduce.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - return .none; - }, - .cmp_vector, .cmp_vector_optimized => { - const extra = air.extraData(Air.VectorCmp, air_datas[@intFromEnum(inst)].ty_pl.payload).data; - if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none); - return .none; - }, - .aggregate_init => { - const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; - const aggregate_ty = ty_pl.ty.toType(); - const len = @as(usize, @intCast(aggregate_ty.arrayLenIp(ip))); - const elements = @as([]const Air.Inst.Ref, @ptrCast(air.extra.items[ty_pl.payload..][0..len])); - - if (elements.len <= bpi - 1) { - for (elements, 0..) |elem, i| { - if (elem == operand_ref) return matchOperandSmallIndex(l, inst, @as(OperandInt, @intCast(i)), .none); - } - return .none; - } - - var bt = l.iterateBigTomb(inst); - for (elements) |elem| { - if (bt.feed()) { - if (elem == operand_ref) return .tomb; - } else { - if (elem == operand_ref) return .write; - } - } - return .write; - }, - .union_init => { - const extra = air.extraData(Air.UnionInit, air_datas[@intFromEnum(inst)].ty_pl.payload).data; - if (extra.init == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - return .none; - }, - .struct_field_ptr, .struct_field_val => { - const extra = air.extraData(Air.StructField, air_datas[@intFromEnum(inst)].ty_pl.payload).data; - if (extra.struct_operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - return .none; - }, - .field_parent_ptr => { - const extra = air.extraData(Air.FieldParentPtr, air_datas[@intFromEnum(inst)].ty_pl.payload).data; - if (extra.field_ptr == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - return .none; - }, - .cmpxchg_strong, .cmpxchg_weak => { - const extra = air.extraData(Air.Cmpxchg, air_datas[@intFromEnum(inst)].ty_pl.payload).data; - if (extra.ptr == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write); - if (extra.expected_value == operand_ref) return matchOperandSmallIndex(l, inst, 1, .write); - if (extra.new_value == operand_ref) return matchOperandSmallIndex(l, inst, 2, .write); - return .write; - }, - .mul_add => { - const pl_op = air_datas[@intFromEnum(inst)].pl_op; - const extra = air.extraData(Air.Bin, pl_op.payload).data; - if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none); - if (pl_op.operand == operand_ref) return matchOperandSmallIndex(l, inst, 2, .none); - return .none; - }, - .atomic_load => { - const ptr = air_datas[@intFromEnum(inst)].atomic_load.ptr; - if (ptr == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - return .none; - }, - .atomic_rmw => { - const pl_op = air_datas[@intFromEnum(inst)].pl_op; - const extra = air.extraData(Air.AtomicRmw, pl_op.payload).data; - if (pl_op.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write); - if (extra.operand == operand_ref) return matchOperandSmallIndex(l, inst, 1, .write); - return .write; - }, - - .br => { - const br = air_datas[@intFromEnum(inst)].br; - if (br.operand == operand_ref) return matchOperandSmallIndex(l, operand, 0, .noret); - return .noret; - }, - .assembly => { - return .complex; - }, - .block, .dbg_inline_block => |tag| { - const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; - const body: []const Air.Inst.Index = @ptrCast(switch (tag) { - inline .block, .dbg_inline_block => |comptime_tag| body: { - const extra = air.extraData(switch (comptime_tag) { - .block => Air.Block, - .dbg_inline_block => Air.DbgInlineBlock, - else => unreachable, - }, ty_pl.payload); - break :body air.extra.items[extra.end..][0..extra.data.body_len]; - }, - else => unreachable, - }); - - if (body.len == 1 and air_tags[@intFromEnum(body[0])] == .cond_br) { - // Peephole optimization for "panic-like" conditionals, which have - // one empty branch and another which calls a `noreturn` function. - // This allows us to infer that safety checks do not modify memory, - // as far as control flow successors are concerned. - - const inst_data = air_datas[@intFromEnum(body[0])].pl_op; - const cond_extra = air.extraData(Air.CondBr, inst_data.payload); - if (inst_data.operand == operand_ref and operandDies(l, body[0], 0)) - return .tomb; - - if (cond_extra.data.then_body_len > 2 or cond_extra.data.else_body_len > 2) - return .complex; - - const then_body: []const Air.Inst.Index = @ptrCast(air.extra.items[cond_extra.end..][0..cond_extra.data.then_body_len]); - const else_body: []const Air.Inst.Index = @ptrCast(air.extra.items[cond_extra.end + cond_extra.data.then_body_len ..][0..cond_extra.data.else_body_len]); - if (then_body.len > 1 and air_tags[@intFromEnum(then_body[1])] != .unreach) - return .complex; - if (else_body.len > 1 and air_tags[@intFromEnum(else_body[1])] != .unreach) - return .complex; - - var operand_live: bool = true; - for (&[_]Air.Inst.Index{ then_body[0], else_body[0] }) |cond_inst| { - if (l.categorizeOperand(air, zcu, cond_inst, operand, ip) == .tomb) - operand_live = false; - - switch (air_tags[@intFromEnum(cond_inst)]) { - .br => { // Breaks immediately back to block - const br = air_datas[@intFromEnum(cond_inst)].br; - if (br.block_inst != inst) - return .complex; - }, - .call => {}, // Calls a noreturn function - else => return .complex, - } - } - return if (operand_live) .none else .tomb; - } - - return .complex; - }, - - .@"try", - .try_cold, - .try_ptr, - .try_ptr_cold, - .loop, - .cond_br, - .switch_br, - .loop_switch_br, - => return .complex, - - .wasm_memory_grow => { - const pl_op = air_datas[@intFromEnum(inst)].pl_op; - if (pl_op.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); - return .none; - }, - } -} - -fn matchOperandSmallIndex( - l: Liveness, - inst: Air.Inst.Index, - operand: OperandInt, - default: OperandCategory, -) OperandCategory { - if (operandDies(l, inst, operand)) { - return .tomb; - } else { - return default; - } -} - /// Higher level API. pub const CondBrSlices = struct { then_deaths: []const Air.Inst.Index, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 9435087edc19..48ac1322d2e0 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -4980,8 +4980,8 @@ pub const FuncGen = struct { .breakpoint => try self.airBreakpoint(inst), .ret_addr => try self.airRetAddr(inst), .frame_addr => try self.airFrameAddress(inst), - .@"try" => try self.airTry(body[i..], false), - .try_cold => try self.airTry(body[i..], true), + .@"try" => try self.airTry(inst, false), + .try_cold => try self.airTry(inst, true), .try_ptr => try self.airTryPtr(inst, false), .try_ptr_cold => try self.airTryPtr(inst, true), .intcast => try self.airIntCast(inst, false), @@ -4989,7 +4989,7 @@ pub const FuncGen = struct { .trunc => try self.airTrunc(inst), .fptrunc => try self.airFptrunc(inst), .fpext => try self.airFpext(inst), - .load => try self.airLoad(body[i..]), + .load => try self.airLoad(inst), .not => try self.airNot(inst), .store => try self.airStore(inst, false), .store_safe => try self.airStore(inst, true), @@ -5045,7 +5045,7 @@ pub const FuncGen = struct { .atomic_store_seq_cst => try self.airAtomicStore(inst, .seq_cst), .struct_field_ptr => try self.airStructFieldPtr(inst), - .struct_field_val => try self.airStructFieldVal(body[i..]), + .struct_field_val => try self.airStructFieldVal(inst), .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0), .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1), @@ -5054,18 +5054,18 @@ pub const FuncGen = struct { .field_parent_ptr => try self.airFieldParentPtr(inst), - .array_elem_val => try self.airArrayElemVal(body[i..]), - .slice_elem_val => try self.airSliceElemVal(body[i..]), + .array_elem_val => try self.airArrayElemVal(inst), + .slice_elem_val => try self.airSliceElemVal(inst), .slice_elem_ptr => try self.airSliceElemPtr(inst), - .ptr_elem_val => try self.airPtrElemVal(body[i..]), + .ptr_elem_val => try self.airPtrElemVal(inst), .ptr_elem_ptr => try self.airPtrElemPtr(inst), - .optional_payload => try self.airOptionalPayload(body[i..]), + .optional_payload => try self.airOptionalPayload(inst), .optional_payload_ptr => try self.airOptionalPayloadPtr(inst), .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst), - .unwrap_errunion_payload => try self.airErrUnionPayload(body[i..], false), - .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(body[i..], true), + .unwrap_errunion_payload => try self.airErrUnionPayload(inst, false), + .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true), .unwrap_errunion_err => try self.airErrUnionErr(inst, false), .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true), .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), @@ -6266,19 +6266,14 @@ pub const FuncGen = struct { // No need to reset the insert cursor since this instruction is noreturn. } - fn airTry(self: *FuncGen, body_tail: []const Air.Inst.Index, err_cold: bool) !Builder.Value { - const pt = self.ng.pt; - const zcu = pt.zcu; - const inst = body_tail[0]; + fn airTry(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value { const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const err_union = try self.resolveInst(pl_op.operand); const extra = self.air.extraData(Air.Try, pl_op.payload); const body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]); const err_union_ty = self.typeOf(pl_op.operand); - const payload_ty = self.typeOfIndex(inst); - const can_elide_load = if (isByRef(payload_ty, zcu)) self.canElideLoad(body_tail) else false; const is_unused = self.liveness.isUnused(inst); - return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, is_unused, err_cold); + return lowerTry(self, err_union, body, err_union_ty, false, false, is_unused, err_cold); } fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value { @@ -6824,11 +6819,10 @@ pub const FuncGen = struct { return self.wip.gepStruct(slice_llvm_ty, slice_ptr, index, ""); } - fn airSliceElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value { + fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { const o = self.ng.object; const pt = self.ng.pt; const zcu = pt.zcu; - const inst = body_tail[0]; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const slice_ty = self.typeOf(bin_op.lhs); const slice = try self.resolveInst(bin_op.lhs); @@ -6838,9 +6832,6 @@ pub const FuncGen = struct { const base_ptr = try self.wip.extractValue(slice, &.{0}, ""); const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, ""); if (isByRef(elem_ty, zcu)) { - if (self.canElideLoad(body_tail)) - return ptr; - self.maybeMarkAllowZeroAccess(slice_ty.ptrInfo(zcu)); const slice_align = (slice_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu))).toLlvm(); @@ -6867,11 +6858,10 @@ pub const FuncGen = struct { return self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, ""); } - fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value { + fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { const o = self.ng.object; const pt = self.ng.pt; const zcu = pt.zcu; - const inst = body_tail[0]; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const array_ty = self.typeOf(bin_op.lhs); @@ -6884,9 +6874,7 @@ pub const FuncGen = struct { try o.builder.intValue(try o.lowerType(pt, Type.usize), 0), rhs, }; if (isByRef(elem_ty, zcu)) { - const elem_ptr = - try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, ""); - if (canElideLoad(self, body_tail)) return elem_ptr; + const elem_ptr = try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, ""); const elem_alignment = elem_ty.abiAlignment(zcu).toLlvm(); return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal); } else { @@ -6900,11 +6888,10 @@ pub const FuncGen = struct { return self.wip.extractElement(array_llvm_val, rhs, ""); } - fn airPtrElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value { + fn airPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { const o = self.ng.object; const pt = self.ng.pt; const zcu = pt.zcu; - const inst = body_tail[0]; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const ptr_ty = self.typeOf(bin_op.lhs); const elem_ty = ptr_ty.childType(zcu); @@ -6918,10 +6905,7 @@ pub const FuncGen = struct { else &.{rhs}, ""); if (isByRef(elem_ty, zcu)) { - if (self.canElideLoad(body_tail)) return ptr; - self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); - const ptr_align = (ptr_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu))).toLlvm(); return self.loadByRef(ptr, elem_ty, ptr_align, if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal); } @@ -6974,11 +6958,10 @@ pub const FuncGen = struct { return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index); } - fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value { + fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { const o = self.ng.object; const pt = self.ng.pt; const zcu = pt.zcu; - const inst = body_tail[0]; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; const struct_ty = self.typeOf(struct_field.struct_operand); @@ -7052,9 +7035,6 @@ pub const FuncGen = struct { .flags = .{ .alignment = alignment }, }); if (isByRef(field_ty, zcu)) { - if (canElideLoad(self, body_tail)) - return field_ptr; - assert(alignment != .none); const field_alignment = alignment.toLlvm(); return self.loadByRef(field_ptr, field_ty, field_alignment, .normal); @@ -7070,7 +7050,6 @@ pub const FuncGen = struct { try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, ""); const payload_alignment = layout.payload_align.toLlvm(); if (isByRef(field_ty, zcu)) { - if (canElideLoad(self, body_tail)) return field_ptr; return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal); } else { return self.loadTruncate(.normal, field_ty, field_ptr, payload_alignment); @@ -7829,11 +7808,10 @@ pub const FuncGen = struct { return self.wip.gepStruct(optional_llvm_ty, operand, 0, ""); } - fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value { + fn airOptionalPayload(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { const o = self.ng.object; const pt = self.ng.pt; const zcu = pt.zcu; - const inst = body_tail[0]; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const operand = try self.resolveInst(ty_op.operand); const optional_ty = self.typeOf(ty_op.operand); @@ -7846,19 +7824,13 @@ pub const FuncGen = struct { } const opt_llvm_ty = try o.lowerType(pt, optional_ty); - const can_elide_load = if (isByRef(payload_ty, zcu)) self.canElideLoad(body_tail) else false; - return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty, can_elide_load); + return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty, false); } - fn airErrUnionPayload( - self: *FuncGen, - body_tail: []const Air.Inst.Index, - operand_is_ptr: bool, - ) !Builder.Value { + fn airErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index, operand_is_ptr: bool) !Builder.Value { const o = self.ng.object; const pt = self.ng.pt; const zcu = pt.zcu; - const inst = body_tail[0]; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const operand = try self.resolveInst(ty_op.operand); const operand_ty = self.typeOf(ty_op.operand); @@ -7877,7 +7849,6 @@ pub const FuncGen = struct { const payload_alignment = payload_ty.abiAlignment(zcu).toLlvm(); const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); if (isByRef(payload_ty, zcu)) { - if (self.canElideLoad(body_tail)) return payload_ptr; return self.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal); } const payload_llvm_ty = err_union_llvm_ty.structFields(&o.builder)[offset]; @@ -9740,45 +9711,14 @@ pub const FuncGen = struct { return .none; } - /// As an optimization, we want to avoid unnecessary copies of isByRef=true - /// types. Here, we scan forward in the current block, looking to see if - /// this load dies before any side effects occur. In such case, we can - /// safely return the operand without making a copy. - /// - /// The first instruction of `body_tail` is the one whose copy we want to elide. - fn canElideLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) bool { - const zcu = fg.ng.pt.zcu; - const ip = &zcu.intern_pool; - for (body_tail[1..]) |body_inst| { - switch (fg.liveness.categorizeOperand(fg.air, zcu, body_inst, body_tail[0], ip)) { - .none => continue, - .write, .noret, .complex => return false, - .tomb => return true, - } - } - // The only way to get here is to hit the end of a loop instruction - // (implicit repeat). - return false; - } - - fn airLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value { + fn airLoad(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value { const pt = fg.ng.pt; const zcu = pt.zcu; - const inst = body_tail[0]; const ty_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const ptr_ty = fg.typeOf(ty_op.operand); const ptr_info = ptr_ty.ptrInfo(zcu); const ptr = try fg.resolveInst(ty_op.operand); - - elide: { - if (ptr_info.flags.alignment != .none) break :elide; - if (!isByRef(Type.fromInterned(ptr_info.child), zcu)) break :elide; - if (!canElideLoad(fg, body_tail)) break :elide; - return ptr; - } - fg.maybeMarkAllowZeroAccess(ptr_info); - return fg.load(ptr, ptr_ty); } From acdee8e06b1fc05df8e7663305d89199d0470247 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 3 Sep 2025 15:25:41 -0700 Subject: [PATCH 03/12] std.Progress: avoid problematic catch syntax --- lib/std/Progress.zig | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index 38a0258649bf..060ba085b682 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -1248,7 +1248,9 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } { i += progress_pulsing.len; } else { const percent = completed_items * 100 / estimated_total; - i += (std.fmt.bufPrint(buf[i..], @"progress_normal {d}", .{percent}) catch &.{}).len; + if (std.fmt.bufPrint(buf[i..], @"progress_normal {d}", .{percent})) |b| { + i += b.len; + } else |_| {} } }, .success => { @@ -1265,7 +1267,9 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } { i += progress_pulsing_error.len; } else { const percent = completed_items * 100 / estimated_total; - i += (std.fmt.bufPrint(buf[i..], @"progress_error {d}", .{percent}) catch &.{}).len; + if (std.fmt.bufPrint(buf[i..], @"progress_error {d}", .{percent})) |b| { + i += b.len; + } else |_| {} } }, } @@ -1364,12 +1368,18 @@ fn computeNode( if (!is_empty_root) { if (name.len != 0 or estimated_total > 0) { if (estimated_total > 0) { - i += (std.fmt.bufPrint(buf[i..], "[{d}/{d}] ", .{ completed_items, estimated_total }) catch &.{}).len; + if (std.fmt.bufPrint(buf[i..], "[{d}/{d}] ", .{ completed_items, estimated_total })) |b| { + i += b.len; + } else |_| {} } else if (completed_items != 0) { - i += (std.fmt.bufPrint(buf[i..], "[{d}] ", .{completed_items}) catch &.{}).len; + if (std.fmt.bufPrint(buf[i..], "[{d}] ", .{completed_items})) |b| { + i += b.len; + } else |_| {} } if (name.len != 0) { - i += (std.fmt.bufPrint(buf[i..], "{s}", .{name}) catch &.{}).len; + if (std.fmt.bufPrint(buf[i..], "{s}", .{name})) |b| { + i += b.len; + } else |_| {} } } From 356482843bc06204cc220c1ffddff178f29f354b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 3 Sep 2025 16:08:06 -0700 Subject: [PATCH 04/12] compiler: require comptime vector indexes --- lib/std/testing.zig | 5 ++-- src/Sema.zig | 18 ++++------- test/behavior/math.zig | 3 +- test/behavior/vector.zig | 64 +++++++--------------------------------- 4 files changed, 18 insertions(+), 72 deletions(-) diff --git a/lib/std/testing.zig b/lib/std/testing.zig index b2dd271dc070..243b4a1850e0 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -135,9 +135,8 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void { .array => |array| try expectEqualSlices(array.child, &expected, &actual), .vector => |info| { - var i: usize = 0; - while (i < info.len) : (i += 1) { - if (!std.meta.eql(expected[i], actual[i])) { + inline for (0..info.len) |i| { + if (expected[i] != actual[i]) { print("index {d} incorrect. expected {any}, found {any}\n", .{ i, expected[i], actual[i], }); diff --git a/src/Sema.zig b/src/Sema.zig index 847658a97cc4..9340e14338fe 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -27909,6 +27909,7 @@ fn elemVal( } } +/// Called when the index or indexable is runtime known. fn validateRuntimeElemAccess( sema: *Sema, block: *Block, @@ -28173,6 +28174,10 @@ fn elemPtrArray( try sema.validateRuntimeValue(block, array_ptr_src, array_ptr); } + if (offset == null and array_ty.zigTypeTag(zcu) == .vector) { + return sema.fail(block, elem_index_src, "vector index not comptime known", .{}); + } + // Runtime check is only needed if unable to comptime check. if (oob_safety and block.wantSafety() and offset == null) { const len_inst = try pt.intRef(.usize, array_len); @@ -31400,19 +31405,6 @@ fn analyzeLoad( } } - if (ptr_ty.ptrInfo(zcu).flags.vector_index == .runtime) { - const ptr_inst = ptr.toIndex().?; - const air_tags = sema.air_instructions.items(.tag); - if (air_tags[@intFromEnum(ptr_inst)] == .ptr_elem_ptr) { - const ty_pl = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].ty_pl; - const bin_op = sema.getTmpAir().extraData(Air.Bin, ty_pl.payload).data; - return block.addBinOp(.ptr_elem_val, bin_op.lhs, bin_op.rhs); - } - return sema.fail(block, ptr_src, "unable to determine vector element index of type '{f}'", .{ - ptr_ty.fmt(pt), - }); - } - return block.addTyOp(.load, elem_ty, ptr); } diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 679c94a78e39..c178795e4533 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -138,8 +138,7 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void { const len_b = @typeInfo(@TypeOf(b)).vector.len; try expect(len_a == len_b); - var i: usize = 0; - while (i < len_a) : (i += 1) { + inline for (0..len_a) |i| { try expect(a[i] == b[i]); } } diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 7ffc10b5bf28..752c7210957f 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -440,49 +440,6 @@ test "store vector elements via comptime index" { try comptime S.doTheTest(); } -test "load vector elements via runtime index" { - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - - const S = struct { - fn doTheTest() !void { - var v: @Vector(4, i32) = [_]i32{ 1, 2, 3, undefined }; - _ = &v; - var i: u32 = 0; - try expect(v[i] == 1); - i += 1; - try expect(v[i] == 2); - i += 1; - try expect(v[i] == 3); - } - }; - - try S.doTheTest(); - try comptime S.doTheTest(); -} - -test "store vector elements via runtime index" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - - const S = struct { - fn doTheTest() !void { - var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; - var i: u32 = 2; - v[i] = 1; - try expect(v[1] == 5); - try expect(v[2] == 1); - i += 1; - v[i] = -364; - try expect(-364 == v[3]); - } - }; - - try S.doTheTest(); - try comptime S.doTheTest(); -} - test "initialize vector which is a struct field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -566,20 +523,20 @@ test "vector division operators" { }; if (!is_signed_int) { const d0 = x / y; - for (@as([4]T, d0), 0..) |v, i| { + inline for (@as([4]T, d0), 0..) |v, i| { try expect(x[i] / y[i] == v); } } const d1 = @divExact(x, y); - for (@as([4]T, d1), 0..) |v, i| { + inline for (@as([4]T, d1), 0..) |v, i| { try expect(@divExact(x[i], y[i]) == v); } const d2 = @divFloor(x, y); - for (@as([4]T, d2), 0..) |v, i| { + inline for (@as([4]T, d2), 0..) |v, i| { try expect(@divFloor(x[i], y[i]) == v); } const d3 = @divTrunc(x, y); - for (@as([4]T, d3), 0..) |v, i| { + inline for (@as([4]T, d3), 0..) |v, i| { try expect(@divTrunc(x[i], y[i]) == v); } } @@ -591,16 +548,16 @@ test "vector division operators" { }; if (!is_signed_int and @typeInfo(T) != .float) { const r0 = x % y; - for (@as([4]T, r0), 0..) |v, i| { + inline for (@as([4]T, r0), 0..) |v, i| { try expect(x[i] % y[i] == v); } } const r1 = @mod(x, y); - for (@as([4]T, r1), 0..) |v, i| { + inline for (@as([4]T, r1), 0..) |v, i| { try expect(@mod(x[i], y[i]) == v); } const r2 = @rem(x, y); - for (@as([4]T, r2), 0..) |v, i| { + inline for (@as([4]T, r2), 0..) |v, i| { try expect(@rem(x[i], y[i]) == v); } } @@ -654,7 +611,7 @@ test "vector bitwise not operator" { const S = struct { fn doTheTestNot(comptime T: type, x: @Vector(4, T)) !void { const y = ~x; - for (@as([4]T, y), 0..) |v, i| { + inline for (@as([4]T, y), 0..) |v, i| { try expect(~x[i] == v); } } @@ -688,7 +645,7 @@ test "vector boolean not operator" { const S = struct { fn doTheTestNot(comptime T: type, x: @Vector(4, T)) !void { const y = !x; - for (@as([4]T, y), 0..) |v, i| { + inline for (@as([4]T, y), 0..) |v, i| { try expect(!x[i] == v); } } @@ -1397,8 +1354,7 @@ test "store packed vector element" { var v = @Vector(4, u1){ 1, 1, 1, 1 }; try expectEqual(@Vector(4, u1){ 1, 1, 1, 1 }, v); - var index: usize = 0; - _ = &index; + const index: usize = 0; v[index] = 0; try expectEqual(@Vector(4, u1){ 0, 1, 1, 1 }, v); } From 80c069cd8c6b435e509ce33bb5e316a7e5cb6783 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 3 Sep 2025 16:35:02 -0700 Subject: [PATCH 05/12] Sema: fix accessing ptr field of double array pointer with sentinel --- src/Sema.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Sema.zig b/src/Sema.zig index 9340e14338fe..97b5e0552054 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -26829,7 +26829,7 @@ fn fieldPtr( const ptr_info = object_ty.ptrInfo(zcu); const new_ptr_ty = try pt.ptrTypeSema(.{ .child = Type.fromInterned(ptr_info.child).childType(zcu).toIntern(), - .sentinel = if (object_ty.sentinel(zcu)) |s| s.toIntern() else .none, + .sentinel = if (inner_ty.sentinel(zcu)) |s| s.toIntern() else .none, .flags = .{ .size = .many, .alignment = ptr_info.flags.alignment, From 331467a17113dee201766bea71f531bdc59bb6ec Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 3 Sep 2025 16:37:19 -0700 Subject: [PATCH 06/12] std: update to avoid runtime vector indexes --- lib/std/Target.zig | 5 +++-- lib/std/crypto/chacha20.zig | 2 +- lib/std/json/static.zig | 26 ++++++++++++++++++++++---- lib/std/meta.zig | 5 ++--- lib/std/testing.zig | 3 +-- lib/std/zon/Serializer.zig | 2 +- lib/std/zon/parse.zig | 12 ++++-------- 7 files changed, 34 insertions(+), 21 deletions(-) diff --git a/lib/std/Target.zig b/lib/std/Target.zig index 60f0b2e30407..5de020b79a96 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -1187,7 +1187,7 @@ pub const Cpu = struct { pub const Index = std.math.Log2Int(std.meta.Int(.unsigned, usize_count * @bitSizeOf(usize))); pub const ShiftInt = std.math.Log2Int(usize); - pub const empty = Set{ .ints = [1]usize{0} ** usize_count }; + pub const empty: Set = .{ .ints = @splat(0) }; pub fn isEmpty(set: Set) bool { return for (set.ints) |x| { @@ -1268,7 +1268,8 @@ pub const Cpu = struct { return struct { /// Populates only the feature bits specified. pub fn featureSet(features: []const F) Set { - var x = Set.empty; + if (@sizeOf(F) == 0) return .empty; + var x: Set = .empty; for (features) |feature| { x.addFeature(@intFromEnum(feature)); } diff --git a/lib/std/crypto/chacha20.zig b/lib/std/crypto/chacha20.zig index c4e84aad5345..17fb7e7ab3e5 100644 --- a/lib/std/crypto/chacha20.zig +++ b/lib/std/crypto/chacha20.zig @@ -216,7 +216,7 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type } fn hashToBytes(comptime dm: usize, out: *[64 * dm]u8, x: BlockVec) void { - for (0..dm) |d| { + inline for (0..dm) |d| { for (0..4) |i| { mem.writeInt(u32, out[64 * d + 16 * i + 0 ..][0..4], x[i][0 + 4 * d], .little); mem.writeInt(u32, out[64 * d + 16 * i + 4 ..][0..4], x[i][1 + 4 * d], .little); diff --git a/lib/std/json/static.zig b/lib/std/json/static.zig index ced6894027e5..4de5676bd65d 100644 --- a/lib/std/json/static.zig +++ b/lib/std/json/static.zig @@ -389,7 +389,7 @@ pub fn innerParse( switch (try source.peekNextTokenType()) { .array_begin => { // Typical array. - return internalParseArray(T, arrayInfo.child, arrayInfo.len, allocator, source, options); + return internalParseArray(T, arrayInfo.child, allocator, source, options); }, .string => { if (arrayInfo.child != u8) return error.UnexpectedToken; @@ -443,7 +443,7 @@ pub fn innerParse( .vector => |vecInfo| { switch (try source.peekNextTokenType()) { .array_begin => { - return internalParseArray(T, vecInfo.child, vecInfo.len, allocator, source, options); + return internalParseVector(T, vecInfo.child, vecInfo.len, allocator, source, options); }, else => return error.UnexpectedToken, } @@ -517,6 +517,25 @@ pub fn innerParse( } fn internalParseArray( + comptime T: type, + comptime Child: type, + allocator: Allocator, + source: anytype, + options: ParseOptions, +) !T { + assert(.array_begin == try source.next()); + + var r: T = undefined; + for (&r) |*elem| { + elem.* = try innerParse(Child, allocator, source, options); + } + + if (.array_end != try source.next()) return error.UnexpectedToken; + + return r; +} + +fn internalParseVector( comptime T: type, comptime Child: type, comptime len: comptime_int, @@ -527,8 +546,7 @@ fn internalParseArray( assert(.array_begin == try source.next()); var r: T = undefined; - var i: usize = 0; - while (i < len) : (i += 1) { + inline for (0..len) |i| { r[i] = try innerParse(Child, allocator, source, options); } diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 65b7d60c1854..3dd725aab9df 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -743,9 +743,8 @@ pub fn eql(a: anytype, b: @TypeOf(a)) bool { return true; }, .vector => |info| { - var i: usize = 0; - while (i < info.len) : (i += 1) { - if (!eql(a[i], b[i])) return false; + inline for (0..info.len) |i| { + if (a[i] != b[i]) return false; } return true; }, diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 243b4a1850e0..1cc1c4b4b557 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -827,8 +827,7 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe print("Vector len not the same, expected {d}, found {d}\n", .{ info.len, @typeInfo(@TypeOf(actual)).vector.len }); return error.TestExpectedEqual; } - var i: usize = 0; - while (i < info.len) : (i += 1) { + inline for (0..info.len) |i| { expectEqualDeep(expected[i], actual[i]) catch |e| { print("index {d} incorrect. expected {any}, found {any}\n", .{ i, expected[i], actual[i], diff --git a/lib/std/zon/Serializer.zig b/lib/std/zon/Serializer.zig index b65b13bf971f..5515cc2f0690 100644 --- a/lib/std/zon/Serializer.zig +++ b/lib/std/zon/Serializer.zig @@ -235,7 +235,7 @@ pub fn valueArbitraryDepth(self: *Serializer, val: anytype, options: ValueOption var container = try self.beginTuple( .{ .whitespace_style = .{ .fields = vector.len } }, ); - for (0..vector.len) |i| { + inline for (0..vector.len) |i| { try container.fieldArbitraryDepth(val[i], options); } try container.end(); diff --git a/lib/std/zon/parse.zig b/lib/std/zon/parse.zig index 6644f1114eaa..5dfb95b07221 100644 --- a/lib/std/zon/parse.zig +++ b/lib/std/zon/parse.zig @@ -446,7 +446,7 @@ pub fn free(gpa: Allocator, value: anytype) void { .optional => if (value) |some| { free(gpa, some); }, - .vector => |vector| for (0..vector.len) |i| free(gpa, value[i]), + .vector => |vector| inline for (0..vector.len) |i| free(gpa, value[i]), .void => {}, else => comptime unreachable, } @@ -998,11 +998,7 @@ const Parser = struct { } } - fn parseVector( - self: *@This(), - T: type, - node: Zoir.Node.Index, - ) !T { + fn parseVector(self: *@This(), T: type, node: Zoir.Node.Index) !T { const vector_info = @typeInfo(T).vector; const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) { @@ -1021,8 +1017,8 @@ const Parser = struct { ); } - for (0..vector_info.len) |i| { - errdefer for (0..i) |j| free(self.gpa, result[j]); + inline for (0..vector_info.len) |i| { + errdefer inline for (0..i) |j| free(self.gpa, result[j]); result[i] = try self.parseExpr(vector_info.child, nodes.at(@intCast(i))); } From 7b669dc297cd6de7b07e75c2a6455868da8ac52a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 3 Sep 2025 18:22:14 -0700 Subject: [PATCH 07/12] x86 codegen: handle spilled tuples --- src/arch/x86_64/CodeGen.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 1d3792d78575..75d52034744a 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -186936,7 +186936,7 @@ const Temp = struct { break :part_ty .usize; }, }, - .struct_type => { + .struct_type, .tuple_type => { assert(src_regs.len - part_index == std.math.divCeil(u32, src_abi_size, 8) catch unreachable); break :part_ty .u64; }, From 0746da41b35fd646ea86f48918e55f65ead9344f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 3 Sep 2025 18:30:40 -0700 Subject: [PATCH 08/12] std.zon.parse: fix not initializing array sentinel --- lib/std/zon/parse.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/std/zon/parse.zig b/lib/std/zon/parse.zig index 5dfb95b07221..89d3f9463796 100644 --- a/lib/std/zon/parse.zig +++ b/lib/std/zon/parse.zig @@ -786,6 +786,7 @@ const Parser = struct { elem.* = try self.parseExpr(array_info.child, nodes.at(@intCast(i))); } + if (array_info.sentinel()) |s| result[result.len] = s; return result; } From 6e3b498d5325457306173ba5abb19edcbf7330d2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 4 Sep 2025 14:48:23 -0700 Subject: [PATCH 09/12] x86 codegen fix --- src/arch/x86_64/CodeGen.zig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 75d52034744a..eac25ad9f809 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -186936,10 +186936,14 @@ const Temp = struct { break :part_ty .usize; }, }, - .struct_type, .tuple_type => { + .struct_type => { assert(src_regs.len - part_index == std.math.divCeil(u32, src_abi_size, 8) catch unreachable); break :part_ty .u64; }, + .tuple_type => |tuple_type| { + assert(tuple_type.types.len == src_regs.len); + break :part_ty .fromInterned(tuple_type.types.get(ip)[part_index]); + }, }; const part_size: u31 = @intCast(part_ty.abiSize(zcu)); const src_rc = src_reg.class(); From 6f42f2bfdba5722b3d8a0afe3b1cc593640a6822 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 4 Sep 2025 14:48:49 -0700 Subject: [PATCH 10/12] register manager: make copy of comptime var before runtime indexing register manager is a bad name --- src/register_manager.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/register_manager.zig b/src/register_manager.zig index bc6761ad3b9c..b9eeeb8d0391 100644 --- a/src/register_manager.zig +++ b/src/register_manager.zig @@ -92,7 +92,8 @@ pub fn RegisterManager( const id_index = reg.id() -% min_id; if (id_index >= map.len) return null; - const set_index = map[id_index]; + const map_copy = map; // This one can be accessed with runtime-known id_index. + const set_index = map_copy[id_index]; return if (set_index < set.len) @intCast(set_index) else null; } From f140c5484759dfdd4cd31215d31b86a44a14b975 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 4 Sep 2025 14:51:32 -0700 Subject: [PATCH 11/12] Sema: fix source location of "declared here" note point at the var not at the init expression --- src/Sema.zig | 26 +++++++++---------- .../comptime_var_referenced_at_runtime.zig | 20 +++++++------- .../comptime_var_referenced_by_decl.zig | 16 ++++++------ .../for_comptime_array_pointer.zig | 2 +- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 97b5e0552054..f4c056b98e26 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3753,9 +3753,9 @@ fn zirAllocExtended( const pt = sema.pt; const gpa = sema.gpa; const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand); + const var_src = block.nodeOffset(extra.data.src_node); const ty_src = block.src(.{ .node_offset_var_decl_ty = extra.data.src_node }); const align_src = block.src(.{ .node_offset_var_decl_align = extra.data.src_node }); - const init_src = block.src(.{ .node_offset_var_decl_init = extra.data.src_node }); const small: Zir.Inst.AllocExtended.Small = @bitCast(extended.small); var extra_index: usize = extra.end; @@ -3774,7 +3774,7 @@ fn zirAllocExtended( if (block.isComptime() or small.is_comptime) { if (small.has_type) { - return sema.analyzeComptimeAlloc(block, init_src, var_ty, alignment); + return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment); } else { try sema.air_instructions.append(gpa, .{ .tag = .inferred_alloc_comptime, @@ -3789,7 +3789,7 @@ fn zirAllocExtended( } if (small.has_type and try var_ty.comptimeOnlySema(pt)) { - return sema.analyzeComptimeAlloc(block, init_src, var_ty, alignment); + return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment); } if (small.has_type) { @@ -3799,8 +3799,8 @@ fn zirAllocExtended( const target = pt.zcu.getTarget(); try var_ty.resolveLayout(pt); if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) { - const var_src = block.src(.{ .node_offset_store_ptr = extra.data.src_node }); - return sema.fail(block, var_src, "local variable in naked function", .{}); + const store_src = block.src(.{ .node_offset_store_ptr = extra.data.src_node }); + return sema.fail(block, store_src, "local variable in naked function", .{}); } const ptr_type = try sema.pt.ptrTypeSema(.{ .child = var_ty.toIntern(), @@ -3839,9 +3839,9 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); - const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node }); + const var_src = block.nodeOffset(inst_data.src_node); const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); - return sema.analyzeComptimeAlloc(block, init_src, var_ty, .none); + return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none); } fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -4251,11 +4251,11 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); - const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node }); + const var_src = block.nodeOffset(inst_data.src_node); const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); if (block.isComptime() or try var_ty.comptimeOnlySema(pt)) { - return sema.analyzeComptimeAlloc(block, init_src, var_ty, .none); + return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none); } if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) { const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node }); @@ -4281,14 +4281,14 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); - const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node }); + const var_src = block.nodeOffset(inst_data.src_node); const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); if (block.isComptime()) { - return sema.analyzeComptimeAlloc(block, init_src, var_ty, .none); + return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none); } if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) { - const var_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node }); - return sema.fail(block, var_src, "local variable in naked function", .{}); + const store_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node }); + return sema.fail(block, store_src, "local variable in naked function", .{}); } try sema.validateVarType(block, ty_src, var_ty, false); const target = pt.zcu.getTarget(); diff --git a/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig b/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig index e060da33a8c1..603ce497326d 100644 --- a/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig +++ b/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig @@ -75,31 +75,31 @@ export fn bax() void { // // :5:19: error: runtime value contains reference to comptime var // :5:19: note: comptime var pointers are not available at runtime -// :4:27: note: 'runtime_value' points to comptime var declared here +// :4:14: note: 'runtime_value' points to comptime var declared here // :12:40: error: runtime value contains reference to comptime var // :12:40: note: comptime var pointers are not available at runtime -// :11:27: note: 'runtime_value' points to comptime var declared here +// :11:14: note: 'runtime_value' points to comptime var declared here // :19:50: error: runtime value contains reference to comptime var // :19:50: note: comptime var pointers are not available at runtime -// :18:27: note: 'runtime_value' points to comptime var declared here +// :18:14: note: 'runtime_value' points to comptime var declared here // :28:9: error: runtime value contains reference to comptime var // :28:9: note: comptime var pointers are not available at runtime -// :27:27: note: 'runtime_value' points to comptime var declared here +// :27:14: note: 'runtime_value' points to comptime var declared here // :36:9: error: runtime value contains reference to comptime var // :36:9: note: comptime var pointers are not available at runtime -// :35:27: note: 'runtime_value' points to comptime var declared here +// :35:14: note: 'runtime_value' points to comptime var declared here // :41:12: error: runtime value contains reference to comptime var // :41:12: note: comptime var pointers are not available at runtime -// :40:27: note: 'runtime_value' points to comptime var declared here +// :40:14: note: 'runtime_value' points to comptime var declared here // :46:39: error: runtime value contains reference to comptime var // :46:39: note: comptime var pointers are not available at runtime -// :45:27: note: 'runtime_value' points to comptime var declared here +// :45:14: note: 'runtime_value' points to comptime var declared here // :55:18: error: runtime value contains reference to comptime var // :55:18: note: comptime var pointers are not available at runtime -// :51:30: note: 'runtime_value' points to comptime var declared here +// :51:14: note: 'runtime_value' points to comptime var declared here // :63:18: error: runtime value contains reference to comptime var // :63:18: note: comptime var pointers are not available at runtime -// :59:27: note: 'runtime_value' points to comptime var declared here +// :59:14: note: 'runtime_value' points to comptime var declared here // :71:19: error: runtime value contains reference to comptime var // :71:19: note: comptime var pointers are not available at runtime -// :67:30: note: 'runtime_value' points to comptime var declared here +// :67:14: note: 'runtime_value' points to comptime var declared here diff --git a/test/cases/compile_errors/comptime_var_referenced_by_decl.zig b/test/cases/compile_errors/comptime_var_referenced_by_decl.zig index 8bd0186b125e..4f4b359311f7 100644 --- a/test/cases/compile_errors/comptime_var_referenced_by_decl.zig +++ b/test/cases/compile_errors/comptime_var_referenced_by_decl.zig @@ -47,19 +47,19 @@ export var h: *[1]u32 = h: { // error // // :1:27: error: global variable contains reference to comptime var -// :2:18: note: 'a' points to comptime var declared here +// :2:5: note: 'a' points to comptime var declared here // :6:30: error: global variable contains reference to comptime var -// :7:18: note: 'b[0]' points to comptime var declared here +// :7:5: note: 'b[0]' points to comptime var declared here // :11:30: error: global variable contains reference to comptime var -// :12:18: note: 'c' points to comptime var declared here +// :12:5: note: 'c' points to comptime var declared here // :16:33: error: global variable contains reference to comptime var -// :17:18: note: 'd' points to comptime var declared here +// :17:5: note: 'd' points to comptime var declared here // :22:24: error: global variable contains reference to comptime var -// :23:18: note: 'e.ptr' points to comptime var declared here +// :23:5: note: 'e.ptr' points to comptime var declared here // :28:33: error: global variable contains reference to comptime var -// :29:18: note: 'f' points to comptime var declared here +// :29:5: note: 'f' points to comptime var declared here // :34:40: error: global variable contains reference to comptime var // :34:40: note: 'g' points to 'v0[0]', where -// :36:24: note: 'v0[1]' points to comptime var declared here +// :36:5: note: 'v0[1]' points to comptime var declared here // :42:28: error: global variable contains reference to comptime var -// :43:22: note: 'h' points to comptime var declared here +// :43:5: note: 'h' points to comptime var declared here diff --git a/test/cases/compile_errors/for_comptime_array_pointer.zig b/test/cases/compile_errors/for_comptime_array_pointer.zig index 48f461cf4261..8925fed2f6e4 100644 --- a/test/cases/compile_errors/for_comptime_array_pointer.zig +++ b/test/cases/compile_errors/for_comptime_array_pointer.zig @@ -9,4 +9,4 @@ export fn foo() void { // // :3:10: error: runtime value contains reference to comptime var // :3:10: note: comptime var pointers are not available at runtime -// :2:34: note: 'runtime_value' points to comptime var declared here +// :2:14: note: 'runtime_value' points to comptime var declared here From adb492325607be7786295ed8c6b01143e4d09b9b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 4 Sep 2025 15:36:49 -0700 Subject: [PATCH 12/12] behavior: remove tests for vector runtime index access vector indexes must be comptime-known now --- test/behavior/x86_64/access.zig | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/test/behavior/x86_64/access.zig b/test/behavior/x86_64/access.zig index 5c6cbe030194..d5aaef35b16d 100644 --- a/test/behavior/x86_64/access.zig +++ b/test/behavior/x86_64/access.zig @@ -52,22 +52,12 @@ fn accessVector(comptime init: anytype) !void { var vector: Vector = undefined; vector = init; inline for (0..@typeInfo(Vector).vector.len) |ct_index| { - var rt_index: usize = undefined; - rt_index = ct_index; - if (&vector[rt_index] != &vector[ct_index]) return error.Unexpected; - if (vector[rt_index] != init[ct_index]) return error.Unexpected; if (vector[ct_index] != init[ct_index]) return error.Unexpected; - vector[rt_index] = rt_vals[0]; - if (vector[rt_index] != ct_vals[0]) return error.Unexpected; if (vector[ct_index] != ct_vals[0]) return error.Unexpected; - vector[rt_index] = ct_vals[1]; - if (vector[rt_index] != ct_vals[1]) return error.Unexpected; if (vector[ct_index] != ct_vals[1]) return error.Unexpected; vector[ct_index] = ct_vals[0]; - if (vector[rt_index] != ct_vals[0]) return error.Unexpected; if (vector[ct_index] != ct_vals[0]) return error.Unexpected; vector[ct_index] = rt_vals[1]; - if (vector[rt_index] != ct_vals[1]) return error.Unexpected; if (vector[ct_index] != ct_vals[1]) return error.Unexpected; } }